使用 STM32L476 的 STOP2 模式降低功耗,但发现 RTC 闹钟唤醒不稳定,有时需要多次尝试才能唤醒。
使用逻辑分析仪监测 WKUP 引脚,发现唤醒信号正常
检查 RTC 配置,发现 RTC 时钟源选择为 LSE (低速外部晶振),但没有正确启动
查看电源管理,发现进入 STOP2 模式前没有正确配置唤醒引脚
后续处理:
确保 LSE 晶振正确启动并稳定运行
增加 LSE 启动超时检测
优化低功耗模式配置和唤醒引脚设置
[color=rgba(0, 0, 0, 0.45)]// RTC初始化函数,增加LSE启动检测RTC_HandleTypeDef hrtc;void MX_RTC_Init(void){ RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef sDate = {0}; RTC_AlarmTypeDef sAlarm = {0}; [color=rgba(0, 0, 0, 0.45)]// 使能电源时钟 __HAL_RCC_PWR_CLK_ENABLE(); [color=rgba(0, 0, 0, 0.45)]// 使能备份域访问 HAL_PWR_EnableBkUpAccess(); [color=rgba(0, 0, 0, 0.45)]// 配置LSE作为RTC时钟源 __HAL_RCC_LSE_CONFIG(RCC_LSE_ON); [color=rgba(0, 0, 0, 0.45)]// 等待LSE稳定,增加超时检测 uint32_t timeout = 10000; while(!(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY)) && (timeout-- > 0)) { [color=rgba(0, 0, 0, 0.45)]// 超时处理 if(timeout == 0) { printf("LSE start timeout!\r\n"); [color=rgba(0, 0, 0, 0.45)]// 可以选择切换到LSI或其他时钟源 __HAL_RCC_LSE_CONFIG(RCC_LSE_OFF); __HAL_RCC_LSI_ENABLE(); while(!(__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY))); __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSI); break; } } [color=rgba(0, 0, 0, 0.45)]// 配置RTC时钟源 __HAL_RCC_RTC_ENABLE(); [color=rgba(0, 0, 0, 0.45)]// 配置RTC hrtc.Instance = RTC; hrtc.Init.HourFormat = RTC_HOURFORMAT_24; hrtc.Init.AsynchPrediv = 127; hrtc.Init.SynchPrediv = 255; hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE; hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; if (HAL_RTC_Init(&hrtc) != HAL_OK) { Error_Handler(); } [color=rgba(0, 0, 0, 0.45)]// 配置时间和日期 [color=rgba(0, 0, 0, 0.45)]// ...省略部分代码... [color=rgba(0, 0, 0, 0.45)]// 配置RTC闹钟,每30秒唤醒一次 sAlarm.AlarmTime.Hours = 0; sAlarm.AlarmTime.Minutes = 0; sAlarm.AlarmTime.Seconds = 30; sAlarm.AlarmTime.SubSeconds = 0; sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET; sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY | RTC_ALARMMASK_HOURS | RTC_ALARMMASK_MINUTES; sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL; sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE; sAlarm.AlarmDateWeekDay = 1; sAlarm.Alarm = RTC_ALARM_A; if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); }}[color=rgba(0, 0, 0, 0.45)]// 进入STOP2模式函数void Enter_STOP2_Mode(void){ [color=rgba(0, 0, 0, 0.45)]// 保存当前RTC闹钟设置 RTC_AlarmTypeDef sAlarm; HAL_RTC_GetAlarm(&hrtc, &sAlarm, RTC_ALARM_A, RTC_FORMAT_BIN); [color=rgba(0, 0, 0, 0.45)]// 关闭不需要的外设时钟 __HAL_RCC_GPIOA_CLK_DISABLE(); __HAL_RCC_GPIOB_CLK_DISABLE(); __HAL_RCC_GPIOC_CLK_DISABLE(); __HAL_RCC_GPIOD_CLK_DISABLE(); __HAL_RCC_GPIOE_CLK_DISABLE(); [color=rgba(0, 0, 0, 0.45)]// 配置唤醒引脚 HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); [color=rgba(0, 0, 0, 0.45)]// 进入STOP2模式 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); [color=rgba(0, 0, 0, 0.45)]// 系统从STOP2模式唤醒后会重新配置时钟 [color=rgba(0, 0, 0, 0.45)]// 重新初始化外设和GPIO [color=rgba(0, 0, 0, 0.45)]// ...省略部分代码...}
|