4、低功耗模式详解(上):Sleep模式原理与配置

各位同学,咱们今天聊聊 Sleep 模式。说实话,在 STM32L4 的几种低功耗模式里,Sleep 是最简单、最基础的一个。但你别因为它简单就跳过——我见过不少项目,明明用 Sleep 就能解决的问题,愣是上了 Stop 甚至 Standby,结果外设重配搞得焦头烂额。

说白了,Sleep 模式就是「CPU 歇着,外设继续干活」。它不像 Stop 那样把大部分时钟都关了,也不像 Standby 那样几乎全系统掉电。Sleep 只是把 CPU 的时钟停了,其他一切照旧。

4.1 Sleep 模式的核心原理

先看一张图,把 Sleep 在整个低功耗体系里的位置搞清楚。

STM32L4 低功耗模式层级关系 Run 模式 Sleep 模式 Low-power Run Stop 0 / 1 / 2 Standby VBAT 模式 Sleep 模式:CPU 时钟停止,外设时钟保持,唤醒最快

从图上能看出来,Sleep 是离 Run 最近的一级。它的功耗降幅不大,但唤醒速度极快——几乎就是瞬间的事。我有个项目做手持数据采集器,要求每次采样间隔 100ms 内完成,中间 CPU 闲着也是闲着,直接进 Sleep,醒来继续干活,效果非常好。

4.2 Sleep 模式的两种变体

STM32L4 的 Sleep 模式其实有两种,区别在于系统时钟和内核时钟的处理方式。

特性 Sleep-on-Exit 普通 Sleep
触发方式 中断返回时自动进入 执行 WFI/WFE 指令
CPU 时钟 停止 停止
系统时钟 (SYSCLK) 保持运行 保持运行
外设时钟 全部保持 全部保持
典型唤醒时间 几个 CPU 周期 几个 CPU 周期
适用场景 中断驱动的轮询任务 主循环中主动休眠

我个人习惯用普通 Sleep 配合 WFI 指令,因为控制逻辑更直观。Sleep-on-Exit 适合那种「中断处理完就没事了」的场景,比如定时器触发 ADC 采样,采完就睡,等下次中断再醒。

4.3 进入与退出 Sleep 模式实战

咱们直接上代码。下面是一个完整的 Sleep 模式进入/退出示例,配合外部中断唤醒。

/* 进入 Sleep 模式的典型配置 */
void enter_sleep_mode(void)
{
    /* 1. 清除唤醒标志 */
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

    /* 2. 选择 Sleep 模式(默认就是 Sleep,但显式设置更安全) */
    HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);

    /* 3. 醒来后从这里继续执行 */
    /* 注意:醒来后 CPU 自动恢复运行,无需额外配置 */
}

/* 外部中断回调 - 唤醒后执行 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == WAKEUP_PIN)
    {
        /* 处理唤醒事件 */
        /* 我习惯在这里加一个去抖延时 */
        HAL_Delay(10);
        /* 读取按键状态或传感器数据 */
    }
}
小技巧:进入 Sleep 前,建议把不用的外设时钟先关了。虽然 Sleep 模式下外设时钟还在跑,但你不用的外设时钟开着就是浪费。我一般在进入 Sleep 前调用一个 DisableUnusedPeriphClocks() 函数,醒来后再恢复。

退出 Sleep 模式有三种方式:

  • 任何中断:只要该中断的优先级高于当前 CPU 优先级,就能唤醒
  • 事件 (Event):通过 SEV 指令或外设事件唤醒
  • 复位:最粗暴的方式,一般不这么用

实际项目中,我最常用的是外部中断唤醒。比如按键按下、传感器数据准备好、RTC 闹钟——这些都是典型的唤醒源。

4.4 Sleep 模式下的外设状态

这一点特别重要,也是很多新手容易踩坑的地方。Sleep 模式下,外设的状态是这样的:

外设类型 Sleep 模式下状态 注意事项
GPIO 保持配置,输出电平不变 注意外部上拉/下拉电阻的功耗
定时器 (TIM/LPTIM) 继续运行 可用于周期性唤醒
USART/I2C/SPI 继续运行 可接收数据并产生中断唤醒
ADC/DAC 继续运行 注意转换完成中断可唤醒
DMA 继续运行 传输完成中断可唤醒
RTC 继续运行 闹钟唤醒的经典方案
Flash 接口 保持就绪 唤醒后立即取指,无延迟
曾经踩过的坑:我之前有个项目,Sleep 模式下用 USART 接收数据唤醒。结果发现 USART 的 RX 引脚在 Sleep 模式下有漏电流,导致整机功耗比预期高了 200μA。排查了半天,最后发现是 GPIO 的上下拉配置和外部电路不匹配。所以,进 Sleep 前一定要检查所有引脚的电气状态。

4.5 实际项目中的 Sleep 模式使用策略

我总结了几条经验,供你参考:

  1. 能不睡就不睡?错! 只要 CPU 在空转,就该进 Sleep。哪怕只睡 1ms,也能省下不少电。
  2. 外设时钟管理是关键。 进 Sleep 前关掉不用的外设时钟,醒来再开。这个动作虽然简单,但效果立竿见影。
  3. 注意唤醒源的选择。 不是所有中断都适合做唤醒源。比如按键中断,一定要做去抖处理,否则可能一秒钟唤醒几十次。
  4. 测量实际功耗。 不要只看数据手册。我习惯在 Sleep 模式下用万用表串进去测电流,经常能发现意料之外的漏电路径。

核心要点:Sleep 模式是 STM32L4 低功耗设计的「入门级」武器。它简单、可靠、唤醒快,适合那些需要频繁唤醒、每次工作时间很短的场景。如果你发现项目功耗还是降不下来,别急着上 Stop 或 Standby,先检查 Sleep 模式下有没有外设还在偷偷耗电。