# 引言 在嵌入式系统设计中,低功耗是永恒的主题,尤其是对于电池供电的 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 模式下实现微安级功耗的定时唤醒,同时保持日历的准确同步。本文提供了完整的配置思路和代码示例,开发者可根据实际需求调整唤醒周期和任务逻辑。这种方案在智能传感器、远程监控等场景中极具实用价值。