news 2025/12/19 19:04:45

【STM32】低功耗

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【STM32】低功耗

目录

  • 1 什么是低功耗?
  • 2 STM32电源系统结构
  • 3 低功耗模式介绍
    • 3.1 睡眠模式(sleep mode)
    • 3.2 停机模式(stop mode)
    • 3.3 待机模式(standby mode)
  • 4 寄存器及库函数介绍
  • 小实验:低功耗实验

1 什么是低功耗?

STM32的低功耗(low power mode)特性是其嵌入式处理器系列的一个重要优势,特别适用于需要长时间运行且功耗敏感的应用场景,如便携式设备、物联网设备、智能家居系统等。

在很多应用场合中都对电子设备的功耗要求非常苛刻,如某些传感器信息采集设备,仅靠小型的电池提供电源,要求工作长达数年之久,且期间不需要任何维护;由于智慧穿戴设备的小型化要求,电池体积不能太大导致容量也比较小,所以也很有必要从控制功耗入手,提高设备的续行时间。

2 STM32电源系统结构

3 低功耗模式介绍

STM32具有运行、睡眠、停止和待机四种工作模式。

上电后默认是在运行模式,当内核不需要继续运行时,可以选择后面三种低功耗模式。

3.1 睡眠模式(sleep mode)

在睡眠模式下,CPU停止工作,但所有外设(如ADC、通信接口等)仍然运行,时钟继续运转。这适用于需要暂时关闭CPU但外围设备需要继续工作的场景。

模式特点:

  • 对系统影响小,但是节能效果最差。
  • 在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。

进入条件:

  • 当系统控制寄存器中的SLEEPDEEP位被清除(通常为0),并且SLEEPONEXIT位根据需求设置时(如果设置为1,则在最低优先级中断处理程序退出时进入Sleep模式;如果为0,则执行WFI或WFE时立即进入)。
  • 执行WFI(Wait For Interrupt)或WFE(Wait For Event)指令来进入。

唤醒条件:

  • 任意一个中断都能将系统从Sleep模式唤醒。
  • 如果执行WFE指令进入Sleep模式,则一旦发生唤醒事件时,MCU将唤醒。

3.2 停机模式(stop mode)

在停机模式下,CPU和核心外围设备的时钟会停止,但部分唤醒源(如外部中断和某些定时器)仍然运行。这适用于需要长时间等待外部事件唤醒的应用,如等待用户输入或外部信号。Stop模式实现了非常低的功耗,同时保留了SRAM和寄存器的内容。

模式特点:

  • 节能效果好,程序不会复位。但恢复时间较长(比如震荡器需要重新起震等)。
  • 在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
  • 退出停止模式,HSI RC振荡器被选为系统时钟。

进入条件:

  • 需要将SLEEPDEEP位设置为1以进入深度睡眠模式,然后通过设置电源控制/状态寄存器(PWR_CSR)中的PDDS位为0来选择进入Stop模式。
  • 根据需求设置LPDS位(LPDS = 0:表示在深睡眠模式下,电压调节器保持开启状态;LPDS = 1:表示在深睡眠模式下,电压调节器进入低功耗模式)。
  • 执行WFI(Wait For Interrupt)或WFE(Wait For Event)指令来进入。
  • 在进入Stop模式之前,通常需要关闭不必要的外设时钟,并保存需要保留的状态信息。

唤醒条件:

  • Stop模式可以通过外部中断(如按键中断、USART接收中断等)唤醒。
  • RTC闹钟事件、USB唤醒、以太网(ETH)唤醒等也可以作为唤醒源,但这些通常需要通过外部中断来触发。

3.3 待机模式(standby mode)

在该模式下,CPU、外围设备和时钟都被关闭,只保留唤醒逻辑和备份寄存器。这适用于不需要保留RAM内容且可以从复位状态恢复的设备,常见于需要极低功耗且稀疏唤醒的应用。Standby模式是STM32中功耗最低的模式之一。

