引言

在物联网、可穿戴设备等电池供电场景中,MCU 大部分时间处于低功耗模式,仅需周期性醒来执行任务。STM32F4 系列支持多种低功耗模式,其中 STOP 模式在保留 SRAM 和寄存器内容的同时,可将电流降至微安级,是兼顾功耗与唤醒速度的理想选择。然而,STOP 模式下高频时钟停止,传统定时器无法工作,多数开发者会立即想到 RTC。但 RTC 唤醒精度通常为秒级,且需配置外部 32.768kHz 晶振,对于毫秒级精确唤醒需求(如传感器采样间隔 10ms)显得力不从心。

幸运的是,STM32F4 内置了 LPTIM(Low-Power Timer),它可在 STOP 模式下依靠低速时钟(如 LSI 或 LSE)独立运行,支持最高 16 位计数,配合时钟预分频,可实现微秒到秒级的灵活定时,且唤醒延迟极低。本文将手把手教你如何配置 LPTIM,实现不依赖 RTC 的毫秒级精确唤醒。

LPTIM 工作原理

LPTIM 是一个专为低功耗场景设计的 16 位定时器,其核心特性包括:

  • 时钟源灵活:可选择 LSI(约 32kHz)、LSE(32.768kHz)或外部时钟,在 STOP 模式下 LSI 和 LSE 仍可运行。
  • 独立于内核:LPTIM 计数不依赖 CPU 时钟,唤醒后无需重新初始化。
  • 多种触发模式:支持单次、连续计数,以及比较匹配、自动重载等。
  • 超低功耗:自身功耗仅微安级,对整体功耗影响极小。

在 STOP 模式下,LPTIM 使用其时钟源持续计数,当计数值达到预设的自动重载值(ARR)时,产生比较匹配事件,该事件可直接触发唤醒信号,将 MCU 从 STOP 模式拉回运行模式。唤醒后,CPU 可立即读取 LPTIM 状态,确认唤醒源。

硬件与时钟配置

以 STM32F407 为例,我们选择 LSI 作为 LPTIM 时钟源,频率约为 32kHz(实际范围 17~47kHz,需校准)。为了获得精确的毫秒定时,我们使用预分频器将 LSI 分频至 1kHz(即 1ms 计数一次)。

关键寄存器

  • RCC->APB1ENR:使能 LPTIM1 时钟(注意:在 STOP 模式下,APB 时钟停止,但 LPTIM 时钟由独立时钟源提供)。
  • RCC->CSR:使能 LSI 并等待就绪。
  • LPTIM->CFGR:配置时钟源、预分频因子。
  • LPTIM->ARR:设置自动重载值,决定唤醒周期。
  • LPTIM->CR:使能 LPTIM 并启动。

配置步骤

1. 使能 LSI 时钟

void LSI_Init(void) {
    RCC->CSR |= RCC_CSR_LSION;               // 使能 LSI
    while ((RCC->CSR & RCC_CSR_LSIRDY) == 0); // 等待就绪
}

2. 配置 LPTIM 时钟源与预分频

void LPTIM_Config(uint16_t arr_value) {
    // 使能 LPTIM1 时钟(在正常运行模式下,APB1 时钟必须开启)
    RCC->APB1ENR |= RCC_APB1ENR_LPTIM1EN;

    // 选择 LSI 作为时钟源,并设置预分频为 32(LSI/32 ≈ 1kHz)
    LPTIM->CFGR = (LPTIM_CFGR_CKSEL_1) | (LPTIM_CFGR_PRESC_2); // CKSEL=1 (LSI), PRESC=2 (分频32)

    // 设置自动重载值,例如 arr_value=10 则 10ms 唤醒
    LPTIM->ARR = arr_value;

    // 使能 LPTIM,并启动单次模式(也可用连续模式)
    LPTIM->CR |= LPTIM_CR_ENABLE;
    LPTIM->CR |= LPTIM_CR_SNGSTRT;  // 单次启动,也可用 CONT 位连续运行
}

3. 进入 STOP 模式并等待唤醒

void EnterStopMode(void) {
    // 设置唤醒源为 LPTIM 事件
    PWR->CR |= PWR_CR_LPDS;          // 低功耗深睡眠(STOP 模式)
    PWR->CR |= PWR_CR_CWUF;          // 清除唤醒标志
    __DSB();
    // 进入 STOP 模式(WFI 或 WFE)
    __WFI();
    // 唤醒后,立即关闭 LPTIM 或重新配置
    LPTIM->CR &= ~LPTIM_CR_ENABLE;   // 可选:禁用 LPTIM
}

4. 完整示例:周期性唤醒执行任务

#include "stm32f4xx.h"

void SystemClock_Config(void); // 标准时钟配置,略

int main(void) {
    HAL_Init();
    SystemClock_Config();

    // 初始化 LSI 和 LPTIM
    LSI_Init();
    LPTIM_Config(10);  // 10ms 唤醒周期

    while (1) {
        // 进入 STOP 模式,等待 LPTIM 唤醒
        EnterStopMode();

        // 唤醒后执行任务(例如读取传感器)
        // 注意:唤醒后系统时钟可能仍为 HSI,需重新配置或直接使用
        GPIO_ToggleBits(GPIOD, GPIO_Pin_12); // 示例:翻转 LED
    }
}

注意事项

  • 时钟精度:LSI 频率误差较大(±50%),若需高精度定时,建议使用 LSE 外部晶振(32.768kHz),但需额外硬件。也可在运行时校准 LSI。
  • 唤醒延迟:从 LPTIM 匹配到 CPU 执行第一条指令,存在约 5~10 个 LSI 周期的延迟,对于 1kHz 时钟,约 5~10ms,需在应用层补偿。
  • LPTIM 复位:在 STOP 模式下,LPTIM 寄存器内容保留,但唤醒后建议重新初始化以确保状态干净。
  • 中断与标志:LPTIM 比较匹配可产生中断,但唤醒时无需中断,直接通过 WFI 唤醒即可。若需中断处理,需在 NVIC 中使能 LPTIM 全局中断。
  • 功耗优化:在 STOP 模式下,关闭所有不必要的外设时钟,并将 GPIO 设置为模拟输入或下拉,以降低漏电流。
  • 调试注意:使用调试器时,STOP 模式可能导致连接断开,建议在调试时禁用低功耗或使用串口打印。

总结

通过 LPTIM,STM32F4 在 STOP 模式下实现了毫秒级精确唤醒,且不依赖 RTC,大大简化了低功耗设计。本文提供了从原理到代码的完整指南,帮助开发者快速上手。实际项目中,可根据需求调整预分频和 ARR 值,实现从 1ms 到 65 秒的灵活定时。掌握这一技巧,你的嵌入式设备将兼具超低功耗与高实时性。