4. 使用外部中断唤醒
任务定义
本案例目标:在MCU进入低功耗停机模式(STOP)后,通过外部GPIO中断将其唤醒,并验证唤醒后程序能正确恢复执行。以STM32L0系列为例,实现按键触发的外部中断唤醒,同时展示唤醒源判断与低功耗模式进入/退出的完整流程。
硬件连接
按键连接到PA0(EXTI0),内部上拉,按下时产生下降沿触发中断。PA5驱动LED作为唤醒指示。MCU进入STOP模式前点亮LED,唤醒后翻转LED状态。
代码实现
#include "stm32l0xx_hal.h"
/* 简单延时(非精确,仅用于视觉观察) */
static void delay_volatile(uint32_t count) {
while (count--) {
__NOP();
}
}
/* LED初始化:PA5 */
static void LED_Init(void) {
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef gpio = {0};
gpio.Pin = GPIO_PIN_5;
gpio.Mode = GPIO_MODE_OUTPUT_PP;
gpio.Pull = GPIO_NOPULL;
gpio.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &gpio);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); /* 初始点亮 */
}
/* 外部中断初始化:PA0下降沿触发 */
static void EXTI_Init(void) {
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef gpio = {0};
gpio.Pin = GPIO_PIN_0;
gpio.Mode = GPIO_MODE_IT_FALLING;
gpio.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &gpio);
HAL_NVIC_SetPriority(EXTI0_1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
}
/* EXTI0中断服务函数 */
void EXTI0_1_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) {
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
}
}
int main(void) {
HAL_Init();
LED_Init();
EXTI_Init();
while (1) {
/* 进入STOP模式前关闭LED */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
delay_volatile(200000); /* 短暂保持熄灭,便于观察 */
/* 进入STOP模式,等待外部中断唤醒 */
HAL_SuspendTick(); /* 暂停SysTick,避免唤醒干扰 */
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
/* 唤醒后恢复 */
HAL_ResumeTick();
HAL_Delay(2); /* 等待时钟稳定 */
/* 点亮LED,表示已唤醒 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
delay_volatile(500000); /* 保持点亮,便于观察 */
}
}
关键实现说明
- 唤醒源配置:PA0配置为下降沿中断(
GPIO_MODE_IT_FALLING),内部上拉保证按键未按下时为高电平,按下时产生下降沿。 - STOP模式进入:调用
HAL_PWR_EnterSTOPMode()前先暂停SysTick(HAL_SuspendTick()),防止唤醒后时钟未稳定时SysTick产生干扰。 - 唤醒后处理:从STOP模式唤醒后,系统时钟自动恢复为MSI(默认),需调用
HAL_ResumeTick()恢复SysTick,并短暂延时等待时钟稳定。 - 中断回调:在
HAL_GPIO_EXTI_Callback()中翻转LED,该回调在中断上下文中执行,操作应保持简短。
工程配置与编译
/* 使用STM32CubeMX生成基础工程,需包含以下配置:
* - 时钟:MSI 2.097MHz(默认),无需PLL
* - PA0: GPIO_EXTI0,下降沿触发,内部上拉
* - PA5: GPIO_Output
* - NVIC: 使能EXTI0_1中断
* - 功耗:选择STOP模式(PWR_LOWPOWERREGULATOR_ON)
*/
编译命令(以GCC工具链为例):
arm-none-eabi-gcc -c main.c -mcpu=cortex-m0plus -mthumb -I./Inc \
-DSTM32L0xx -DUSE_HAL_DRIVER
arm-none-eabi-gcc -o firmware.elf main.o \
startup_stm32l0xx.s system_stm32l0xx.c \
-T stm32l0xx_flash.ld -lc -lm
验证方法与判定标准
- 烧录与运行:将编译生成的固件烧录至STM32L0开发板,连接调试器(ST-Link)与串口(可选,用于观察)。
- 观察流程:
- 上电后LED点亮约0.5秒(初始状态),随后熄灭并进入STOP模式(此时整板电流应显著下降,可用万用表测量VDD电流,预期从mA级降至µA级)。
- 按下按键(PA0接地),LED应立即点亮约1秒,然后再次熄灭进入STOP模式。
- 判定通过:
- 每次按键按下,LED均能可靠点亮,说明外部中断成功唤醒MCU。
- LED熄灭期间(STOP模式)电流明显低于运行模式,证明低功耗状态生效。
- 连续多次按键(≥10次)无失效,说明唤醒路径稳定。
- 调试器验证(可选):在
HAL_GPIO_EXTI_Callback()入口设断点,按键后能停住,证明中断确实触发;单步执行可观察PC从STOP唤醒后正确恢复。
注意事项
- 若使用其他STM32系列,需调整中断向量名称(如EXTI0_IRQn)与时钟配置,但原理相同。
- STOP模式下调试器连接可能断开,建议先通过LED现象验证,再连接调试器观察。
- 按键需做硬件消抖(RC滤波或软件延时),本案例为演示中断唤醒,未包含消抖逻辑,实际产品需补充。