深入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振荡器的唤醒阶段测量得到。唤醒时使用的时钟源依当前的操作模式而定:

![功耗对比图]

  1. 是否需要保留程序运行状态?

    • Stop Mode
    • → 进入第2步
  2. 对功耗要求是否苛刻?

    • (μA级)→ Standby Mode
    • (mA级)→ Sleep Mode

典型应用示例

  • 温湿度传感器(每小时采集1次) → Standby Mode + RTC唤醒
  • 无线遥控器(按键唤醒) → Stop Mode + EXTI中断
  • 实时数据监控(间歇工作) → Sleep Mode + 定时器唤醒

通过合理选择模式,可平衡功耗与性能,典型场景可降低90%以上的能耗。


二、关键寄存器解析

在123123述
该图取自"良许嵌入式"
由此图,我们可以了解到低功耗模式下,主要我们需要了解的寄存器如下:

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();

四、低功耗实验

实验目的

  1. 按下按键 2 ,进入低功耗模式(睡眠、停机、待机);
  2. 按下按键 1 ,退出低功耗模式;
  3. 正常模式下,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本身就有错误。希望各位在留言区对我答疑解惑,非常感谢。

六、优化建议

  1. 时钟管理

    • 进入低功耗前关闭不必要的外设时钟
    • 使用__HAL_RCC_GPIOx_CLK_DISABLE()优化GPIO功耗
  2. IO配置

    • 将未使用的GPIO设置为模拟模式
    • 避免浮空输入状态
    • 禁用调试接口:__HAL_DBGMCU_FREEZE_TIMx()
  3. 电压调节

    • 根据频率调整电压调节器模式:
    HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE3);
    

七、常见问题

  1. 唤醒失败检查

    • 确认WKUP引脚已正确配置
    • 检查PWR_CSR寄存器标志位
    • 验证NVIC优先级配置
  2. 电流异常排查

    • 使用GPIO状态分析仪检查引脚泄漏
    • 检查SWD接口是否禁用
    • 验证电压调节器模式设置

注意:使用待机模式前务必保存关键数据到备份寄存器(RTC_BKPxR),待机模式会丢失SRAM内容。


通过本文介绍的方法,希望大家可以灵活控制STM32的功耗状态,在保持HAL库易用性的同时实现精确的功耗管理。建议结合具体型号的参考手册调整参数,并通过电流表实际测量优化效果。

微信交流群:
在这里插入图片描述

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