第3章 低功耗模式详解:STM32H7的多种低功耗模式与电压调节
低功耗设计,说白了就是让芯片在“该歇的时候歇着”。STM32H7 作为双核高性能 MCU,功耗管理比单核复杂得多。我刚开始接触 H7 时,以为低功耗就是调个 Sleep 模式完事,结果项目做出来电池续航差得离谱。后来才明白——你得把电压调节、频率缩放、唤醒延迟这些全盘考虑进去。
这一章,咱们把 H7 的几种低功耗模式掰开揉碎讲清楚。
3.1 四种核心低功耗模式
STM32H7 提供了四种主要运行模式:Run、Sleep、Stop、Standby。它们不是简单的“省电程度递增”,而是各有各的适用场景。
| 模式 | CPU 状态 | 外设状态 | 唤醒源 | 典型唤醒时间 |
|---|---|---|---|---|
| Run | 全速运行 | 全部可用 | — | — |
| Sleep | 暂停(WFI/WFE) | 全部可用 | 任意中断/事件 | ~5 个 CPU 周期 |
| Stop | 断电 | 可选保持 | RTC、EXTI、LPUART 等 | ~10-50 µs |
| Standby | 完全断电 | 仅 RTC、备份域 | WKUP 引脚、RTC 闹钟 | ~100-200 µs |
关键点:Stop 模式是 H7 低功耗设计的“主力战场”。它能在 µs 级唤醒的同时,把功耗压到几十 µA。我大部分项目最终都落在 Stop 模式上。
3.2 电压调节与频率缩放(Voltage Scaling)
H7 内部集成了一个可编程电压调节器(LDO 或 SMPS),支持三种电压等级:VOS0、VOS1、VOS3。电压越高,CPU 能跑的频率越高,但漏电流也越大。
| VOS 等级 | 典型电压 | CPU 最高频率 | 典型功耗(@25°C) |
|---|---|---|---|
| VOS0 | 1.35V | 550 MHz | ~150 mW |
| VOS1 | 1.25V | 480 MHz | ~100 mW |
| VOS3 | 1.05V | 200 MHz | ~40 mW |
你想想看,如果只是跑个传感器采集,根本不需要 550 MHz。把 VOS 降到 VOS3,功耗直接砍掉三分之二。我在一个手持设备项目里,就是靠动态切换 VOS 等级,把平均功耗从 80 mW 降到了 25 mW。
我的习惯:在系统空闲时切到 VOS3 + 低频,有计算任务时再升到 VOS1。切换 VOS 需要等待调节器稳定,大约 5-10 µs,这个时间要算进你的实时性预算里。
3.3 频率缩放(Clock Gating 与 Divider)
频率缩放不是简单的“降频”。H7 的时钟树支持对每个域独立分频:CPU 域、AXI 域、AHB 域、APB 域。你可以让 CPU 跑 200 MHz,但 AXI 总线只跑 100 MHz,外设只跑 50 MHz。
// 示例:动态降频到 200 MHz,VOS3
void enter_low_freq_mode(void)
{
// 1. 切换到 HSI 时钟,避免 PLL 抖动
RCC->CFGR |= RCC_CFGR_SW_HSI;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI);
// 2. 关闭 PLL
RCC->CR &= ~RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) != 0);
// 3. 设置 VOS3
PWR->CR3 = (PWR->CR3 & ~PWR_CR3_VOS) | PWR_CR3_VOS_3;
while ((PWR->CSR1 & PWR_CSR1_VOSRDY) == 0);
// 4. 降低 AHB/APB 分频
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_HPRE) | RCC_CFGR_HPRE_DIV4;
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_PPRE1) | RCC_CFGR_PPRE1_DIV2;
}
我曾经踩过的坑:降频前没检查外设是否正在传输数据。有一次在 SPI DMA 传输中直接改了 AHB 分频,结果总线时钟不同步,DMA 传了一半的数据全乱了。记住:改时钟前先停掉所有正在使用该时钟的外设。
3.4 Stop 模式深入:三种子模式
H7 的 Stop 模式不是单一的。它有三种子模式,区别在于 SRAM 和寄存器的保持策略:
- Stop0:全部 SRAM 保持,唤醒最快(~10 µs),功耗 ~200 µA
- Stop1:仅保留 64 KB SRAM,唤醒稍慢(~30 µs),功耗 ~50 µA
- Stop2:仅保留备份域 SRAM,唤醒最慢(~50 µs),功耗 ~10 µA
怎么选?如果你的应用需要快速响应外部事件(比如按键中断),用 Stop0。如果只是定时采集数据,用 Stop2 更省电。我在一个温湿度记录仪项目里,用 Stop2 模式,两节 AA 电池撑了 8 个月。
3.5 Standby 模式:真正的“关机”
Standby 模式下,CPU 和大部分外设都断电了,只有 RTC 和备份域还在工作。唤醒后芯片会从头执行(类似复位),但备份域的数据还在。
// 进入 Standby 模式
void enter_standby(void)
{
// 1. 清除唤醒标志
PWR->CSR1 |= PWR_CSR1_CWUF;
// 2. 设置唤醒引脚(PA0)
PWR->CSR1 |= PWR_CSR1_EWUP1;
// 3. 进入 Standby
PWR->CR1 |= PWR_CR1_LPDS;
PWR->CR1 |= PWR_CR1_PDDS;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
__WFI();
}
注意:Standby 唤醒后,系统时钟默认是 HSI(64 MHz)。如果你需要高频运行,记得在 main 函数开头重新配置 PLL。我习惯在唤醒后先检查复位原因,如果是 Standby 唤醒,就跳过一些初始化步骤,直接进入工作循环。
3.6 知识体系:低功耗模式选择流程
下面这张图是我自己总结的,每次做低功耗设计都会参考它:
3.7 实战建议:如何选择低功耗模式
我个人的经验是:不要一开始就追求最低功耗。先让你的系统跑起来,用电流表测出各个模式的基线功耗,再逐步优化。
- 先确定唤醒延迟要求:如果应用需要 µs 级响应,只能选 Stop0 或 Sleep。
- 再考虑数据保持需求:如果需要在唤醒后恢复现场,至少用 Stop1。如果可以从头开始,用 Standby 最省电。
- 最后调电压和频率:在满足性能的前提下,尽量用 VOS3 + 低频。我见过很多开发者一上来就开最高频率,其实 90% 的时间 CPU 都在空转。
避坑指南:我曾经在一个项目里,用 Stop2 模式配合 RTC 闹钟唤醒,结果发现每次唤醒后 RTC 的计数都跳了几秒。查了半天,原来是 Stop2 模式下 RTC 的时钟源被切断了。记住:进入低功耗模式前,确认所有关键外设的时钟源是否还能正常工作。