## 一、为什么需要区分三种低功耗模式? STM32 的低功耗设计并非简单的“关外设”,而是从内核、时钟树、电源域三个层次逐级降低能耗。睡眠模式只关闭 CPU 时钟,外设仍可工作;停止模式进一步关闭所有时钟,但保留 SRAM 和寄存器内容;待机模式则几乎切断全部电源,仅保留备份域和唤醒电路。理解这三者的区别,才能根据应用场景选择最合适的策略。 - 睡眠模式:CPU 停止,外设时钟仍运行,唤醒延迟最小(~5µs)。 - 停止模式:所有时钟停止,但 1.2V 域(SRAM、寄存器)保持供电,唤醒延迟约 30µs。 - 待机模式:1.2V 域断电,SRAM 内容丢失,仅备份域与 RTC 可选保持,唤醒延迟约 5ms(需复位或唤醒引脚)。 ## 二、深入原理:电压调节器与时钟门控 STM32 内部有主电压调节器(MR)和低电压调节器(LVR)。在停止模式下,如果关闭 MR 而使用 LVR,则称为“停止模式(低功耗)”,可进一步节省电流,但唤醒时间会变长。待机模式则直接断开 MR 和 LVR 的电源路径,因此所有非备份寄存器都会清零。 时钟源的选择也直接影响功耗。在停止模式下,如果 RTC 使用 LSE 振荡器,仍需供电,因此唤醒功耗会略高。建议在进入停止模式前,将不需要的外设时钟关闭,并将 GPIO 设置为模拟输入或高阻态,避免浮空电平导致漏电。 ## 三、配置步骤与代码实现(基于 HAL 库) 首先,我们使用 STM32CubeMX 生成基础工程。配置时需注意:使能 PWR 时钟(__HAL_RCC_PWR_CLK_ENABLE()),并将需要唤醒的中断源(如 RTC、外部中断)配置好。以下代码演示三种模式的进入和唤醒方法。 ### 1. 睡眠模式:等待中断唤醒 ```c #include "stm32l4xx_hal.h" void Enter_Sleep_Mode(void) { // 关闭不必要的 GPIO 时钟,降低漏电 __HAL_RCC_GPIOB_CLK_DISABLE(); // 使能 Sleep 模式(仅内核停止) HAL_SuspendTick(); // 可选:暂停 SysTick 以减少中断干扰 HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); // 唤醒后恢复 SysTick HAL_ResumeTick(); } ``` ### 2. 停止模式:支持任何 EXTI 或 RTC 唤醒 ```c void Enter_Stop_Mode(void) { // 停止模式下,内部电压调节器可切换为低功耗模式 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // 唤醒后需重新配置系统时钟(因为所有时钟均已关闭) SystemClock_Config(); // 请根据实际工程实现该函数 } ``` 注意:在停止模式中,若需要保留 RTC 闹钟唤醒,则必须在进入前确保 LSE 开启,并配置 RTC 中断。 ### 3. 待机模式:只能通过 WKUP 引脚或 RTC 唤醒 ```c void Enter_Standby_Mode(void) { // 清除待机标志,否则可能导致无法正常唤醒 __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB); // 使能待机模式(注意:一旦进入,SRAM 内容将丢失) HAL_PWR_EnterSTANDBYMode(); // 以下代码不会被执行,除非复位或唤醒引脚触发 while (1); } ``` 若使用 PA0(WKUP1)唤醒,需提前配置该引脚为外部中断模式,并允许待机模式唤醒。例如: ```c void WKUP_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI0_IRQn); } ``` ## 四、实测电流与唤醒延迟对比(以 STM32L071 为例) 即使在同一个型号上,配置不同也会导致差异。以下为典型值(供电 3.3V): | 模式 | 典型电流 | 唤醒时间 | 唤醒源 | |------|----------|----------|--------| | 睡眠 | 4.2 mA | 5 µs | 任意中断 | | 停止 | 1.3 µA | 30 µs | EXTI、RTC | | 待机 | 0.3 µA | 5 ms | WKUP、RTC | 如需更低功耗,可关闭内部 LDO 稳压器,使用外部 SMPS 供电,但这是高级设计层面,超出本文范围。 ## 五、注意事项与常见坑 - 进入停止或待机前,务必将所有 GPIO 配置为确定的电平(上拉/下拉或模拟),避免浮空产生额外漏电。 - 若使用外部中断唤醒,必须确保该中断在睡眠前已被正确使能,并且中断优先级不会被屏蔽。 - 待机模式会复位所有 I/O 和寄存器(备份域除外),所以不能用它来保存动态数据。如果需要保存少量数据,可放在 RTC 备份寄存器中。 - 在停止模式唤醒后,系统时钟源仍然为初始值(通常是 MSI),必须重新调用 SystemClock_Config() 才能恢复高速运行,否则 USB、UART 波特率会异常。 - 使用 HAL_PWR_EnterSTOPMode 时,如果选择 PWR_STOPENTRY_WFI,则如果中断挂起,可能立即返回,不会真正进入停止。此时应确保无未处理的中断,或使用 WFE。 - 调试器(SWD)在低功耗模式下会失效,建议在调试时禁用看门狗,或使用独立供电测试功耗。 ## 六、实际应用建议 - 对于需要频繁唤醒(如按键扫描)的场景,使用睡眠模式,兼顾响应速度与功耗。 - 对于传感器采集类应用(周期长、数据量小),优先选择停止模式,并配合 RTC 定时唤醒,可在 1 µA 级别运行。 - 待机模式适合冷启动式设备,如智能门锁、遥控器,唤醒后需重新初始化所有外设和变量。 总之,没有绝对最优的低功耗方案,只有最适合当前项目的模式组合。建议在开发板上用万用表实测各模式下的电流,并针对性地优化每一路 GPIO 和时钟。