3. 电源管理模式(上):Run模式、Sleep模式、Low-power Run模式的工作原理与进入/退出流程

各位同学,咱们今天聊聊STM32的电源管理。说实话,我刚接触这块时也觉得挺绕的——什么Run、Sleep、Stop、Standby,一堆模式看得眼花。但做低功耗项目多了,你会发现这些模式其实就是一套「省电工具箱」,关键是你得知道什么时候该用哪个工具。

这一章我们先讲前三个:Run模式、Sleep模式和Low-power Run模式。它们属于「浅度睡眠」范畴,退出快、逻辑简单,适合做低功耗入门的第一课。

Run / Sleep / Low-power Run 状态转换 Run 模式 HCLK = 最大频率 Sleep 模式 CPU 时钟停止 Low-power Run MSI 低速运行 WFI/WFE 中断/事件 降低电压+切换时钟 恢复电压+时钟 💡 关键区别 Sleep 模式 CPU 停但外设全开;Low-power Run 是降频降压运行,外设受限

3.1 Run模式——默认的「全速前进」

Run模式说白了就是STM32上电后的默认状态。CPU全速跑,所有外设想开就开,功耗嘛……自然也是最高的。我刚开始做项目时,经常写完代码发现电流几十毫安,一查——好家伙,根本没进任何低功耗模式,一直在Run模式里裸奔。

Run模式的特点:

  • CPU时钟全速运行(HCLK = 系统时钟)
  • 所有外设时钟可独立使能/禁能
  • 供电电压为VCORE(通常1.2V或1.8V,取决于型号)
  • 典型电流:几十μA/MHz(比如STM32L4系列约50μA/MHz)

关键认知:Run模式不是「不能省电」,而是「默认不省电」。你可以在Run模式下关闭不用的外设时钟、降低主频、使用门控时钟——这些操作不会改变模式名称,但能实实在在省下电流。

我个人习惯在项目初期先跑一遍所有外设,用电流表测一下Run模式的基线电流。这样后面做低功耗优化时,心里就有底了——知道省了多少,也知道极限在哪。

3.2 Sleep模式——CPU歇着,外设继续干

Sleep模式是STM32最轻量级的低功耗模式。它的核心逻辑很简单:CPU的时钟停了,但所有外设的时钟照常跑。

你想想看,如果你的程序只是在等一个串口数据、等一次ADC转换完成,CPU在那空转干嘛?不如让它睡一会儿,等外设完事了再叫醒它。

进入Sleep模式

有两种指令可以触发:

  • WFI(Wait For Interrupt):等中断来了才醒
  • WFE(Wait For Event):等事件来了就醒,不一定要中断
// 进入Sleep模式(WFI方式)
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);

// 或者直接用汇编
__WFI();

我的经验:大多数场景用WFI就够了。WFE适合那种需要快速响应外部事件、但又不想走完整中断服务函数的场合。我在一个传感器采集项目里用过WFE——GPIO电平变化直接唤醒,省掉了中断入栈出栈的开销,响应时间从3μs降到了1.2μs。

退出Sleep模式

退出方式也很直接:

  • 任何使能的中断触发 → WFI唤醒
  • 外部事件发生 → WFE唤醒
  • 唤醒后从WFI/WFE的下一条指令继续执行

这里有个坑:我曾经在项目里用Sleep模式做间歇性数据采集,结果发现每次唤醒后第一个数据总是错的。查了半天——原来是USART在Sleep模式下接收了数据,但CPU醒来时RXNE标志已经置位,我忘了清标志就直接读数据寄存器。嗯,从那以后我养成了习惯:唤醒后第一件事就是检查并清除外设中断标志。

对比项 WFI方式 WFE方式
唤醒源 使能的中断 事件(含中断事件)
唤醒延迟 几个CPU周期 几个CPU周期
典型场景 定时中断、外设中断 GPIO电平变化、DMA完成
功耗 相同 相同

3.3 Low-power Run模式——降速降压的「省电跑」

Low-power Run模式是我个人非常喜欢的一个模式。它不像Sleep那样让CPU完全停掉,而是让CPU继续跑,但跑得很慢、电压压得很低。

工作原理:

  • 内核电压从VCORE降到VLP(通常1.0V左右)
  • 系统时钟切换到MSI(多速内部振荡器),频率限制在2MHz以下
  • Flash访问受限(可能需要插入等待周期)
  • 部分外设不可用(如USB、高速ADC)

注意:进入Low-power Run模式前,必须先把系统时钟切换到MSI,并且确保所有外设的时钟源不依赖HSE/HSI/PLL。我见过有人直接调用进入函数,结果时钟源没切——芯片直接死在那,调试器都连不上。最后只能按复位键。

进入Low-power Run模式

步骤比Sleep复杂一些:

  1. 将系统时钟切换到MSI(频率≤2MHz)
  2. 配置电压调节器为低功耗模式
  3. 调用进入函数
// 进入Low-power Run模式的典型流程
void Enter_LowPowerRun(void)
{
    // 1. 切换到MSI时钟,2MHz
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
    
    // 2. 配置电压调节器为低功耗模式
    HAL_PWREx_EnableLowPowerRunMode();
    
    // 3. 此时已进入Low-power Run模式
    // CPU继续运行,但频率≤2MHz,电压降低
}

退出Low-power Run模式

退出流程是进入的逆操作:

  1. 调用函数退出低功耗电压模式
  2. 恢复系统时钟到目标频率
  3. 恢复外设时钟配置
// 退出Low-power Run模式
void Exit_LowPowerRun(void)
{
    // 1. 退出低功耗电压模式
    HAL_PWREx_DisableLowPowerRunMode();
    
    // 2. 恢复时钟(例如恢复到16MHz HSI)
    // 重新配置PLL、HSE等
}

避坑指南:我曾经在一个电池供电的温湿度记录仪里用了Low-power Run模式。理想很丰满——CPU以2MHz跑,电流从5mA降到了800μA。但实际测试发现,每次退出Low-power Run模式时,电压恢复需要大约5μs,这期间如果外设有操作,数据会出错。解决方案是:退出后先等10μs,再操作外设。嗯,有时候「等一等」反而是最快的。

3.4 三种模式的选型建议

说了这么多,到底什么时候用哪个?我整理了一个简单的判断逻辑:

  • CPU需要持续处理数据 → Run模式(降频+关外设时钟)
  • CPU大部分时间在等外设 → Sleep模式(WFI/WFE)
  • CPU需要持续运行,但可以接受低速 → Low-power Run模式

举个例子:一个I2C温度传感器,每秒采集一次。采集耗时2ms,剩下998ms在等定时器。这种场景Sleep模式最合适——CPU睡998ms,醒来2ms干活,平均电流能降两个数量级。

而如果你在做数据记录,需要每秒处理100笔数据,每笔处理耗时5μs——总耗时才500μs,剩下999.5ms空闲。但问题是,你不能让CPU睡,因为数据随时可能来。这时候Low-power Run模式就派上用场了:CPU以2MHz跑,处理时间变成50μs,但空闲时电流只有Run模式的1/5。