一、EXTI 原理与中断路径
STM32 的 EXTI(External Interrupt/Event Controller)负责管理外部引脚的中断/事件触发。每个 GPIO 引脚均可配置为 EXTI 输入,但同一时刻只能有一个引脚映射到同一中断线(例如 PA0 和 PB0 共享 EXTI0)。
- 触发方式:上升沿、下降沿、双边沿,或软件触发(用于测试)。
- 中断路径:引脚电平变化 → EXTI 边沿检测 → 挂起寄存器置位 → NVIC 响应 → 执行中断服务函数(ISR)。
- 事件路径:不产生中断,仅触发其他外设(如 ADC 转换),适合低功耗场景。
关键寄存器:
-
EXTI_IMR:中断屏蔽寄存器(使能中断线) -
EXTI_RTSR/EXTI_FTSR:上升/下降沿触发选择 -
EXTI_PR:挂起寄存器,写 1 清除中断标志
二、硬件连接与低功耗模式选择
实战场景:使用按键(连接到 PA0)作为外部中断源,在睡眠模式下按下按键唤醒 MCU,并翻转 LED(PB5)。
- 按键电路:PA0 接按键到 GND,内部上拉,按下时产生下降沿。
- LED 电路:PB5 接 LED 串联电阻到 VCC,低电平点亮。
STM32 低功耗模式对比:
- 睡眠模式:仅关闭 CPU 时钟,外设仍运行,唤醒延迟最短(微秒级)。
- 停止模式:关闭所有时钟,仅保留 SRAM 和寄存器内容,唤醒延迟较长(毫秒级),但功耗更低。
本例采用睡眠模式,兼顾快速响应与功耗优化。
三、HAL 库配置步骤(以 STM32F4 为例)
1. 初始化 GPIO 和 EXTI
void EXTI_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 使能 GPIOA 和 GPIOB 时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
// 配置 PA0 为外部中断输入,上拉,下降沿触发
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置 PB5 为推挽输出
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// 使能 EXTI0 中断并设置优先级
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
2. 中断服务函数编写
HAL 库将中断处理分为两个阶段:
-
EXTI0_IRQHandler:硬件中断入口,调用 HAL 库通用处理函数。 -
HAL_GPIO_EXTI_Callback:用户回调函数,需在外部重写。
// 中断入口函数
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
// 用户回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_0)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5); // 翻转 LED
}
}
3. 进入睡眠模式并唤醒
在 main 函数中,初始化后进入睡眠模式。使用 __WFI()(Wait For Interrupt)指令,当 EXTI 中断发生时,CPU 被唤醒并执行中断服务,然后返回主循环。
int main(void)
{
HAL_Init();
EXTI_Init();
while (1)
{
// 进入睡眠模式,等待外部中断唤醒
__WFI();
// 唤醒后执行其他任务(例如延时消抖)
HAL_Delay(50); // 简单消抖
}
}
四、深入理解:中断标志清除与消抖
-
标志清除:HAL 库在
HAL_GPIO_EXTI_IRQHandler中自动清除挂起位,无需手动操作。但若使用寄存器编程,必须在 ISR 中写 1 到EXTI_PR对应位。 - 按键消抖:机械按键存在抖动,通常产生多次边沿。简单方法是在回调中延时 10-20ms 后再次检测电平;更优方案是使用定时器或状态机。
五、进阶:停止模式唤醒与 RTC 结合
若需更低功耗,可进入停止模式(HAL_PWR_EnterSTOPMode)。此时需配置 EXTI 为事件模式(GPIO_MODE_EVT_FALLING),并确保唤醒后重新配置系统时钟(因为停止模式会关闭 HSI/HSE)。
// 进入停止模式
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 唤醒后重新初始化时钟
SystemClock_Config();
注意:停止模式下,EXTI 事件可唤醒,但中断需在唤醒后重新使能 NVIC。
六、注意事项与调试技巧
- 中断优先级:若系统有其他中断,需合理设置抢占优先级,避免死锁。
-
引脚冲突:同一 EXTI 线只能映射一个引脚,若多个引脚共用,需在回调中判断
GPIO_Pin。 - 调试建议:在 ISR 中设置断点可能影响时序,建议使用串口打印或 LED 指示。
- 功耗测量:使用万用表或功耗分析仪,确保睡眠模式电流符合预期(通常 µA 级)。
七、总结
本文通过一个按键唤醒 LED 的实例,完整展示了 STM32 EXTI 的配置、中断处理及低功耗唤醒流程。掌握 EXTI 不仅有助于实现快速响应,更是低功耗设计的关键。建议读者进一步尝试停止模式、事件模式,并结合 RTC 定时唤醒,构建更复杂的低功耗系统。