模式特点:

  • 节能效果最好,但程序会复位,只有少数条件唤醒。
  • 在Standby模式下,大部分IO引脚处于高阻态,只有复位引脚、TAMPER引脚(如果配置为防侵入或校准输出)和WKUP引脚可用作唤醒源。

进入条件:

  • Standby模式进入前,需要清除电源控制/状态寄存器(PWR_CSR)中的WUF位,以确保没有未处理的唤醒标志。
  • 将SLEEPDEEP位设置为1以进入深度睡眠模式,并设置PDDS位为1来选择进入Standby模式。
  • 执行WFI或WFE指令进入Standby模式。

唤醒条件:

  • Standby模式可以通过WKUP引脚的上升沿唤醒。
  • RTC闹钟事件也可以作为唤醒源。
  • 独立看门狗(IWDG)复位和NRST引脚上的外部复位也可以唤醒STM32,但这通常用于系统复位而非低功耗唤醒。

4 寄存器及库函数介绍

小实验:低功耗实验

实验目的

  1. 按下按键 2 ,进入低功耗模式(睡眠、停机、待机);
  2. 按下按键 1 ,退出低功耗模式;
  3. 正常模式下,LED1 闪烁;进入停机模式,LED2 长亮,退出停机模式则 LED2 熄灭。

硬件清单

  • STM32
  • ST-Link

完整代码

main.c

#include"sys.h"#include"uart1.h"#include"delay.h"#include"led.h"#include"uart1.h"#include"lpwr.h"#include"key.h"intmain(void){HAL_Init();/* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9);/* 设置时钟, 72Mhz *///LED初始化led_init();//串口1初始化uart1_init(115200);//低功耗初始化lpwr_init();printf("打印测试:hello world\r\n");uint8_ti=0;while(1){if(key_scan()==2){//进入睡眠模式//lpwr_enter_sleep();//进入停机模式//lpwr_enter_stop();//进入待机模式lpwr_enter_standby();}//200ms闪烁一次if(i%20==0){led1_toggle();}i++;delay_ms(10);}}

lpwr.c

#include"lpwr.h"#include"led.h"//低功耗初始化voidlpwr_init(void){GPIO_InitTypeDef gpio_initstruct;//使能GPIOB时钟__HAL_RCC_GPIOA_CLK_ENABLE();//调用GPIO初始化函数gpio_initstruct.Pin=GPIO_PIN_0;//WEKEUP对应引脚gpio_initstruct.Mode=GPIO_MODE_IT_RISING;//上升沿触发gpio_initstruct.Speed=GPIO_SPEED_FREQ_HIGH;//高速gpio_initstruct.Pull=GPIO_PULLDOWN;//下拉HAL_GPIO_Init(GPIOA,&gpio_initstruct);//设置中断优先级HAL_NVIC_SetPriority(EXTI0_IRQn,2,2);//使能中断HAL_NVIC_EnableIRQ(EXTI0_IRQn);}//中断服务函数voidEXTI0_IRQHandler(void){//公共处理函数HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);}//进入睡眠模式voidlpwr_enter_sleep(void){//关闭滴答定时器HAL_SuspendTick();//进入低功耗睡眠模式HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON,PWR_STOPENTRY_WFI);}//进入停机模式voidlpwr_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);/* 设置时钟, 72Mhz */}//进入待机模式voidlpwr_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();//不会运行到这里}

lpwr.h

#ifndef__LPWR_H__#define__LPWR_H__#include"sys.h"//低功耗初始化voidlpwr_init(void);//进入睡眠模式voidlpwr_enter_sleep(void);//进入停机模式voidlpwr_enter_stop(void);//进入待机模式voidlpwr_enter_standby(void);#endif

key.c

