3. 开发环境搭建

低功耗设计,说白了就是让芯片在“该歇的时候歇着”。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)
VOS01.35V550 MHz~150 mW
VOS11.25V480 MHz~100 mW
VOS31.05V200 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 知识体系:低功耗模式选择流程

下面这张图是我自己总结的,每次做低功耗设计都会参考它:

STM32H7 低功耗模式选择流程 系统空闲 需要 < 10 µs 唤醒? 是 → Stop0 模式 需要保持 SRAM? 是 → Stop1 模式 否 → Standby 模式 提示:VOS 等级和频率缩放可在任何模式下动态调整,不限于空闲状态

3.7 实战建议:如何选择低功耗模式

我个人的经验是:不要一开始就追求最低功耗。先让你的系统跑起来,用电流表测出各个模式的基线功耗,再逐步优化。

  1. 先确定唤醒延迟要求:如果应用需要 µs 级响应,只能选 Stop0 或 Sleep。
  2. 再考虑数据保持需求:如果需要在唤醒后恢复现场,至少用 Stop1。如果可以从头开始,用 Standby 最省电。
  3. 最后调电压和频率:在满足性能的前提下,尽量用 VOS3 + 低频。我见过很多开发者一上来就开最高频率,其实 90% 的时间 CPU 都在空转。

避坑指南:我曾经在一个项目里,用 Stop2 模式配合 RTC 闹钟唤醒,结果发现每次唤醒后 RTC 的计数都跳了几秒。查了半天,原来是 Stop2 模式下 RTC 的时钟源被切断了。记住:进入低功耗模式前,确认所有关键外设的时钟源是否还能正常工作。