STM32 低功耗模式

STM32 低功耗模式

注意事项

烧录程序

  • 芯片在3中低功耗模式下,是没法直接再下载程序的,如果直接点击下载,就会提示报错,这是因为芯片现在在睡眠,不会理调试端口,解决方法也很简单
    • 第一步,按住复位键不放
    • 第二步,点下载按钮
    • 第三步,即使松开复位键

在这里插入图片描述

  • 点击下载按钮后一定要即使松开复位键,否则会报错了。实测按一下复位键,马上点下载也是可以的

在这里插入图片描述

判断寄存器读写特征

  • 下图 W 表示只能写入不能读出

在这里插入图片描述

  • 下图 rw 表示可读可写

在这里插入图片描述

  • 下图 r 表示只能读不能写

在这里插入图片描述

睡眠模式+串口收发数据

  • 假设我们目前要用STM32做一个下位机,下位机接收电脑串口发过来的指令,然后执行相应的功能,电脑随时都可能通过串口发送指令,当然也可以几个小时、几天都不发指令,为了随时能相应指令,STM32就得时刻准备着,比如在主循环中,不断地检查标志位,但是如果一直不发指令,这些检查标志位等的操作就没有什么意义,还比较费电。
  • 如果把代码放入中断执行,但是即使主循环是空的,CPU也是在不断耗电的,所以对于这种靠中断触发,没有中断的时候,就没什么事的代码,我们就可以加入低功耗模式,没事的时候就低功耗,中断来了,再唤醒运行即可。

模式选择

  • 睡眠模式(可以) CPU时钟关闭,程序不再执行,但是外设的时钟不会关,USART硬件电路还是可以接收数据的,USART收到数据后,产生中断,唤醒CPU。
  • 停机模式或停止模式(不可以) 所有1.8V区域的时钟均关闭,CPU和外设都不能运行,USART也就不能收到数据,无法产生中断,并且USART的中断也不能唤醒停止模式。
  • 待机模式(不可以)

代码示例(USART代码略)

mian.c

SLEEPDEEP和SLEEPONEXIT位使用默认配置,默认为0.

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

uint16_t Num;
uint8_t RxData;
int main(void)
{
    
    OLED_Init();
    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");
        Delay_ms(500);
        OLED_ShowString(2,1,"        ");
        Delay_ms(500);
        
        __WFI();//立刻进入睡眠模式 对应CPU的一个汇编指令 #define __WFI  __wfi
    }
}

程序执行流程

  • 程序开始,初始化,把串口配置好
  • 进入主循环,检查标志位,Running闪烁一次
  • 在主循环的最后,执行WFI,这时CPU就会立刻睡眠,程序停在WFI指令处。这时CPU睡眠,但是各个外设,比如USART还是工作状态。
  • 等到我们用串口助手发送数据时,USART外设收到数据,产生中断,唤醒CPU
  • 睡眠模式唤醒之后,程序在暂停的地方继续运行,所以程序会运行到WFI之后,但是唤醒之后,中断也是会立刻申请的,所以程序再跳回到while循环开头之前,先进入USART的中断函数,在中断函数中,读取数据,置RxFlag,清除RXNE。
  • 回到while循环的开头,这时RxFlag刚刚置1,所以if成立,执行数据回传和显示的功能,唤醒的功能执行完之后,Running闪烁一次。
  • 最后程序又来到WFI的位置,CPU再次进入睡眠。等待下一个数据发过来时,程序再重新执行一遍这个流程。
  • 睡眠模式,一般可以在while循环的最后加一个WFI指令,每来一个中断,先进中断函数,再执行一遍程序功能。

待机模式+实时时钟

  • 待机模式对标的是极度省电,光STM32自己一个省电,那也不行,所以一般在进入待机模式之前,我们都要尽可能地把外挂模块都关闭,如果外挂模块的耗电远超STM32本身,这时再给STM32待机,不管外部模块的话,那不就是捡了芝麻,丢了西瓜。
  • 所以STM32进入待机模式之前,一定要把外部接的模块,能停的都停掉,能断的都断掉,这样才能最大化省电。

程序流程

  • 第一步,设置RTC时钟
  • 第二步,进入待机模式
  • 第三步,使用闹钟信号,唤醒待机模式

待机模式唤醒后,程序是从头开始执行的,进入待机模式之后,高速时钟也都会关闭,在退出待机模式时,程序从头开始执行,在程序刚开始的时候,自动调用SystemInit()初始化时钟,所以待机模式,就不用像停止模式那样,手动调用SystemInit()了。

代码示例

main.c
#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "MyRTC.h"
#include "Delay.h"
int main(void)
{
    OLED_Init();
    MyRTC_Init();
    //虽然在RTC初始化已经开启了PWR时钟,就把开启PWR时钟的代码省略,那么我们待机模式的代码就会对RTC代码具有依赖性,增大了代	  码之间的耦合性,没有RTC待机模式就不能正常工作。
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//开启PWR时钟,保持代码独立性
    
    OLED_ShowString(1,1,"CNT :");
    OLED_ShowString(2,1,"ALR :");
    OLED_ShowString(3,1,"ALRF:");
    
    PWR_WakeUpPinCmd(ENABLE);//WAKE_UP引脚唤醒 WAKE_UP引脚默认是下拉的,WAKE_UP接高电平的时刻,待机模式就被唤醒了
    
    uint32_t Alarm = RTC_GetCounter()+10;//设定闹钟为10S后
    RTC_SetAlarm(Alarm);//设置闹钟值
    OLED_ShowNum(2,6,Alarm,10);//显示闹钟值
    
    while(1)
    {
        
       OLED_ShowNum(1,6, RTC_GetCounter(),10);//显示秒数 随着CNT的增大,CNT会和ALR相等,然后触发闹钟标志位置1
       OLED_ShowNum(3,6, RTC_GetFlagStatus(RTC_FLAG_ALR),10);//显示闹钟标志位
        
       OLED_ShowString(4,1,"Running");
       Delay_ms(500);
       OLED_ShowString(4,1,"        ");
       Delay_ms(500);
        
       OLED_ShowString(4,9,"STANDBY"); 
       Delay_ms(1000);
       OLED_ShowString(4,1,"        ");
       Delay_ms(500);
       
       OLED_Clear();//清屏
        
       PWR_EnterSTANDBYMode();//进入待机模式
        
    }
}

PWR_EnterSTANDBYMode()

  • 清除WakeUP标志位
  • 选择STANDBY模式,实际上就是把PDDS置1
  • SLEEPDEEP置1,进入深度睡眠
  • 调用WFI指令,进入待机模式
  • 对于待机模式,其实并没有区分WFI和WFE,库函数里也不能选择,统一调用WFI,WFI和WFE的区别就是唤醒方式不同。对于待机模式,它的唤醒条件是指定的4个信号,没有对中断唤醒和事件唤醒做出区分,所以我们就也不用区分了。
void PWR_EnterSTANDBYMode(void)
{
  /* Clear Wake-up flag */
  PWR->CR |= PWR_CR_CWUF;
  /* Select STANDBY mode */
  PWR->CR |= PWR_CR_PDDS;
  /* Set SLEEPDEEP bit of Cortex System Control Register */
  SCB->SCR |= SCB_SCR_SLEEPDEEP;
/* This option is used to ensure that store operations are completed */
#if defined ( __CC_ARM   )
  __force_stores();
#endif
  /* Request Wait For Interrupt */
  __WFI();
}
//在执行完这个函数进入待机模式后,这个函数之后的代码,就再也执行不到了,因为待机模式退出,程序从头开始。
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YRr YRr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值