2、低功耗模式设计:MCU睡眠/停止/待机模式详解、唤醒源配置、功耗测量方法
做工业产品,功耗这关绕不过去。尤其是电池供电的设备,比如无线传感器、便携仪表,功耗设计直接决定了产品能用多久。我见过不少工程师,代码写得飞起,结果一测功耗,几十毫安,电池撑不了几天。嗯,这其实不是代码的问题,是MCU的低功耗模式没用好。
今天我们就来聊聊MCU的三种低功耗模式:睡眠、停止、待机。我会结合我自己的项目经验,把每种模式的特点、唤醒源、以及怎么测功耗,都给你讲透。
2.1 三种低功耗模式,到底怎么选?
不同MCU厂商的叫法可能不一样,但核心逻辑差不多。以STM32为例,我们常说的就是睡眠(Sleep)、停止(Stop)、待机(Standby)。说白了,就是“睡多深”的区别。
| 模式 | 内核状态 | 外设状态 | RAM保持 | 典型功耗 | 唤醒时间 |
|---|---|---|---|---|---|
| 睡眠(Sleep) | 停止 | 运行 | 全部保持 | ~mA级 | ~us级 |
| 停止(Stop) | 停止 | 可配置 | 全部保持 | ~uA级 | ~us级 |
| 待机(Standby) | 断电 | 断电 | 仅备份区 | ~nA级 | ~ms级 |
你看这个表,功耗越低,唤醒时间越长。这是个取舍。我个人习惯是:如果设备需要频繁响应,比如每秒唤醒一次,那就用停止模式。如果设备大部分时间都在“睡觉”,比如几分钟才上报一次数据,那就用待机模式。
2.2 睡眠模式:最浅的睡眠
睡眠模式其实就是把CPU内核时钟关了,但外设还在跑。比如你开了个定时器,定时器溢出时,CPU就醒了。
我在项目中遇到过一个问题:一个数据采集器,要求每100ms采集一次数据。我一开始用了睡眠模式,结果发现功耗还是偏高。为什么?因为虽然CPU睡了,但ADC、DMA、SPI这些外设都还在全速跑。说白了,睡眠模式适合那种“CPU没事干,但外设还在忙”的场景。
关键点:睡眠模式下,任何中断都可以唤醒CPU。所以你要确保只有你期望的中断源才能唤醒,其他中断要屏蔽掉。
// 进入睡眠模式示例(STM32)
HAL_SuspendTick(); // 暂停系统滴答定时器,避免频繁唤醒
__WFI(); // 等待中断指令,进入睡眠
// 醒来后继续执行
HAL_ResumeTick();
2.3 停止模式:深度睡眠,但保留现场
停止模式是我用得最多的。它把CPU内核和大部分外设的时钟都关了,只保留几个关键外设,比如RTC、外部中断、LPUART。这样功耗能降到微安级。
你想想看,一个传感器节点,每秒钟醒来一次,读个数据,发个报文,然后继续睡。停止模式就特别合适。唤醒时间也就几个微秒,几乎感觉不到延迟。
我的经验:进入停止模式前,一定要把不用的外设时钟关掉。我见过有人进了停止模式,功耗还有几百微安,查了半天,发现是GPIO没配置好,导致漏电流。嗯,细节决定成败。
// 进入停止模式示例(STM32)
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 系统时钟需要重新配置
SystemClock_Config();
2.4 待机模式:真正的“关机”
待机模式是最省电的,功耗可以做到纳安级。但代价也大:RAM里的数据全丢了,只有备份寄存器里的数据能保留。唤醒后,程序会从头开始执行,就像复位一样。
我记得有一次做一款户外温湿度记录仪,要求电池用一年。我算了一下,如果用停止模式,电池只能撑半年。后来改成待机模式,每10分钟唤醒一次,记录数据后继续睡。结果电池用了两年还没换。这就是待机模式的威力。
注意:待机模式唤醒后,程序是从main函数重新开始的。所以你要在初始化代码里判断一下,是上电复位还是待机唤醒复位。否则你的数据可能会被初始化掉。
// 判断复位源
if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET) {
// 待机唤醒复位,保留数据
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
} else {
// 上电复位,做完整初始化
}
2.5 唤醒源配置:谁叫醒你?
不同的低功耗模式,支持的唤醒源不一样。我整理了一个表格,方便你对照。
| 唤醒源 | 睡眠模式 | 停止模式 | 待机模式 |
|---|---|---|---|
| 任何中断 | ✓ | ✗ | ✗ |
| RTC闹钟 | ✓ | ✓ | ✓ |
| 外部中断(EXTI) | ✓ | ✓ | ✓ |
| LPUART | ✓ | ✓ | ✗ |
| WKUP引脚 | ✗ | ✗ | ✓ |
这里有个坑:外部中断作为唤醒源时,要注意电平保持时间。我曾经遇到一个项目,按键唤醒MCU,结果按键按下去,MCU醒了,但按键抖动又触发了多次中断。后来我在中断里加了去抖处理,问题才解决。
2.6 功耗测量方法:别靠猜,要实测
功耗设计好不好,不是算出来的,是测出来的。我建议你准备一个精密电流表,或者用示波器配合电流探头。测量时要注意几点:
- 去掉调试接口:调试器本身会消耗电流,影响测量结果。
- 测量平均功耗:用示波器抓一个完整的工作周期,计算平均电流。
- 注意瞬态电流:MCU唤醒瞬间会有大电流尖峰,别被这个吓到,关键是平均功耗。
实用技巧:我习惯在电源回路里串联一个10欧姆的采样电阻,用示波器测电阻两端的电压波形。这样既能看瞬态,又能算平均。比万用表直观多了。
2.7 避坑指南:我踩过的几个雷
做低功耗设计,有些坑是共通的。我分享几个我自己的经历,希望能帮你少走弯路。
- GPIO浮空:未使用的GPIO一定要配置成模拟输入或上拉/下拉输出。浮空的GPIO会引入漏电流,功耗直接翻倍。
- 外设时钟没关:进入低功耗前,记得把不用的外设时钟关了。尤其是ADC和定时器,它们即使不工作,时钟开着也会耗电。
- 唤醒后时钟配置:从停止模式唤醒后,系统时钟会恢复到默认值(通常是低速时钟)。记得重新配置时钟,否则程序跑得慢,功耗反而高。
- RTC校准:如果用了RTC唤醒,记得校准RTC。否则时间长了,唤醒周期会漂移,影响功耗。
好了,关于低功耗模式设计,今天就聊这么多。下一章我们会讲电源管理芯片的选择和外围电路设计,到时候再接着聊。