掌握STM32低功耗开发!HAL库实战指南,让你的项目续航翻倍
STM32系列提供了三种主要低功耗模式,满足不同场景的能耗需求:上电后默认是在运行模式,当内核不需要继续运行时,可以选择后面三种低功耗模式。
深入STM32低功耗开发:HAL库实战指南
一、STM32低功耗模式概览
1. 什么是低功耗
STM32的低功耗(low power mode)特性是其嵌入式处理器系列的一个重要优势,特别适用于需要长时间运行且功耗敏感的应用场景,如便携式设备、物联网设备、智能家居系统等。
在很多应用场合中都对电子设备的功耗要求非常苛刻,如某些传感器信息采集设备,仅靠小型的电池提供电源,要求工作长达数年之久,且期间不需要任何维护;由于智慧穿戴设备的小型化要求,电池体积不能太大导致容量也比较小,所以也很有必要从控制功耗入手,提高设备的续行时间。
2. STM32电源系统结构

3. 低功耗模式介绍
STM32系列提供了三种主要低功耗模式,满足不同场景的能耗需求:
上电后默认是在运行模式,当内核不需要继续运行时,可以选择后面三种低功耗模式。
3.1. Sleep Mode(睡眠模式)
特点:
- 仅关闭CPU时钟,外设保持运行
- 唤醒后程序立即继续执行(无需复位)
- 功耗:约1-3 mA(与主频相关)
唤醒方式:
- 任意中断(GPIO、定时器、通信接口等)
适用场景:
- 短暂空闲(如等待传感器数据的间歇期)
- 实时性要求高的场景(如电机控制中的停顿间隙)
- 需快速唤醒(<10 μs)的低功耗需求
3.2. Stop Mode(停止模式)
特点:
- 关闭主电压调节器,冻结所有时钟(HCLK/PCLK)
- SRAM和寄存器数据保留
- 功耗:约10-50 μA
唤醒方式:
- 外部中断(EXTI)、RTC闹钟、低功耗定时器
适用场景:
- 中等功耗要求的长期待机(如智能手表的夜间模式)
- 需要保存运行状态的低功耗场景(如工业设备的休眠待机)
- 唤醒时间要求中等(100-200 μs)
3.3. Standby Mode(待机模式)
特点:
- 关闭整个电源域(仅备份域维持)
- 丢失SRAM和寄存器数据(需通过备份寄存器保存关键数据)
- 功耗:约1-5 μA
唤醒方式:
- 外部复位(NRST)、特定唤醒引脚(WKUP)、RTC闹钟
适用场景:
- 超低功耗长期休眠(如电池供电的远程传感器)
- 无需保留运行状态的场景(如一次性触发设备)
- 可接受较长唤醒时间(1-10 ms)
4. 模式选择决策树
下表列出的唤醒时间是在一个8MHz的HSI RC振荡器的唤醒阶段测量得到。唤醒时使用的时钟源依当前的操作模式而定:
![![功耗对比图]](https://i-blog.csdnimg.cn/direct/7adb28473bc64dfcb26340586e3a6cb0.png)
-
是否需要保留程序运行状态?
- 是 → Stop Mode
- 否 → 进入第2步
-
对功耗要求是否苛刻?
- 是(μA级)→ Standby Mode
- 否(mA级)→ Sleep Mode
典型应用示例:
- 温湿度传感器(每小时采集1次) → Standby Mode + RTC唤醒
- 无线遥控器(按键唤醒) → Stop Mode + EXTI中断
- 实时数据监控(间歇工作) → Sleep Mode + 定时器唤醒
通过合理选择模式,可平衡功耗与性能,典型场景可降低90%以上的能耗。
二、关键寄存器解析

该图取自"良许嵌入式"
由此图,我们可以了解到低功耗模式下,主要我们需要了解的寄存器如下:
1. 电源控制寄存器 (PWR_CR)

在该寄存器中,我们主要关注两位,一位PDDS、一位LPDS。
PDDS( 位 1 ):掉电深睡眠
与LPDS位协同操作
0:当CPU进入深睡眠时进入停机模式,调压器的状态由LPDS位控制。
1:CPU进入深睡眠时进入待机模式。
LPDS(位 0):深睡眠下的低功耗:
PDDS=0时,与PDDS位协同操作
0:在停机模式下电压调压器开启
1:在停机模式下电压调压器处于低功耗模式
2. 电源控制状态寄存器 (PWR_CSR)

在该寄存器下,我们主要看EWUP和WUF两位、
EWUP(位 8):使能WKUP引脚
0:WKUP引脚为通用I/O。WKUP引脚上的事件不能将CPU从待机模式唤醒
1:WKUP引脚用于将CPU从待机模式唤醒,WKUP引脚被强置为输入下拉的配置(WKUP引脚
上的上升沿将系统从待机模式唤醒)
注:在系统复位时清除这一位。
WUF(位 0):唤醒标志
该位由硬件设置,并只能由POR/PDR(上电/掉电复位)或设置电源控制寄存器(PWR_CR)的
CWUF位清除。
0:没有发生唤醒事件
1:在WKUP引脚上发生唤醒事件或出现RTC闹钟事件。
注:当WKUP引脚已经是高电平时,在(通过设置EWUP位)使能WKUP引脚时,会检测到一个额外的
事件。
3. 系统控制寄存器 (SCB_SCR)

主要关注的位是SLEEPDEEP和SLEEPONEXIT两位。
SLEEPDEEP(位2 )
控制处理器是否使用睡眠或者深度睡眠来使用低功耗模式
0: 睡眠模式
1: 深度睡眠模式(停机、待机)
SLEEPONEXIT( 位1)
配置在从处理程序模式(Handler mode)返回到线程模式(Thread mode)时启用退出即休眠(Sleep-on-Exit)功能。将此位设置为1,可使中断驱动型应用程序避免返回到空的主程序循环中。
0:立即睡眠
1:等待中断退出再睡眠
三、HAL库关键函数
// 进入睡眠模式
void HAL_PWR_EnterSLEEPMode(uint32_t Regulator, uint8_t SLEEPEntry);
// 进入停止模式
void HAL_PWR_EnterSTOPMode(uint32_t Regulator, uint8_t STOPEntry);
// 进入待机模式
void HAL_PWR_EnterSTANDBYMode(void);
// 启用唤醒引脚
void HAL_PWR_EnableWakeUpPin(uint32_t WakeUpPinPolarity);
// 使能时钟电源(宏函数)
__HAL_RCC_PWR_CLK_ENABLE();
四、低功耗实验
实验目的
- 按下按键 2 ,进入低功耗模式(睡眠、停机、待机);
- 按下按键 1 ,退出低功耗模式;
- 正常模式下,LED1 闪烁;进入停机模式,LED2 长亮,退出停机模式则 LED2 熄灭。
部分关键代码
1. 初始化函数
唤醒中断初始化
void lpwr_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
//打开时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOB时钟
//调用GPIO初始化函数
gpio_initstruct.Pin = GPIO_PIN_0; //
gpio_initstruct.Mode = GPIO_MODE_IT_RISING; // 上升沿触发
gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
HAL_GPIO_Init(GPIOA, &gpio_initstruct);
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 2);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
2. 进入低功耗示例
睡眠模式
void lpwr_enter_sleep(void)
{
HAL_SuspendTick();
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
}
停止模式
void lpwr_enter_stop(void)
{
//暂停滴答定时器
HAL_SuspendTick();
//点亮LED2,代表进入停机模式
led2_on();
//进入停机模式
HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
//熄灭LED2,代表退出停机模式
led2_off();
//从停机模式唤醒,需要重新配置系统时钟
stm32_clock_init(RCC_PLL_MUL9);
}
待机模式
void lpwr_enter_standby(void)
{
//使能电源时钟(关闭电压调节器)
__HAL_RCC_PWR_CLK_ENABLE();
//使能WAKEUP引脚的唤醒功能
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
//清除唤醒标记,否则将持续保持唤醒状态
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
//进入待机模式
HAL_PWR_EnterSTANDBYMode();
//测试:看看代码会不会运行到下面?
led2_on();
}
3. 主程序代码
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "lpwr.h"
#include "key.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init(); /* 初始化LED灯 */
uart1_init(115200);
lpwr_init();
key_init();
printf("hello world!\r\n");
uint8_t i = 0;
while(1)
{
if(key_scan() == 2)
{
//lpwr_enter_sleep();
//lpwr_enter_stop();
lpwr_enter_standby();
}
if((i % 20) == 0)
led1_toggle();
i++;
delay_ms(10);
}
}
五、实验现象

