STM32F4 低功耗 STOP 模式下的 LPTIM 微安级定时唤醒与 RTC 日历同步实战
👁 2 阅读 · 2026-08-27 · 嵌入式
在电池供电的物联网设备中,低功耗与时间精度往往难以兼得。STM32F4 的 STOP 模式可将功耗降至微安级,但传统定时器无法工作。本文深入剖析如何利用 LPTIM(低功耗定时器)在 STOP 模式下实现微安级定时唤醒,并巧妙结合 RTC 的闹钟与备份寄存器,确保唤醒后日历准确同步。文章涵盖原理、配置步骤、完整代码示例及关键注意事项,助你打造高效低功耗系统。
# 引言
在嵌入式系统设计中,低功耗是永恒的主题,尤其是对于电池供电的 IoT 节点、可穿戴设备或环境监测器。STM32F4 系列凭借其强大的性能和丰富的外设,成为许多产品的首选。然而,进入 STOP 模式后,主时钟停止,传统定时器(如 TIMx)无法工作,如何实现周期性唤醒并保持时间基准?本文将介绍一种经典方案:使用 LPTIM 实现微安级定时唤醒,同时利用 RTC 的备份寄存器与闹钟功能,确保唤醒后日历同步。
# 原理剖析
## 1. STOP 模式下的时钟域
STM32F4 的 STOP 模式会关闭除 RTC、LPTIM(若使用 LSI 或 LSE 时钟)和部分 GPIO 外的所有时钟。此时,系统电流可降至几十微安(典型值约 10-20 µA @ 25°C)。LPTIM 是一个低功耗定时器,它可以在 STOP 模式下继续运行,但必须使用 LSI(约 32 kHz)或 LSE(32.768 kHz)作为时钟源。
## 2. LPTIM 的唤醒机制
LPTIM 支持多种计数模式,其中“单次模式”或“连续模式”均可。我们通常配置为“单次模式”,即计数到设定值后产生中断,并触发唤醒事件。LPTIM 的时钟源选择 LSI,因为 LSI 在 STOP 模式下仍可工作,且功耗极低。
## 3. RTC 日历同步策略
RTC 由 LSE 驱动(若 LSE 未启用,也可用 LSI),在 STOP 模式下继续走时。但 LPTIM 唤醒后,系统时钟(如 HSI)重新启动,RTC 的时间可能因时钟切换产生微小偏差。为了确保日历同步,我们可以在进入 STOP 前,将当前 RTC 时间存入备份寄存器(BKP),唤醒后读取并校准。或者更简单:利用 RTC 闹钟中断,但这里我们使用 LPTIM 作为唤醒源,RTC 仅作为时间基准,唤醒后直接读取 RTC 时间即可,因为 RTC 在 STOP 模式下依然精确走时。
# 硬件与软件准备
- 开发板:STM32F407 Discovery 或任意 F4 系列板
- 工具:STM32CubeIDE 或 Keil MDK
- 库:HAL 库(本文基于 HAL)
# 配置步骤
## 1. 时钟配置
- 系统时钟:使用 HSE 或 HSI,PLL 倍频至 168 MHz(F407)
- LSI 使能:用于 LPTIM 时钟源
- LSE 使能(可选):用于 RTC,精度更高
在 CubeMX 中,将 LSI 使能,并将 LPTIM 时钟源选为 LSI。RTC 时钟源选为 LSE(若板上有 32.768 kHz 晶振)或 LSI。
## 2. LPTIM 配置
- 选择 LPTIM1(F4 系列通常有 LPTIM1)
- 时钟源:LSI
- 预分频器:根据所需唤醒周期计算。例如,LSI 频率为 32 kHz,若需 1 秒唤醒,则预分频设为 1(不分频),自动重载值设为 32000-1。
- 模式:单次模式(Single mode)
- 中断:使能比较匹配中断
## 3. RTC 配置
- 使能 RTC,选择 LSE 或 LSI 作为时钟源
- 配置日期和时间(初始值)
- 使能备份寄存器(BKP)用于存储标志(可选)
## 4. 低功耗模式配置
- 在进入 STOP 前,确保 LPTIM 已启动,并设置唤醒源为 LPTIM
- 使用 HAL_PWR_EnterSTOPMode() 进入 STOP 模式
# 完整代码示例
以下代码基于 HAL 库,演示了如何配置 LPTIM 和 RTC,并实现周期性唤醒。
```c
/* 包含头文件 */
#include "main.h"
#include "lptim.h"
#include "rtc.h"
/* 全局变量 */
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
/* LPTIM 初始化 */
void LPTIM_Init(void)
{
LPTIM_HandleTypeDef hlptim;
hlptim.Instance = LPTIM1;
hlptim.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK; // 实际应改为 LSI,但 HAL 中需通过 RCC 配置
hlptim.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1;
hlptim.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
hlptim.Init.Output.Polarity = LPTIM_OUTPUTPOLARITY_HIGH;
hlptim.Init.Output.Pin = LPTIM_OUTPUT_PIN_1;
hlptim.Init.Output.Mode = LPTIM_OUTPUTMODE_PWM;
hlptim.Init.Clock.Filter = LPTIM_CLOCKFILTER_NONE;
HAL_LPTIM_Init(&hlptim);
/* 设置自动重载值,假设 LSI=32kHz,1秒唤醒 */
HAL_LPTIM_SetOnce_IT(&hlptim, 32000 - 1);
}
/* RTC 初始化 */
void RTC_Init(void)
{
RTC_HandleTypeDef hrtc;
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.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
HAL_RTC_Init(&hrtc);
/* 设置初始时间:2024-01-01 00:00:00 */
sTime.Hours = 0;
sTime.Minutes = 0;
sTime.Seconds = 0;
sDate.Year = 24;
sDate.Month = 1;
sDate.Date = 1;
HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
}
/* LPTIM 中断回调 */
void HAL_LPTIM_CompareMatchCallback(LPTIM_HandleTypeDef *hlptim)
{
// 唤醒后执行的任务
// 读取 RTC 时间
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
printf("Wake up at %02d:%02d:%02d\n", sTime.Hours, sTime.Minutes, sTime.Seconds);
// 重新设置 LPTIM 以准备下一次唤醒
HAL_LPTIM_SetOnce_IT(&hlptim, 32000 - 1);
}
/* 主函数 */
int main(void)
{
HAL_Init();
SystemClock_Config();
LPTIM_Init();
RTC_Init();
// 启动 LPTIM
HAL_LPTIM_Start_IT(&hlptim);
while (1)
{
// 进入 STOP 模式,LPTIM 唤醒
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 唤醒后重新配置系统时钟(因为 STOP 会关闭 PLL)
SystemClock_Config();
// 可以在这里执行其他任务
}
}
```
**注意**:上述代码中 LPTIM 时钟源配置需在 CubeMX 中正确设置,HAL 库中通过 `__HAL_RCC_LPTIM1_CLK_ENABLE()` 和 `__HAL_RCC_LSI_ENABLE()` 使能时钟,并确保 LPTIM 时钟选择为 LSI。
# 注意事项
1. **时钟源选择**:LPTIM 必须使用 LSI 或 LSE,不能使用 HSI,否则在 STOP 模式下会停止。确保 LSI 已使能。
2. **唤醒后系统时钟重配**:从 STOP 模式唤醒后,系统时钟默认使用 HSI,需要重新调用 `SystemClock_Config()` 恢复为 PLL 高速时钟,否则外设可能运行异常。
3. **LPTIM 重载值计算**:LSI 频率有误差(典型 ±5%),若需精确周期,建议使用 LSE(32.768 kHz)并校准。
4. **RTC 精度**:RTC 使用 LSE 时精度更高,但 LSE 晶振可能未焊接,需检查硬件。若使用 LSI,则 RTC 误差较大。
5. **中断优先级**:LPTIM 中断优先级应高于其他可屏蔽中断,确保唤醒后及时处理。
6. **功耗优化**:进入 STOP 前,关闭不必要的外设时钟,并将 GPIO 设置为模拟输入或低功耗状态,以降低漏电流。
7. **调试**:在调试时,STOP 模式可能导致调试器断开,建议使用 `HAL_DBGMCU_EnableDBGStopMode()` 保持调试时钟。
# 总结
通过 LPTIM 与 RTC 的配合,STM32F4 可以在 STOP 模式下实现微安级功耗的定时唤醒,同时保持日历的准确同步。本文提供了完整的配置思路和代码示例,开发者可根据实际需求调整唤醒周期和任务逻辑。这种方案在智能传感器、远程监控等场景中极具实用价值。