STM32 外部中断 EXTI 与睡眠唤醒综合实战:从按键到低功耗的完整链路
👁 2 阅读 · 2026-08-19 · STM32 中断
本文深入剖析 STM32 外部中断(EXTI)的硬件机制与配置要点,并结合低功耗模式(睡眠/停止)实现按键唤醒的综合实战。通过原理讲解、寄存器级配置、HAL 库代码示例,帮助开发者掌握中断触发条件、中断服务函数编写、以及如何在睡眠模式下利用 EXTI 唤醒 MCU,从而构建高效、低功耗的嵌入式系统。
## 一、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
```c
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`:用户回调函数,需在外部重写。
```c
// 中断入口函数
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 被唤醒并执行中断服务,然后返回主循环。
```c
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)。
```c
// 进入停止模式
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 唤醒后重新初始化时钟
SystemClock_Config();
```
注意:停止模式下,EXTI 事件可唤醒,但中断需在唤醒后重新使能 NVIC。
## 六、注意事项与调试技巧
- **中断优先级**:若系统有其他中断,需合理设置抢占优先级,避免死锁。
- **引脚冲突**:同一 EXTI 线只能映射一个引脚,若多个引脚共用,需在回调中判断 `GPIO_Pin`。
- **调试建议**:在 ISR 中设置断点可能影响时序,建议使用串口打印或 LED 指示。
- **功耗测量**:使用万用表或功耗分析仪,确保睡眠模式电流符合预期(通常 µA 级)。
## 七、总结
本文通过一个按键唤醒 LED 的实例,完整展示了 STM32 EXTI 的配置、中断处理及低功耗唤醒流程。掌握 EXTI 不仅有助于实现快速响应,更是低功耗设计的关键。建议读者进一步尝试停止模式、事件模式,并结合 RTC 定时唤醒,构建更复杂的低功耗系统。