4. 电源管理模式详解:Run、Sleep、Low-power Run、Stop 0/1/2、Standby、Shutdown

说实话,STM32L4 的电源管理,是我见过最灵活也最容易踩坑的模块之一。它不像有些芯片只有「醒着」和「睡着」两种状态,而是给你准备了整整 7 种运行模式。每种模式都有自己的脾气,切换不对,功耗就下不去。

我个人习惯,拿到一个新项目,先不看外设,先把电源模式画个图理清楚。因为后面所有的低功耗优化,本质上都是在这些模式之间做选择和切换。

4.1 七种模式,一张图看懂

先看这张总览图,把 STM32L4 的电源模式家族串起来。你想想看,从最高功耗到最低功耗,其实是一条「功能逐步剥离」的链条。

核心思路: 功耗每降一级,你就得放弃一部分硬件功能。关键是在「够用」和「省电」之间找到平衡点。

STM32L4 电源管理模式总览 STM32L4 电源管理模式总览 高功耗 低功耗 Run Sleep Low-power Run Stop 0 / 1 / 2 Standby Shutdown 关键特性:从左到右,CPU 停止 → 时钟关闭 → 电压调节器关闭 → RAM 保留 → RAM 全部丢失 Run / Sleep • CPU 运行或休眠 • 所有外设可用 • 功耗:~100μA/MHz • 唤醒:立即 Low-power Run • CPU 低速运行 • 仅 MSI 时钟 • 功耗:~8μA • 唤醒:立即 Stop 0 / 1 / 2 • CPU 停止,RAM 保留 • 电压调节器可选 • 功耗:Stop2 最低 ~1μA • 唤醒:~5μs Standby / Shutdown • 大部分电路断电 • Standby:保留 2KB RAM + 备份寄存器 • Shutdown:全部丢失,仅唤醒引脚有效 • 功耗:Standby ~100nA,Shutdown ~30nA 唤醒时间对比 • Sleep / Low-power Run:立即 • Stop 0/1/2:~5μs • Standby:~50μs • Shutdown:~150μs

4.2 Run 模式与 Sleep 模式

Run 模式,就是芯片全速工作的状态。CPU 跑着,所有外设都能用,时钟该开的都开着。这时候功耗最高,大概在 100μA/MHz 左右。没什么好说的,干活的时候就得这样。

Sleep 模式,说白了就是 CPU 暂停了,但外设还在跑。你想想看,如果你只是等一个串口数据,或者等一个定时器溢出,完全没必要让 CPU 空转。这时候进 Sleep,功耗能降一半左右。

我的经验: 很多初学者觉得 Sleep 模式没用,因为「反正很快就醒了」。但我在一个数据采集项目里,把主循环中所有等待都改成 Sleep + 事件唤醒,整体功耗降了 40%。积少成多,效果很可观。

// 进入 Sleep 模式的典型代码
HAL_SuspendTick();          // 暂停系统滴答定时器
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
// 醒来后继续执行
HAL_ResumeTick();

4.3 Low-power Run 模式

这个模式有点意思。CPU 还在跑,但只能跑 MSI 时钟,最高 2MHz。电压调节器也切到低功耗档。功耗能压到 8μA 左右。

我在一个手持仪表项目里用过这个模式。设备大部分时间在采集传感器数据,不需要高速处理。我就把主频降到 2MHz,用 Low-power Run 跑。等数据攒够了,再切回正常 Run 模式做运算。效果很好,电池续航直接翻倍。

注意: 进入 Low-power Run 之前,一定要先把系统时钟切换到 MSI。如果你还挂着 HSI 或 HSE,直接调用 HAL_PWREx_EnableLowPowerRunMode() 会失败。我刚开始就踩过这个坑,查了半天才发现是时钟源没切。

// 进入 Low-power Run 模式的步骤
// 1. 先切换到 MSI 时钟
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
// 2. 使能低功耗运行模式
HAL_PWREx_EnableLowPowerRunMode();
// 3. 现在可以降频到 2MHz 以下
// ... 执行低功耗任务 ...
// 4. 退出时先禁能低功耗运行模式
HAL_PWREx_DisableLowPowerRunMode();

