根本原因是RTC预分频器未正确写入、ALRAE位未置1、EXTI_Line17未使能;且唤醒后未清除ALRF和PR17标志,导致刚唤醒即再次触发中断。

Stop模式下RTC闹钟唤醒为什么经常失败
根本原因是STM32等主流MCU在Stop模式下,APB1总线(RTC寄存器所在总线)时钟被关闭,但RTC本身由LSE或LSI驱动,仍运行;而很多开发者误以为只要配置了RTC_Alarm就自动生效——实际必须确保:① RTC预分频器已正确写入(哪怕只写一次),② RTC_CR.ALRAE位在进入Stop前已置1,③ 未遗漏EXTI_Line17中断使能和NVIC配置。常见现象是系统进Stop后永不唤醒,用逻辑分析仪测到LSE仍在振,但RTC_ISR.ALRAWF始终为1(写告警寄存器不生效),本质是RTC未初始化完成。
进入Stop前必须手动触发RTC初始化流程
即使RTC已初始化过,Stop模式退出后RTC仍保持运行,但再次进入Stop前若修改过闹钟时间,必须重新同步写入——因为RTC_ALRMAR是影子寄存器,需通过RTC_WUTR或RTC_ISR.RSF标志确认日历同步完成。实操建议:
- 调用
HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BIN)后,立刻检查HAL_RTC_GetState(&hrtc) == HAL_RTC_STATE_READY - 不要依赖
HAL_Delay()等待,改用轮询__HAL_RTC_ALARM_GET_FLAG(&hrtc, RTC_FLAG_ALRAWF)直到返回0 - 确保
RCC_PeriphCLKInitTypeDef中PeriphClockSelection包含RCC_PERIPHCLK_RTC,且RtcClockSelection设为RCC_RTCCLKSOURCE_LSE(LSE比LSI更稳,尤其低温下)
唤醒后必须手动清除EXTI挂起位和RTC标志
Stop唤醒本质是EXTI Line17(对应RTC Alarm事件)触发的NMI或IRQ,但HAL库默认不会自动清EXTI_PR.PR17和RTC_ISR.ALRF,导致下次进Stop前若未清除,会立即再次触发中断——表现为刚唤醒就又进中断,死循环。关键动作:
- 在
HAL_RTC_AlarmAEventCallback()里第一行加__HAL_RTC_ALARM_CLEAR_FLAG(&hrtc, RTC_FLAG_ALRA) - 紧接着调用
__HAL_EXTI_CLEAR_FLAG(EXTI_LINE_17)(注意不是EXTI_ClearITPendingBit(),后者已废弃) - 如果使用FreeRTOS,在回调里别直接调用
vTaskResume(),先关BASEPRI再操作寄存器,否则可能因中断嵌套丢失标志
Stop模式选型:STOP2比STOP0更省电但限制更多
以STM32L4为例,PWR_MAINREGULATOR_ON + PWR_STOPENTRY_WFI是STOP0,SRAM2保持供电;而PWR_LOWPOWERREGULATOR_ON + WFI是STOP2,功耗低30%,但此时VREFINT关闭,ADC不可用,且部分GPIO状态可能丢失。实操要点:
立即学习“C++免费学习笔记(深入)”;
- 进STOP2前必须调用
HAL_PWREx_EnableLowPowerRunMode(),否则强制降为STOP0 - 所有唤醒源引脚(包括RTC)的
GPIO_MODE_ANALOG配置要保留,避免漏电——曾有案例因PA0(RTC_Alarm)设成GPIO_MODE_INPUT导致待机电流从1.2μA升至8μA - RTC闹钟时间单位用
RTC_FORMAT_BIN而非RTC_FORMAT_BCD,BCD在跨小时/日期时易出错(如0x29秒被解析成41秒而非29秒)
PA0(若复用为WakeUp引脚)或逻辑分析仪看EXTI_Line17电平跳变。很多“唤醒失败”其实是程序在唤醒中断里又主动调用了HAL_PWR_EnterSTOPMode(),却忘了重装闹钟。


