#include"key.h"#include"delay.h"//初始化GPIOvoidkey_init(void){GPIO_InitTypeDef gpio_initstruct;//使能GPIOA时钟__HAL_RCC_GPIOA_CLK_ENABLE();//调用GPIO初始化函数gpio_initstruct.Pin=GPIO_PIN_1;//KEY1,KEY2对应引脚gpio_initstruct.Mode=GPIO_MODE_INPUT;//输入gpio_initstruct.Pull=GPIO_PULLUP;//上拉gpio_initstruct.Speed=GPIO_SPEED_FREQ_HIGH;//高速HAL_GPIO_Init(GPIOA,&gpio_initstruct);}//按键扫描函数uint8_tkey_scan(void){//检测按键2是否按下if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)==GPIO_PIN_RESET){//消抖delay_ms(10);//再次判断按键是否按下if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)==GPIO_PIN_RESET){//如果确实按下,那么等待按键松开while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)==GPIO_PIN_RESET);//返回按键值return2;}}//返回默认值return0;}

key.h

#ifndef__KEY_H__#define__KEY_H__#include"sys.h"voidkey_init(void);uint8_tkey_scan(void);#endif

led.c

#include"led.h"#include"sys.h"//初始化GBIO口函数voidled_init(void){GPIO_InitTypeDef gpio_initstruct;//使能GPIOB时钟__HAL_RCC_GPIOB_CLK_ENABLE();//调用GPIO初始化函数gpio_initstruct.Pin=GPIO_PIN_8|GPIO_PIN_9;//LED1,LED2对应引脚gpio_initstruct.Mode=GPIO_MODE_OUTPUT_PP;//推挽输出gpio_initstruct.Speed=GPIO_SPEED_FREQ_HIGH;//高速gpio_initstruct.Pull=GPIO_PULLUP;//上拉HAL_GPIO_Init(GPIOB,&gpio_initstruct);//关闭LEDHAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);}//点亮LED1的函数voidled1_on(void){HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);//拉低LED1引脚,点亮LED1}//熄灭LED1的函数voidled1_off(void){HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);//拉高LED1引脚,熄灭LED1}//翻转LED1的函数voidled1_toggle(void){HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);//翻转LED1引脚电平}//点亮LED2的函数voidled2_on(void){HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);//拉低LED2引脚,点亮LED2}//熄灭LED2的函数voidled2_off(void){HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);//拉高LED2引脚,熄灭LED2}//翻转LED2的函数voidled2_toggle(void){HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);//翻转LED2引脚电平}

led.h

#ifndef__LED_H__#define__LED_H__//初始化GBIO口函数voidled_init(void);//点亮LED1的函数voidled1_on(void);//熄灭LED1的函数voidled1_off(void);//翻转LED1的函数voidled1_toggle(void);//点亮LED2的函数voidled2_on(void);//熄灭LED2的函数voidled2_off(void);//翻转LED2的函数voidled2_toggle(void);#endif
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/12 0:01:23

RPA 重塑 IT 运维:6 大核心场景解锁自动化新效能

在数字化时代,IT 运维是企业业务连续运转的 “生命线”,但服务器监控、数据备份、日志分析等重复性工作,长期占用 IT 人员大量精力,传统人工模式不仅效率低下,还易因疲劳操作引发系统故障或安全风险。RPA(R…

作者头像 李华
网站建设 2025/12/11 23:56:15

C++设计模式大乱斗:让代码不再“乱炖”(一)

文章目录1. 造人派(创建型)1.1 单例模式(Singleton):朕的江山只有一位!干啥用?核心奥义猫哥上代码猫哥点评1.2 工厂模式(Factory):对象量产流水线&#xff01…

作者头像 李华
网站建设 2025/12/11 23:52:48

【time-rs】time-core 中的 convert.rs 文件详解

概述 这个文件是 time-core crate 中的时间单位转换模块,采用编译时计算的零成本抽象设计。它定义了一系列时间单位类型(如纳秒、微秒等)和它们之间的转换关系。 1. 设计哲学 零成本抽象 编译时计算:所有转换系数在编译时确定无运…

作者头像 李华