4.4 Stop 0/1/2 模式:最常用的低功耗模式

Stop 模式是 STM32L4 低功耗设计的核心。它有三个子模式,差别在于电压调节器的状态和唤醒速度。

特性 Stop 0 Stop 1 Stop 2
电压调节器 MR(主调节器) LPR(低功耗调节器) LPR(低功耗调节器)
典型功耗 ~50μA ~5μA ~1μA
唤醒时间 ~3μs ~5μs ~7μs
RAM 保留 全部 全部 全部
GPIO 状态 保持 保持 保持
适用场景 快速唤醒 平衡模式 超低功耗待机

你可能会问:「三个模式差别不大,我该用哪个?」

我的建议是:默认用 Stop 1。它功耗和唤醒时间都比较均衡。如果你需要频繁唤醒(比如 1ms 一次),用 Stop 0。如果你能接受稍慢的唤醒,比如 10ms 才需要响应一次,用 Stop 2。

关键点: Stop 模式下,所有时钟都停了,但 RAM 和寄存器内容全部保留。醒来后程序从原地继续执行,就像什么都没发生过。这是它和 Standby 最大的区别。

// 进入 Stop 2 模式
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);

// 进入 Stop 1 模式
HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI);

// 进入 Stop 0 模式(通过标准 Stop 函数)
HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);

4.5 Standby 模式与 Shutdown 模式

这两个模式是「狠角色」。进去之后,大部分电路都断电了。CPU 内核、大部分外设、甚至一部分 RAM 都没了。

Standby 模式,还保留着 2KB 的备份 SRAM 和备份寄存器。你可以把关键数据存在那里。唤醒后,程序从头开始执行(类似复位),但你可以通过检查复位标志来判断是从 Standby 醒来的。

Shutdown 模式,更彻底。连备份域的部分电路都断了。只留下几个唤醒引脚还能工作。功耗低到 30nA 左右。适合那种「一年换一次电池」的设备。

我曾经犯过的错: 在一个产品中,我把 RTC 闹钟配置为 Standby 唤醒源。结果发现设备每隔几秒就重启一次。查了两天才发现,RTC 闹钟标志在进入 Standby 前没有清除,导致一醒来又触发闹钟,又进 Standby。死循环了。所以记住:进 Standby 前,一定要清除所有唤醒标志。

// 进入 Standby 模式
HAL_PWR_EnterSTANDBYMode();

// 进入 Shutdown 模式
HAL_PWREx_EnterSHUTDOWNMode();

// 检查复位原因(判断是否从 Standby 醒来)
if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET) {
    // 从 Standby 醒来
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
}

4.6 模式切换的避坑指南

说了这么多,最后总结几条实战经验。这些都是我拿真金白银换来的教训。

  • 时钟源要提前切好。 进 Low-power Run 前切到 MSI,进 Stop 前确保没有外设在用 HSE。否则切换会失败,或者功耗下不去。
  • 外设要提前关掉。 进低功耗模式前,把不需要的外设时钟关了。尤其是 ADC、DAC、USB 这些耗电大户。我见过有人进 Stop 2 还有 10μA,查了半天发现是 ADC 没关。
  • GPIO 要处理好。 浮空的 GPIO 会漏电。进低功耗前,把所有不用的引脚设成模拟模式,或者拉高/拉低。这个细节能省下 1-2μA。
  • 唤醒源要配置正确。 不是所有中断都能在 Stop 模式下唤醒芯片。只有那些标记为「可唤醒」的中断才行。具体看参考手册的「Wakeup from Stop mode」章节。
  • 测量功耗要用实际电路。 开发板上的电流测量跳线往往不准。我习惯自己焊一个 10Ω 采样电阻,用示波器看电压降,这样能精确看到每个模式下的电流波形。

一个小技巧: 调试低功耗时,别一上来就追求最低功耗。先让设备在 Stop 1 模式下跑起来,确认能正常唤醒。然后再一步步优化到 Stop 2、Standby。这样出问题了容易定位。

好了,电源管理模式就讲到这里。这章内容比较多,但都是后面实战的基础。你把这些模式的特性和切换条件记熟,后面做低功耗优化就会顺手很多。