如何在STM32 BluePill上实现固定周期从待机模式自动唤醒
STM32 BluePill(STM32F103)定时唤醒待机模式实现方案
实现原理
STM32待机模式下仅RTC、备份寄存器、待机电路保持供电,是功耗最低的休眠模式,和你之前ATmega328P的掉电休眠逻辑匹配。采用RTC闹钟作为唤醒源,即可实现固定间隔自动唤醒,无需操作系统支持。
STM32CubeMX 基础配置(图形化配置避免宏定义编译错误)
- 时钟配置:开启LSE外部低速晶振(32.768kHz,RTC专用精度更高,没有硬件的话也可以选LSI内部低速时钟,精度稍差),RTC时钟源选择对应配置的LSE/LSI
- RTC配置:开启「Alarm A」闹钟功能
- PWR配置:开启RTC闹钟作为待机模式唤醒源
- 其他外设配置:按需开启你用到的传感器接口、警报输出IO即可
可直接复用的代码实现
#include "stm32f1xx_hal.h" // 直接引用CubeMX自动生成的RTC句柄即可 extern RTC_HandleTypeDef hrtc; // 配置RTC闹钟,设定interval_s秒后触发唤醒 void set_rtc_wakeup(uint32_t interval_s) { RTC_AlarmTypeDef sAlarm = {0}; HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_A); // 获取当前RTC时间 RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef sDate = {0}; HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN); // 计算闹钟触发时间:当前时间 + 间隔秒数 uint32_t total_sec = sTime.Hours * 3600 + sTime.Minutes * 60 + sTime.Seconds + interval_s; sAlarm.AlarmTime.Hours = (total_sec / 3600) % 24; sAlarm.AlarmTime.Minutes = (total_sec % 3600) / 60; sAlarm.AlarmTime.Seconds = total_sec % 60; sAlarm.Alarm = RTC_ALARM_A; sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY; // 仅匹配时间即可,忽略日期 sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL; // 启动闹钟中断 HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN); __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); __HAL_RTC_ALARM_ENABLE_IT(&hrtc, RTC_IT_ALRA); } // 进入待机模式函数,和你之前Arduino的休眠函数功能完全对应 void enter_standby(uint32_t wakeup_interval_s) { // 先配置唤醒闹钟 set_rtc_wakeup(wakeup_interval_s); // 关闭不必要外设降低功耗,对应你之前关闭ADC的操作 // 用到ADC可以加:HAL_ADC_DeInit(&hadc); // 用到串口可以加:HAL_UART_DeInit(&huart1); // 进入待机模式 HAL_PWR_EnterSTANDBYMode(); } int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_RTC_Init(); // 其他外设初始化:比如ADC、传感器相关初始化 // 待机唤醒后芯片相当于重启,会从main重新执行,和你之前Arduino的setup逻辑完全对齐 uint16_t sensor_value = read_sensor(); // 替换为你自己的传感器读取函数 if(sensor_value == 0) { turnOnAlarm(); // 替换为你自己的警报触发逻辑 while(1); // 触发警报后停止休眠循环 } // 否则设置4秒后唤醒继续循环,要改2秒直接传参数2即可 enter_standby(4); // 代码不会执行到此处 while(1); } // 示例:替换为你自己的传感器读取逻辑 uint16_t read_sensor(void) { return HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0); } // 示例:替换为你自己的警报触发逻辑 void turnOnAlarm(void) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); }
注意事项
- 待机模式唤醒后所有通用寄存器都会重置,不需要额外写loop函数,逻辑完全和你之前Arduino的实现对齐
- 如果需要保留少量数据跨休眠周期,可以存储在RTC备份寄存器中,STM32F103最多支持20字节的备份存储
- 没有外部32.768k晶振的场景,直接把RTC时钟源换成LSI内部时钟即可,不用修改业务代码,仅定时精度稍低
内容的提问来源于stack exchange,提问作者Tono Nam
相关产品推荐
相关产品推荐

