#13. PWR 低功耗模式.

STM32 低功耗模式.

PWR(Power Control)电源控制

  • PWR负责管理STM32内部的电源供电部分,可以实现可编程电压监测器和低功耗模式的功能
  • 可编程电压监测器(PVD)可以监控VDD电源电压,当VDD下降到PVD阀值以下或上升到PVD阀值之上时,PVD会触发中断,用于执行紧急关闭任务
  • 低功耗模式包括睡眠模式(Sleep)/停机模式(Stop)和待机模式(Standby),
    可在系统空闲时,降低STM32的功耗,延长设备使用时间.

常见唤醒电路:
串口接收数据的中断唤醒,外部中断唤醒, RTC闹钟唤醒 等.

Demo2: 睡眠模式 + 串口发送接收.

睡眠模式关键代码: __WFI()
执行完这句,芯片进行睡眠, 收到数据后,自动退出睡眠模式,
执行一遍任务后,继续睡眠.
在空闲时,芯片一直在睡眠, 可以降低系统功耗.

Demo3: 停止模式+ 对射红外传感器.

PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFI);
SystemInit();

Demo4: 待机模式+实时时钟.

`PWR_EnterSTANDBYMode();`

2. 整体介绍

睡眠模式: 一般省电 mA级别.
WFI(Wait For Interrupt) 等待中断, 任一中断可唤醒.
任何外设发生任何中断事,芯片都会立刻醒来.
WFE(Wait For Event)等待事件, 唤醒事件可唤醒.
可以不需要进入中断函数,直接从睡眠的地方继续运行.

停机模式: 非常省电 微安级别.
PDDS=0; LPDS: 0开启电压调节器,1进入低功耗; SLEEPDEEP位 1 深度睡眠.
再调用WFI或 WFE 就进入停机模式了.
任一外部中断 可唤醒.

待机模式: 极其省电. 微安级别.
SLEEPDEEP位 1 ; PDDS置1;WFI或 WFE.
唤醒: WakeUp引脚的上升沿,RTC闹钟事件,NRST引脚的外部复位,IWDG复位.
能关闭的电路都关闭了.

执行WFI 或 WFE 指令后,STM32立即进入低功耗模式,所以其他参数要在他前面配置好.

2.1 睡眠模式总结:

执行完WFI/WFE指令后,STM32进入睡眠模式,程序暂停运行,唤醒后程序从暂停的地方继续运行;
SLEEPONEXIT位决定STM32执行完WFI或WFE后,是立刻进入睡眠, 还是等STM32从最低优先级的中断处理程序中退出时进入睡眠;
在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态;
WFI指令进入睡眠模式,可被任意一个NVIC响应的中断唤醒;
WFE指令进入睡眠模式,可被唤醒事件唤醒.

2.2 停止模式

执行完WFI/WFE指令后,STM32进入停止模式,程序暂停运行,唤醒后程序从暂停的地方继续运行;
1.8V供电区域的所有时钟都被停止,PLL、HSI和HSE被禁止,SRAM和寄存器内容被保留下来;
在停止模式下,所有的I/0引脚都保持它们在运行模式时的状态;
当一个中断或唤醒事件导致退出停止模式时,[HSI]被选为系统时钟-8MHz;
当电压调节器处于低功耗模式下,系统从停止模式退出时,会有一段额外的启动延时;
WFI指令进入停止模式,可被任意一个EXTI中断唤醒;
WFE指令进入停止模式,可被任意一个EXTI事件唤醒;

2.3 待机模式

执行完WFI/WFE指令后,STM32进入待机模式,唤醒后程序从头开始运行;
整个1.8V供电区域被断电,PLL、HSI和HSE也被断电,SRAM和寄存器内容丢失,只有备份的寄存器和待机电路维持供电;
在待机模式下,所有的1/0引脚变为高阻态(浮空输入);
WKUP引脚的上升沿、RTC闹钟事件的上升沿、NRST引脚上外部复位、IWDG复位 退出待机模式;


3.工程代码.

3.1 修改主频率,以降低功耗.

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"

int main(void)
{
    OLED_Init();                            //OLED初始化
    
    OLED_ShowString(1, 1, "SYSCLK:");       //显示静态字符串
    OLED_ShowNum(1, 8, SystemCoreClock, 8); //显示SystemCoreClock变量
                                            //SystemCoreClock的值表示当前的系统主频频率
    
    while (1)
    {
        OLED_ShowString(2, 1, "Running");   //闪烁Running,指示当前主循环运行的快慢
        Delay_ms(500);
        OLED_ShowString(2, 1, "       ");
        Delay_ms(500);
    }
}
主频率在system_stm32f10x.c 中修改 宏定义.
72MHz时, 闪烁周期是1秒.
36Mhz时, 闪烁周期是2秒. 主频降低了一半.

3.2 睡眠模式+ 串口收发.

没事的时候,低功耗; 有中断来了, 就醒来干活.
推荐使用WFI, 使用中断唤醒.