我们可以使用Proteus进行仿真实验,在实验中,我们会看到上电后,LED1在不断的闪,当我们按下KEY1,KED1保持睡眠前状态,停止闪烁。
当我们按下KEY2,触发WKUP上升沿中断,进行唤醒。观察到实验现象,LED1恢复闪烁。
并且我们能够观察到,当进行睡眠、停止模式时,程序会继续从休眠处运行的程序继续往下运行。
但是按所学的来说,在待机状态下,程序会触发复位,从main函数中进行运行。在Proteus仿真中,并没有成功实现,而在现实中使用硬件成功实现。我想知道,这是Proteus中的Bug还是我的Proteus本身就有错误。希望各位在留言区对我答疑解惑,非常感谢。
六、优化建议
-
时钟管理
- 进入低功耗前关闭不必要的外设时钟
- 使用
__HAL_RCC_GPIOx_CLK_DISABLE()优化GPIO功耗
-
IO配置
- 将未使用的GPIO设置为模拟模式
- 避免浮空输入状态
- 禁用调试接口:
__HAL_DBGMCU_FREEZE_TIMx()
-
电压调节
- 根据频率调整电压调节器模式:
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE3);
七、常见问题
-
唤醒失败检查
- 确认WKUP引脚已正确配置
- 检查PWR_CSR寄存器标志位
- 验证NVIC优先级配置
-
电流异常排查
- 使用GPIO状态分析仪检查引脚泄漏
- 检查SWD接口是否禁用
- 验证电压调节器模式设置
注意:使用待机模式前务必保存关键数据到备份寄存器(RTC_BKPxR),待机模式会丢失SRAM内容。
通过本文介绍的方法,希望大家可以灵活控制STM32的功耗状态,在保持HAL库易用性的同时实现精确的功耗管理。建议结合具体型号的参考手册调整参数,并通过电流表实际测量优化效果。
微信交流群:
更多推荐



所有评论(0)