3. 外部中断控制LED
任务目标
使用STM32微控制器的外部中断(EXTI)功能,将按键连接到GPIO引脚,当按键按下时触发外部中断服务函数,在中断中翻转LED的亮灭状态。本案例以STM32F103系列为例,通过标准外设库实现完整功能。
硬件连接
- LED正极通过限流电阻(约220Ω)连接到
PB0,负极接地 - 按键一端连接
PA0,另一端接地(按下为低电平) - PA0需配置为上拉输入,确保未按下时引脚为高电平
完整代码实现
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
// 按键按下标志(在中断中置1,主循环中清零)
volatile uint8_t key_pressed = 0;
// LED GPIO初始化
void LED_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_ResetBits(GPIOB, GPIO_Pin_0); // 初始LED熄灭
}
// 按键GPIO和EXTI初始化
void KEY_EXTI_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 使能GPIOA和AFIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
// PA0配置为上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 将PA0连接到EXTI0线
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
// 配置EXTI0:下降沿触发(按键按下时电平从高到低)
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
// 配置NVIC中断优先级
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
// EXTI0中断服务函数
void EXTI0_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
// 消抖延时(简单延时约20ms)
for (volatile uint32_t i = 0; i < 200000; i++);
// 再次确认按键确实按下(低电平有效)
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_RESET) {
key_pressed = 1;
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
int main(void) {
LED_Init();
KEY_EXTI_Init();
while (1) {
if (key_pressed) {
key_pressed = 0;
// 翻转LED状态
if (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0) == Bit_SET) {
GPIO_ResetBits(GPIOB, GPIO_Pin_0);
} else {
GPIO_SetBits(GPIOB, GPIO_Pin_0);
}
}
}
}
编译与烧录
- 创建STM32标准外设库工程,添加上述代码到
main.c文件 - 在工程配置中定义
STM32F10X_MD(针对STM32F103中容量型号) - 编译生成HEX文件,通过ST-Link或J-Link烧录到开发板
验证方法
烧录成功后,观察以下现象:
- 初始状态:LED处于熄灭状态
- 每次按下按键并释放,LED状态翻转一次(亮→灭或灭→亮)
- 连续快速按键时,每次按键都能正确翻转LED状态,不会出现漏触发或误触发
若LED状态与按键动作不一致,检查PA0上拉配置是否正确、EXTI触发边沿是否设置为下降沿,以及中断服务函数中消抖延时是否合适。