停机模式下,1.8V区域的时钟都关闭了,cpu+外设都不能运行.
自然 USART 也接收不到数据,产生不了中断了.
而且,USART的中断,也不能唤醒 停止模式, 所以只能用睡眠模式.

USART 收到数据,产生中断(执行中断函数),唤醒CPU工作. 之后执行主循环.

uint8_t RxData;         //定义用于接收串口数据的变量

int main(void)
{
    OLED_Init();        //OLED初始化
    OLED_ShowString(1, 1, "RxData:");   //显示静态字符串
    Serial_Init();      //串口初始化
    
    while (1)
    {   //----程序主题功能
        if (Serial_GetRxFlag() == 1)            //检查串口接收数据的标志位
        {
            RxData = Serial_GetRxData();        //获取串口接收的数据
            Serial_SendByte(RxData);            //串口将收到的数据回传回去,用于测试
            OLED_ShowHexNum(1, 8, RxData, 2);   //显示串口接收的数据
        }
        //闪烁一次.
        OLED_ShowString(2, 1, "Running");       //OLED闪烁Running,指示当前主循环正在运行
        Delay_ms(100);
        OLED_ShowString(2, 1, "       ");
        Delay_ms(100);
        //----程序主题功能
        
        __WFI();    //执行WFI指令,CPU立刻睡眠模式,并等待中断唤醒(推荐)
    }
}
// 

3.3 停止stop模式,+对射式红外常感器计次. 外部中断

空闲时进入低功耗, 使用外部中断触发唤醒.
外部中断,不需要时钟.

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"

int main(void)
{
    /*模块初始化*/
    OLED_Init();            //OLED初始化
    CountSensor_Init();     //计数传感器初始化
    
    /*开启PWR 时钟*/
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);     //开启PWR的时钟
    //停止模式和待机模式一定要记得开启
    /*显示静态字符串*/
    OLED_ShowString(1, 1, "Count:");
    
    while (1)
    {
        OLED_ShowNum(1, 7, CountSensor_Get(), 5);           //OLED不断刷新显示CountSensor_Get的返回值
        OLED_ShowString(2, 1, "Running");                   //OLED闪烁Running,指示当前主循环正在运行
        Delay_ms(100);
        OLED_ShowString(2, 1, "       ");
        Delay_ms(100);
        
        //进入停止模式
        PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); //STM32进入停止模式,并等待中断唤醒
        SystemInit();   //唤醒后,要重新配置时钟,否则停止模式后主频变成8Mhz.
    }
}

3.3 待机模式,+ 实时时钟.

int main(void)
{
    /*模块初始化*/
    OLED_Init();        //OLED初始化
    MyRTC_Init();       //RTC初始化
    /*开启时钟 pwr时钟*/
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);     //开启PWR的时钟
                                                            //停止模式和待机模式一定要记得开启
    
    /*显示静态字符串*/
    OLED_ShowString(1, 1, "CNT :");
    OLED_ShowString(2, 1, "ALR :");
    OLED_ShowString(3, 1, "ALRF:");
    
    /*使能WKUP引脚*/
    PWR_WakeUpPinCmd(ENABLE);                       //使能位于PA0的WKUP引脚,WKUP引脚上升沿唤醒待机模式
    
    /*设定闹钟*/
    uint32_t Alarm = RTC_GetCounter() + 10;         //闹钟为唤醒后当前时间的后10s
    RTC_SetAlarm(Alarm);                            //写入闹钟值到RTC的ALR寄存器
    OLED_ShowNum(2, 6, Alarm, 10);                  //显示闹钟值
    
    while (1)
    {
        OLED_ShowNum(1, 6, RTC_GetCounter(), 10);   //显示32位的秒计数器
        OLED_ShowNum(3, 6, RTC_GetFlagStatus(RTC_FLAG_ALR), 1); //显示闹钟标志位,闹钟响置1.
        
        OLED_ShowString(4, 1, "Running");   //OLED闪烁Running,指示当前主循环正在运行
        Delay_ms(100);
        OLED_ShowString(4, 1, "       ");
        Delay_ms(100);
        
        OLED_ShowString(4, 9, "STANDBY");   //OLED闪烁STANDBY,指示即将进入待机模式
        Delay_ms(1000);
        OLED_ShowString(4, 9, "       ");
        Delay_ms(100);
        OLED_Clear();                       //OLED清屏,模拟关闭外部所有的耗电设备,以达到极度省电
        
        PWR_EnterSTANDBYMode();                     //STM32进入停止模式,并等待指定的唤醒事件(WKUP上升沿或RTC闹钟)
        /*待机模式唤醒后,程序会重头开始运行,重新执行main函数*/
    }
}

wakeupPincmd, PWR_WakeUpPinCmd(ENABLE);
使能Wakeup引脚, wkup 引脚用于将CPU从待机模式唤醒,
wkup 引脚被强置为输入下拉的配置(wkup引脚上的 上升沿将系统从待机模式唤醒).

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容