4. 电源管理模式深度解析:Run、Sleep、Low-power Run、Stop 0/1/2、Standby、Shutdown 模式切换与实测

各位做电池项目的朋友,电源管理这块儿,说白了就是跟功耗较劲。STM32L4 给了我们七种模式,从跑得最快的 Run 到几乎断电的 Shutdown。怎么选?什么时候切?切换代价多大?这章我带你一个一个摸清楚。

核心原则:性能越高,功耗越大;睡越死,唤醒越慢。没有银弹,只有权衡。

4.1 七种模式速览

先看一张总表,心里有个谱。我习惯把这七种模式分成三档:干活档(Run、Low-power Run)、打盹档(Sleep、Stop 0/1/2)、死睡档(Standby、Shutdown)。

模式 CPU 状态 SRAM 保留 典型电流 唤醒源 唤醒时间
Run 运行 全部 ~100 µA/MHz — —
Sleep 暂停 全部 ~50 µA/MHz 任何中断 ~5 个周期
Low-power Run 降频运行 全部 ~8 µA — —
Stop 0 停止 全部 ~100 µA 任意 EXTI ~5 µs
Stop 1 停止 全部 ~3 µA 任意 EXTI ~5 µs
Stop 2 停止 部分 ~1 µA 有限 EXTI ~6 µs
Standby 断电 2 KB ~0.3 µA WKUP 引脚、RTC ~50 µs
Shutdown 断电 无 ~0.02 µA WKUP 引脚 ~150 µs

看到没?从 Stop 0 到 Stop 2,电流差了 100 倍,但唤醒时间几乎没变。这就是 L4 的厉害之处。

4.2 干活档:Run 与 Low-power Run

Run 模式没啥好说的,就是正常跑。但要注意,L4 在 Run 模式下可以动态调频调压。我有个项目,平时跑 80 MHz,空闲时降到 2 MHz,电流从 8 mA 直接掉到 200 µA。这个技巧后面章节会细讲。

Low-power Run 是个好东西。它让 CPU 还能跑,但只能跑 2 MHz,电压也降到最低。适合什么场景?比如你正在做 ADC 采样,采样率不高,但又不想进 Stop 模式来回折腾。

我的习惯:如果任务能在 1 ms 内干完,我倾向于进 Stop 模式;如果任务要持续几十毫秒,Low-power Run 更划算。因为进 Stop 再出来,那几十微秒的唤醒时间也是成本。

4.3 打盹档:Sleep 与 Stop 0/1/2

Sleep 模式最简单,CPU 停了,外设还在跑。适合那种外设自己干活、CPU 等着收结果的场景。比如 SPI 发完一帧数据,CPU 睡过去,DMA 传完再叫醒它。

Stop 模式才是重头戏。L4 给了三个版本,我当年第一次看到时也懵了。其实区别就两点:稳压器状态和SRAM 保留范围。

  • Stop 0:主稳压器开着,所有 SRAM 都保留。唤醒最快,但功耗最高。
  • Stop 1:主稳压器关了,用低功耗稳压器。所有 SRAM 保留,但功耗降了一个数量级。
  • Stop 2:低功耗稳压器,但只保留前 64 KB SRAM。后 64 KB 断电。

我在一个传感器节点项目里,数据量不大,就用了 Stop 2。把关键变量放在前 64 KB,后 64 KB 放临时缓冲区,反正唤醒后重新初始化就行。电流从 3 µA 降到了 1 µA,电池寿命多了半年。

注意:Stop 2 模式下,不是所有 EXTI 线都能唤醒。只有 PWR 唤醒引脚和部分 RTC 事件可以。设计时一定要看数据手册的唤醒源表格,别到时候叫不醒。

4.4 死睡档:Standby 与 Shutdown

这两个模式,CPU 彻底断电了。区别在于:Standby 还留了 2 KB 的备份 SRAM 和 RTC,Shutdown 连 RTC 都关了,只剩几个唤醒引脚还能工作。

