3. 外部中断触发
任务目标
本案例基于STM32F103系列MCU,通过外部中断实现按键控制LED翻转。核心目标是:配置GPIO外部中断线,使按键按下时触发中断服务函数(ISR),在ISR中翻转LED状态,并演示中断优先级与嵌套的基本配置方法。
硬件连接与前置条件
- MCU:STM32F103C8T6(Blue Pill板)
- 按键PA0接GND(按下为低电平),外部中断线EXTI0
- LED接PC13(板上LED,低电平点亮)
- 开发环境:STM32CubeIDE 或 Keil MDK + HAL库
完整代码实现
/* main.c - 外部中断触发LED翻转 */
#include "main.h"
/* 中断优先级分组:抢占优先级2位,子优先级2位 */
void HAL_MspInit(void)
{
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
}
/* PA0外部中断初始化 */
static void EXTI_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 使能GPIOA时钟 */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/* PA0配置为外部中断输入,上拉(按键接GND) */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; /* 下降沿触发 */
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* PC13配置为推挽输出 */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* 设置EXTI0中断优先级:抢占优先级1,子优先级0 */
HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
/* 外部中断0服务函数(在stm32f1xx_it.c中调用) */
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
/* 中断回调:按键按下时翻转LED */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_0)
{
/* 简单消抖:延时20ms后再次检测电平 */
HAL_Delay(20);
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
}
}
}
int main(void)
{
HAL_Init();
EXTI_Init();
/* 初始状态:LED灭(PC13高电平) */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
while (1)
{
/* 主循环空闲,等待中断触发 */
}
}
中断优先级与嵌套说明
本案例使用NVIC_PRIORITYGROUP_2分组,即4位优先级中高2位为抢占优先级、低2位为子优先级。EXTI0配置为抢占优先级1、子优先级0。若需演示嵌套中断,可再配置一个更高抢占优先级的中断源(如定时器中断,抢占优先级0),当EXTI0中断服务执行期间该中断到来时,会暂停当前ISR优先处理高优先级中断。本例仅配置单个外部中断,但优先级分组和数值设置已为嵌套扩展预留接口。
编译与烧录
- 在STM32CubeIDE中新建STM32F103C8T6工程,将上述代码替换main.c内容。
- 确认系统时钟已通过HAL_RCC_ClockConfig()配置(默认使用HSI 8MHz或外部晶振)。
- 编译生成HEX文件,通过ST-Link烧录至开发板。
验证方法与判定标准
- 功能验证:上电后LED处于熄灭状态。每次按下PA0按键并释放,LED状态翻转一次(亮→灭或灭→亮)。
- 消抖验证:快速连续按动按键,LED状态应稳定翻转,不会出现一次按键多次翻转的现象。
- 优先级验证(可选):若额外配置一个定时器中断(抢占优先级0),在定时器ISR中翻转另一个LED,可观察到定时器中断能打断EXTI0的ISR执行,证明抢占优先级生效。
常见问题
- 按键无响应:检查PA0是否正确上拉,按键另一端是否接GND;确认EXTI0_IRQHandler已在启动文件中声明。
- LED状态乱跳:消抖延时不足或按键接触不良,可增大延时至30~50ms。
- 编译报错:确认HAL库版本与芯片型号匹配,main.h中已包含必要头文件。