4. 低功耗模式详解:Sleep、Stop0/1/2、Standby、Shutdown
低功耗设计,说白了就是让芯片在没事干的时候尽量「睡过去」。但怎么睡、睡多深、醒来要多快,这里面门道不少。STM32L4 给了我们好几种睡眠模式,从打个盹到彻底关机,各有各的用场。
我刚开始做低功耗项目时,总觉得选个最省电的模式就对了。结果呢?要么唤醒太慢,要么该干活的时候起不来。后来踩过几次坑,才真正搞明白这些模式该怎么用。
4.1 Sleep 模式——打个盹
Sleep 模式是最浅的睡眠。CPU 停了,但外设还在跑。你想想看,就像你躺在床上闭着眼,但耳朵还能听见周围的声音。
进入 Sleep 很简单,执行一条 WFI 或 WFE 指令就行。唤醒也快,任何中断都能把它叫醒。我有个项目是做无线传感器,数据采集间隔 100ms,中间就用 Sleep 模式。每次采集完睡过去,定时器一到就醒,功耗从 10mA 降到了 3mA 左右。
4.2 Stop 模式——深度睡眠
Stop 模式就厉害了。内核掉电,但 SRAM 和寄存器内容都保留。说白了就是「脑子关机了,但记忆还在」。STM32L4 给了我们三个 Stop 子模式:Stop 0、Stop 1、Stop 2。
| 特性 | Stop 0 | Stop 1 | Stop 2 |
|---|---|---|---|
| 典型功耗 | ~100 μA | ~30 μA | ~3 μA |
| 唤醒时间 | ~5 μs | ~10 μs | ~15 μs |
| SRAM 保持 | 全部 | 全部 | 全部 |
| RTC 可用 | 是 | 是 | 是 |
| LPUART 可用 | 是 | 是 | 是 |
| LPTIM 可用 | 是 | 是 | 是 |
| ADC 可用 | 是 | 否 | 否 |
看到这个表,你应该明白了。Stop 0 功耗最高但唤醒最快,Stop 2 最省电但唤醒最慢。怎么选?看你的应用场景。
我曾经做过一个便携式医疗设备,要求电池用一年。大部分时间设备在待机,但需要 RTC 定时唤醒做测量。我选了 Stop 2 模式,配合 RTC 唤醒,待机功耗做到了 3.5 μA。客户测试下来,两节 CR2032 电池确实撑了 14 个月。
4.3 Standby 模式——彻底关机
Standby 模式就更狠了。SRAM 掉电,寄存器全丢,除了备份域(Backup Domain)里的东西,啥都不剩。唤醒后相当于复位重跑。
功耗能降到 0.3 μA 左右。但代价是什么?唤醒后代码从头执行,变量全没了。你得把关键数据存到备份寄存器或者 RTC 的备份 SRAM 里。
我记得有个项目是做户外环境监测,设备装在野外,半年换一次电池。平时就 Standby 模式,每天定时唤醒一次,采集数据、通过 LoRa 发出去,然后继续睡。功耗算下来,两节 AA 电池能撑 8 个月。
4.4 Shutdown 模式——终极省电
Shutdown 模式是 STM32L4 的终极武器。功耗低到 0.1 μA 以下,比 Standby 还省。但代价也更大——连备份域的部分功能都关了。
Shutdown 模式下,只有 RTC 的特定唤醒事件和 WKUP 引脚能唤醒。而且唤醒后,系统从复位开始跑,连 RTC 的配置都可能需要重新初始化。
说实话,Shutdown 模式我用得不多。只有在那些对功耗要求极其苛刻的场景才会用。比如纽扣电池供电、一年只工作几次的设备。
4.5 模式选择决策流程
这么多模式,到底怎么选?我一般按这个思路来:
- 先看唤醒频率——如果每秒唤醒多次,用 Sleep 或 Stop 0
- 再看唤醒源——如果需要 UART 唤醒,只能用 Stop 模式
- 然后看数据保持需求——如果变量不能丢,别用 Standby 或 Shutdown
- 最后算功耗预算——根据电池容量和目标续航,反推允许的待机功耗
你想想看,如果设备每 10 秒醒一次,每次工作 50ms,那大部分时间在待机。这时候待机功耗就决定了整机续航。选对模式,电池寿命能差好几倍。
4.6 代码示例:进入 Stop 2 模式
说了这么多,来点实际的。下面这段代码演示如何进入 Stop 2 模式,并用 RTC 唤醒:
// 进入 Stop 2 模式示例
void Enter_Stop2_Mode(void)
{
// 1. 关闭不用的外设时钟
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
// ... 其他外设
// 2. 配置 RTC 唤醒(假设已初始化)
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 4000, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
// 每 4000 个时钟周期唤醒一次,约 1 秒(假设 LSE 32.768kHz)
// 3. 进入 Stop 2 模式
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
// 4. 唤醒后从这里继续执行
// 重新配置系统时钟
SystemClock_Config();
// 重新使能外设时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
// ...
}
这段代码看起来简单,但有几个细节要注意。RTC 唤醒的时钟源、分频系数、重装值,都要算清楚。我见过有人把分频设错了,本来想 1 秒唤醒一次,结果 10 秒才醒一次,数据采集全乱了。
好了,这几种模式的区别和用法,你应该心里有数了。记住,没有最好的模式,只有最适合你项目的模式。选对了,电池能多用好几个月;选错了,调试能让你怀疑人生。