我曾经做过一个产品,用户一年才换一次电池。平时就是 Shutdown,每天 RTC 闹钟唤醒一次,采集数据、发送、再睡回去。0.02 µA 的待机电流,几乎可以忽略不计。

但代价是什么?唤醒后相当于复位,所有变量都得重新初始化。所以,Standby 适合需要保留少量状态(比如计数器、校准值)的场景,Shutdown 适合那种「醒来后从头再来」的场景。

4.5 模式切换实战代码

光说不练假把式。下面给几个最常用的切换代码片段。注意,切换前一定要关掉不用的外设时钟,否则电流降不下去。

进入 Stop 2 模式

// 进入 Stop 2 模式
// 1. 关掉不用的外设时钟
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
// ... 其他外设

// 2. 配置 Stop 模式等级
HAL_PWREx_EnableLowPowerRunMode();  // 可选,如果之前是 Low-power Run
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);

// 3. 醒来后恢复时钟
SystemClock_Config();  // 重新配置系统时钟

进入 Standby 模式

// 进入 Standby 模式
// 1. 使能唤醒引脚(以 PA0 为例)
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);

// 2. 清除唤醒标志
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

// 3. 进入 Standby
HAL_PWR_EnterSTANDBYMode();

// 4. 醒来后从复位向量表重新执行

进入 Shutdown 模式

// 进入 Shutdown 模式
// 1. 使能唤醒引脚
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);

// 2. 清除标志
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

// 3. 进入 Shutdown
HAL_PWREx_EnterSHUTDOWNMode();

// 4. 醒来后也是复位,但 RTC 不保留

避坑指南:我曾经在进入 Standby 前忘了关 ADC,结果待机电流多了 2 µA。查了两天才发现,ADC 的校准电路在 Standby 模式下还在耗电。所以,进低功耗前,把所有模拟外设都关掉,包括 ADC、DAC、OPAMP、COMP。

4.6 实测数据对比

下面是我用 L476RG 开发板实测的数据。环境:室温 25°C,VDD = 3.3 V,所有 GPIO 配置为模拟输入(最省电)。

模式 实测电流 唤醒时间 备注
Run (80 MHz) 8.2 mA — Flash 预取开启
Sleep (80 MHz) 4.1 mA ~0.1 µs 外设时钟全开
Low-power Run (2 MHz) 8.5 µA — 内部 RC 振荡器
Stop 0 112 µA 4.8 µs 主稳压器开启
Stop 1 3.2 µA 5.1 µs 低功耗稳压器
Stop 2 1.1 µA 5.6 µs 部分 SRAM 断电
Standby 0.35 µA 48 µs RTC 运行
Shutdown 0.02 µA 145 µs RTC 关闭

看到 Stop 0 和 Stop 1 的差距了吗?同样是所有 SRAM 保留,就因为稳压器不同,电流差了 35 倍。所以,除非你需要极快的唤醒响应,否则别用 Stop 0。

4.7 模式切换决策流程

最后,我画了一张决策图,帮你快速选模式。嗯,这个图我每次做新项目都会拿出来看一眼。

STM32L4 电源模式选择决策流程 需要 CPU 运行? 是 → 需要高频? Run 模式 Low-power Run 否 → 需要保留全部 SRAM? Stop 0 / Stop 1 Stop 2 需要 RTC 或备份 SRAM? Standby Shutdown 提示:Stop 0 与 Stop 1 的选择取决于是否需要极快唤醒(< 5 µs),否则优先用 Stop 1

说白了,选模式就是回答三个问题:CPU 要不要跑?SRAM 要留多少?唤醒要多快?回答完,答案自然就出来了。

最后一句经验之谈:别在代码里硬编码模式。我习惯在工程里定义一个 power_profile.h,把模式选择、唤醒源、唤醒时间都配成宏。换电池方案时,改几个宏就行,不用动业务逻辑。