目录
[1 工程配置](#1 工程配置)
[1.1 参数配置和说明](#1.1 参数配置和说明)
[1.2 代码架构](#1.2 代码架构)
[2 代码实现](#2 代码实现)
[2.1 初始化PWR中断唤醒](#2.1 初始化PWR中断唤醒)
[2.2 配置唤醒中断函数](#2.2 配置唤醒中断函数)
[2.3 进入stop模式函数](#2.3 进入stop模式函数)
[2.4 进入待机模式函数](#2.4 进入待机模式函数)
[2.5 WakeUp回调函数](#2.5 WakeUp回调函数)
[3 功能测试](#3 功能测试)
[4 不同场景的配置示例](#4 不同场景的配置示例)
概述
STM32的RTC唤醒中断是实现超低功耗、电池长期续航应用 的基石。它的核心是一个与低功耗模式深度绑定的、独立的硬件定时器。配置时,请务必:根据需求(精度、周期)选择合适的唤醒时钟源; 正确计算并设置唤醒计数值 。在中断服务程序中务必清除标志 。深刻理解在不同低功耗模式下被唤醒后的系统行为差异(尤其是待机模式下的复位)。
1 工程配置
1.1 参数配置和说明
1) RCC配置:
启用
LSE(低速外部时钟)在
RTC选项卡中,使能Activate Clock Source和Activate Calendar时钟源选择:
LSE

使能时钟源/日历,和Alarm类型

2) RTC参数配置 :通过预分频计算最终得到1Hz时钟用于日历

Hour Format: 24小时制 Asynchronous Predivider: 127 (32768/(127+1)=256Hz) Synchronous Predivider: 255 (256/(255+1)=1Hz)
3) NVIC配置:

1.2 代码架构
使用STM32 Cube 生成代码架构

屏蔽如下代码,这些代码在用户程序中重新实现

2 代码实现
2.1 初始化PWR中断唤醒

源代码如下:
cpp
void lowpwr_init( void )
{
/* 检查是否为从待机模式唤醒 */
if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET)
{
log_a("从待机模式唤醒!\r\n");
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
/* 检查唤醒源是否为RTC */
if (__HAL_PWR_GET_FLAG(PWR_FLAG_WU) != RESET)
{
log_a("唤醒源:RTC唤醒定时器\r\n");
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
}
}
}
2.2 配置唤醒中断函数

源代码如下:
cpp
/* 配置唤醒中断函数 */
void RTC_Wakeup_Config(uint32_t interval_ms)
{
uint32_t wakeup_counter = 0;
uint32_t clock_freq = 0;
/* 1. 停止唤醒定时器(配置前必须先停止) */
HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
/* 2. 计算唤醒计数值(以RTCCLK/16=2048Hz为例) */
// 公式:WakeupCounter = (interval_ms * clock_freq) / 1000 - 1
// 选择RTC_WAKEUPCLOCK_RTCCLK_DIV16 (32768/16 = 2048Hz)
// 每个计数周期 = 1/2048 ≈ 0.488ms
clock_freq = 2048; // Hz
wakeup_counter = (interval_ms * clock_freq) / 1000 - 1;
/* 3. 限制计数值范围(WUT是16位寄存器) */
if (wakeup_counter > 0xFFFF)
wakeup_counter = 0xFFFF;
if (wakeup_counter < 1)
wakeup_counter = 1;
/* 4. 初始化并启动唤醒中断 */
// 参数:RTC句柄,唤醒计数值,时钟源
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, wakeup_counter,
RTC_WAKEUPCLOCK_RTCCLK_DIV16);
/* 5. 清除可能存在的旧标志 */
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG();
log_a("唤醒中断配置完成!\r\n");
log_a("唤醒间隔: %lu ms\r\n", interval_ms);
log_a("唤醒计数值: %lu\r\n", wakeup_counter);
}
2.3 进入stop模式函数

源代码:
cpp
/* 进入停止模式函数 */
void Enter_Stop_Mode(void)
{
log_a("\r\n....准备进入停止模式...\r\n");
/* 1. 确保唤醒中断已正确配置 */
if (__HAL_RTC_WAKEUPTIMER_GET_IT_SOURCE(&hrtc, RTC_IT_WUT) == RESET)
{
log_a("错误:唤醒中断未使能!\r\n");
return;
}
/* 2. 清除所有唤醒标志 */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
/* 3. 配置唤醒引脚(如果需要外部唤醒) */
// HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
/* 4. 进入停止模式(根据需求选择调节器模式) */
// 参数1:调节器模式(PWR_MAINREGULATOR_ON 或 PWR_LOWPOWERREGULATOR_ON)
// 参数2:进入模式方式(PWR_STOPENTRY_WFI 或 PWR_STOPENTRY_WFE)
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
/* 5. 唤醒后执行的代码(系统会从这里继续运行) */
SystemClock_Config(); // 重新配置系统时钟(重要!)
log_a("\r\n.....从停止模式唤醒!\r\n");
}
2.4 进入待机模式函数

cpp
/* 进入待机模式函数(更低的功耗,唤醒后会复位) */
void Enter_Standby_Mode(void)
{
log_a("准备进入待机模式...\r\n");
/* 1. 清除所有唤醒标志 */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
/* 2. 使能唤醒引脚(可选) */
// HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
/* 3. 确保RTC唤醒中断已使能 */
__HAL_RTC_WAKEUPTIMER_ENABLE_IT(&hrtc, RTC_IT_WUT);
/* 4. 进入待机模式 */
HAL_PWR_EnterSTANDBYMode();
/* 注意:从待机模式唤醒后,MCU会完全复位,程序从main()重新开始执行 */
}
2.5 WakeUp回调函数

cpp
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
/* 1. 检查是否是唤醒中断触发 */
{
/* 2. 清除RTC唤醒中断标志(必须的步骤!) */
/* 3. 清除EXTI线路22的中断标志 */
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG();
/* 4. 执行用户代码(尽量简短) */
wakeup_flag = 1; // 设置软件标志
/* 5. 可选的LED指示(如果有LED连接) */
// HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
TRIGGLE_LED;
/* 6. 重新使能唤醒中断(某些情况下需要) */
// HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, wakeup_counter, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
}
}
3 功能测试

1) 初始化LR POWER 功能

2) 运行函数:

3) 性能优化建议
最小化中断服务时间:ISR中只设置标志,复杂操作放在主循环
合理选择低功耗模式:
短期空闲 → 睡眠模式
长时间等待 → 停止模式
超低功耗需求 → 待机模式
关闭未用外设时钟:进入低功耗前关闭所有不必要的外设时钟
使用RTC备份寄存器:保存关键数据,防止待机模式唤醒后丢失
4) 核心源代码如下:
cpp
#define WAKE_UP_TIME 4000 // 400000 ms = 400 seconds
extern RTC_HandleTypeDef hrtc;
extern void SystemClock_Config(void);
static uint8_t wakeup_flag = 0;
void lowpwr_init( void )
{
/* 检查是否为从待机模式唤醒 */
if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET)
{
log_a("从待机模式唤醒!\r\n");
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
/* 检查唤醒源是否为RTC */
if (__HAL_PWR_GET_FLAG(PWR_FLAG_WU) != RESET)
{
log_a("唤醒源:RTC唤醒定时器\r\n");
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
}
}
}
/*******************************************************************************
* WAKE UP FUNCTION
*******************************************************************************
*/
static int lwr_cnt = 0,wk_cnt = 0;
bool lwr_sate = 0;
/* 配置唤醒中断函数 */
void RTC_Wakeup_Config(uint32_t interval_ms)
{
uint32_t wakeup_counter = 0;
uint32_t clock_freq = 0;
/* 1. 停止唤醒定时器(配置前必须先停止) */
HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
/* 2. 计算唤醒计数值(以RTCCLK/16=2048Hz为例) */
// 公式:WakeupCounter = (interval_ms * clock_freq) / 1000 - 1
// 选择RTC_WAKEUPCLOCK_RTCCLK_DIV16 (32768/16 = 2048Hz)
// 每个计数周期 = 1/2048 ≈ 0.488ms
clock_freq = 2048; // Hz
wakeup_counter = (interval_ms * clock_freq) / 1000 - 1;
/* 3. 限制计数值范围(WUT是16位寄存器) */
if (wakeup_counter > 0xFFFF)
wakeup_counter = 0xFFFF;
if (wakeup_counter < 1)
wakeup_counter = 1;
/* 4. 初始化并启动唤醒中断 */
// 参数:RTC句柄,唤醒计数值,时钟源
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, wakeup_counter,
RTC_WAKEUPCLOCK_RTCCLK_DIV16);
/* 5. 清除可能存在的旧标志 */
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG();
log_a("唤醒中断配置完成!\r\n");
log_a("唤醒间隔: %lu ms\r\n", interval_ms);
log_a("唤醒计数值: %lu\r\n", wakeup_counter);
}
/* 进入停止模式函数 */
void Enter_Stop_Mode(void)
{
log_a("\r\n....准备进入停止模式...\r\n");
/* 1. 确保唤醒中断已正确配置 */
if (__HAL_RTC_WAKEUPTIMER_GET_IT_SOURCE(&hrtc, RTC_IT_WUT) == RESET)
{
log_a("错误:唤醒中断未使能!\r\n");
return;
}
/* 2. 清除所有唤醒标志 */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
/* 3. 配置唤醒引脚(如果需要外部唤醒) */
// HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
/* 4. 进入停止模式(根据需求选择调节器模式) */
// 参数1:调节器模式(PWR_MAINREGULATOR_ON 或 PWR_LOWPOWERREGULATOR_ON)
// 参数2:进入模式方式(PWR_STOPENTRY_WFI 或 PWR_STOPENTRY_WFE)
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
/* 5. 唤醒后执行的代码(系统会从这里继续运行) */
SystemClock_Config(); // 重新配置系统时钟(重要!)
log_a("\r\n.....从停止模式唤醒!\r\n");
}
/* 进入待机模式函数(更低的功耗,唤醒后会复位) */
void Enter_Standby_Mode(void)
{
log_a("准备进入待机模式...\r\n");
/* 1. 清除所有唤醒标志 */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
/* 2. 使能唤醒引脚(可选) */
// HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
/* 3. 确保RTC唤醒中断已使能 */
__HAL_RTC_WAKEUPTIMER_ENABLE_IT(&hrtc, RTC_IT_WUT);
/* 4. 进入待机模式 */
HAL_PWR_EnterSTANDBYMode();
/* 注意:从待机模式唤醒后,MCU会完全复位,程序从main()重新开始执行 */
}
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
/* 1. 检查是否是唤醒中断触发 */
{
/* 2. 清除RTC唤醒中断标志(必须的步骤!) */
/* 3. 清除EXTI线路22的中断标志 */
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG();
/* 4. 执行用户代码(尽量简短) */
wakeup_flag = 1; // 设置软件标志
/* 5. 可选的LED指示(如果有LED连接) */
// HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
TRIGGLE_LED;
/* 6. 重新使能唤醒中断(某些情况下需要) */
// HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, wakeup_counter, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
}
}
void lwr_mode_run( void )
{
RTC_TimeTypeDef current_time;
/* 检查唤醒标志 */
if(wakeup_flag)
{
wakeup_flag = 0;
/* 这里可以执行周期性任务 */
// Perform_Periodic_Task();
if( lwr_sate )
{
wk_cnt++;
lwr_cnt = 0;
log_a("RTC唤醒中断触发,Current time: ");
/* 读取并显示当前RTC时间 */
HAL_RTC_GetTime(&hrtc, ¤t_time, RTC_FORMAT_BIN);
log_a("%02d:%02d:%02d\r\n",
current_time.Hours,
current_time.Minutes,
current_time.Seconds);
if(wk_cnt > 10 )
{
lwr_sate = 0;
wk_cnt = 0;
RTC_Wakeup_Config(WAKE_UP_TIME);
}
}
else
{
lwr_cnt++;
wk_cnt = 0;
}
}
/* 空闲时进入低功耗模式 */
//if (!wakeup_flag)
if( lwr_cnt > 50 && !wakeup_flag )
{
/* 按键检测示例:按下按键进入停止模式 */
// if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET)
// {
// HAL_Delay(50); // 消抖
// if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET)
// {
// Enter_Stop_Mode();
// }
// }
/* 读取并显示当前RTC时间 */
HAL_RTC_GetTime(&hrtc, ¤t_time,
RTC_FORMAT_BIN);
log_a("%02d:%02d:%02d\r\n",
current_time.Hours,
current_time.Minutes,
current_time.Seconds);
log_a(" 系统进入低功耗模式 \r\n ");
lwr_cnt = 0;
Enter_Stop_Mode();
lwr_sate = 1;
/* 进入睡眠模式(最轻度低功耗) */
// HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
}
}
/***
* lwr test
*/
void lwr_test( void )
{
lowpwr_init();
/*
配置RTC唤醒中断为2秒间隔
2000ms = 2秒
*/
RTC_Wakeup_Config(WAKE_UP_TIME);
}
4 不同场景的配置示例
1) 每隔10分钟唤醒采集数据
cpp
// 使用ck_spre(1Hz时钟源),最长可设置36小时
void Config_10min_Wakeup(void)
{
// 600秒 = 10分钟,注意WUTR最大值为0xFFFF
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 600-1, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);
}
2) 场景2:高精度每秒唤醒
cpp
void Config_1s_Wakeup(void)
{
// 使用RTCCLK/16 = 2048Hz,计数值2047
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 2047, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
}
3) 场景3:动态调整唤醒间隔
cpp
void Dynamic_Adjust_Wakeup(uint32_t new_interval_ms)
{
// 先停止定时器
HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
// 重新计算并配置
uint32_t counter = (new_interval_ms * 2048) / 1000 - 1;
if (counter > 0xFFFF) counter = 0xFFFF;
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, counter, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
// 清除旧标志
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);
}