zoukankan      html  css  js  c++  java
  • STM32-电源控制、低功耗模式

    STM32的电源控制

    STM32的电源框图

    STM32的工作电压(VDD)为2.0~3.6V。通过内置的电压调节器提供所需的1.8V电源。 当主电源VDD掉电后,通过VBAT脚为实时时钟(RTC)和备份寄存器提供电源。

    下面是STM32的电源框图:

    注意:框图中的VDDA和VSSA必须分别联到VDD和VSS。

    独立的A/D转换器供电和参考电压

    为了提高转换的精确度,ADC使用一个独立的电源供电,过滤和屏蔽来自印刷电路板上的毛刺干扰。

    • ADC的电源引脚为VDDA;
    • 独立的电源地VSSA。

    如果有VREF-引脚(根据封装而定),它必须连接到VSSA。同时,为了确保输入为低压时获得更好精度,用户可以连接一个独立的外部参考电压ADC到VREF+和VREF-脚上。在VREF+的电压范围为2.4V~VDDA。

    电池备份区域

    使用电池或其他电源连接到VBAT脚上,当VDD断电时,可以保存备份寄存器的内容和维持RTC的功能。 

    VBAT脚也为RTC、LSE振荡器和PC13至PC15供电,这保证当主要电源被切断时RTC能继续工作。切换到VBAT供电由复位模块中的掉电复位功能控制。 如果应用中没有使用外部电池,VBAT必须连接到VDD引脚上。

    电压调节器

    复位后调节器总是使能的。根据应用方式它以3种不同的模式工作:

    • 运行模式:调节器以正常功耗模式提供1.8V电源(内核,内存和外设);
    • 停止模式:调节器以低功耗模式提供1.8V电源,以保存寄存器和SRAM的内容;
    • 待机模式:调节器停止供电。除了备用电路和备份域外,寄存器和SRAM的内容全部丢失。

    STM32的低功耗模式

    很多单片机有低功耗模式,STM32也不例外。在系统或者电源复位后,微控制器出于运行状态之下,HCLK为CPU提供时钟,内核执行代码。当CPU不需要继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个事件触发。

    低功耗模式分类

    STM32有三种低功耗模式:

    • 睡眠模式:Cortex-M3内核停止,所有外设包括Cortex-M3核心的外设,如NVIC、系统时钟(SysTick)等仍在运行;
    • 停止模式:所有时钟都已停止。
    • 待机模式:1.8V内核电源关闭。

    在运行模式下,可以通过下面方式降低功耗:

    • 降低系统时钟:

    在运行模式下,通过对预分频寄存器进行编程,可以降低任意一个系统时钟(SYSCLK、HCLK、PCLK1、PCLK2)的速度。进入睡眠模式前,也可以利用预分频器来降低外设的时钟;

    • 关闭APB和AHB总线上未被使用的外设时钟:

    在运行模式下,任何时候都可以通过停止为外设和内存提供时钟(HCLK和PCLKx)来减少功耗。 为了在睡眠模式下更多地减少功耗,可在执行WFI或WFE指令前关闭所有外设的时钟。 通过设置AHB外设时钟使能寄存器 (RCC_AHBENR)、APB2外设时钟使能寄存器(RCC_APB2ENR)和APB1外设时钟使能寄存器(RCC_APB1ENR)来开关各个外设模块的时钟。

    睡眠模式

    在睡眠模式下,Cortex-M3内核停止,所有外设包括Cortex-M3核心的外设,如NVIC、系统时钟(SysTick)等仍在运行,也就是说:所有的I/O引脚都保持它们在运行模式时的状态。

    该模式唤醒所需的时间最短,因为没有时间损失在中断的进入或退出上。

    停止模式

    停止模式是在Cortex™-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电压调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止,但1.8V供电区域仍通电,PLL、HSI和HSE RC振荡器的功能被禁止,SRAM和寄存器内容被保留下来。

    在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。

    待机模式

    待机模式可实现系统的最低功耗。该模式是在Cortex-M3深睡眠模式时关闭电压调节器。整个1.8V供电区域被断电。PLL、HSI和HSE振荡器也被断电。SRAM和寄存器内容丢失。只有备份的寄存器和待机电路维持供电。

    在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:

    • 复位引脚(始终有效);
    • 当被设置为防侵入或校准输出时的TAMPER引脚;
    • 被使能的唤醒引脚。

    电源控制相关配置寄存器

    电源控制寄存器(PWR_CR)

    作用:掉电深度睡眠位的设置(停止模式和待机模式)。

    电源控制/状态寄存器(PWR_CSR)

    作用:使能WKUP引脚用于待机模式唤醒、WUF唤醒标志位。

    电源控制相关配置库函数

    • 2个模式进入函数
    1.  
      void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry);
    2.  
      void PWR_EnterSTANDBYMode(void);

    作用:前者进入停机状态,后者进入待机状态。

    • 2个使能函数
    1.  
      void PWR_WakeUpPinCmd(FunctionalState NewState);
    2.  
      void PWR_BackupAccessCmd(FunctionalState NewState);

    作用:前者使能WK_UP引脚唤醒(正常模式下,WK_UP引脚作为普通IO口,待机模式下设置成唤醒功能),后者使能BKP后备区域访问使能。

    • 2个状态位函数
    1.  
      FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG);
    2.  
      void PWR_ClearFlag(uint32_t PWR_FLAG);

    作用:前者获取电源控制的状态位,后者清除相应的状态位。

    • 2个内核指令函数
    1.  
      __WFI();
    2.  
      __WFE();

    作用:CM3内核的WFI(等待中断)、WFE(等待事件)指令(定义在:core_cm3.h)。

    待机模式的一般步骤

    实例要求:实现同一个引脚PA0引脚(WK_UP引脚),正常模式下,长按3秒进入待机模式;待机模式下,长按3秒待机唤醒。

    • 使能电源时钟。调用函数:RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    • 设置WK_UP引脚作为唤醒源。调用函数:PWR_WakeUpPinCmd(ENABLE);
    • 进入待机模式。调用函数:void PWR_EnterSTANDBYMode(void),执行设置SLEEPDEEP位,设置PDDS位,执行WFI指令。
    #define WKUP_KD PAin(0)			//PA0 检测是否外部WK_UP按键按下
    1.  
      void Sys_Standby(void)
    2.  
      {
    3.  
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //使能PWR外设时钟
    4.  
      PWR_WakeUpPinCmd(ENABLE); //使能唤醒管脚功能
    5.  
      PWR_EnterSTANDBYMode(); //进入待命(STANDBY)模式
    6.  
      }
    7.  
      //系统进入待机模式
    8.  
      void Sys_Enter_Standby(void)
    9.  
      {
    10.  
      RCC_APB2PeriphResetCmd(0X01FC,DISABLE); //复位所有IO口
    11.  
      Sys_Standby();
    12.  
      }
    13.  
      //检测WKUP脚的信号
    14.  
      //返回值1:连续按下3s以上
    15.  
      // 0:错误的触发
    16.  
      u8 Check_WKUP(void)
    17.  
      {
    18.  
      u8 t=0; //记录按下的时间
    19.  
      LED0=0; //亮灯DS0
    20.  
      while(1)
    21.  
      {
    22.  
      if(WKUP_KD)
    23.  
      {
    24.  
      t++; //已经按下了
    25.  
      delay_ms(30);
    26.  
      if(t>=100) //按下超过3秒钟
    27.  
      {
    28.  
      LED0=0; //点亮DS0
    29.  
      return 1; //按下3s以上了
    30.  
      }
    31.  
      }else
    32.  
      {
    33.  
      LED0=1;
    34.  
      return 0; //按下不足3秒
    35.  
      }
    36.  
      }
    37.  
      }
    38.  
      //中断,检测到PA0脚的一个上升沿.
    39.  
      //中断线0线上的中断检测
    40.  
       
    41.  
       
    42.  
      void EXTI0_IRQHandler(void)
    43.  
      {
    44.  
      EXTI_ClearITPendingBit(EXTI_Line0); // 清除LINE10上的中断标志位
    45.  
      if(Check_WKUP())//关机?
    46.  
      {
    47.  
      Sys_Enter_Standby();
    48.  
      }
    49.  
      }
    50.  
      //PA0 WKUP唤醒初始化
    51.  
      void WKUP_Init(void)
    52.  
      {
    53.  
      GPIO_InitTypeDef GPIO_InitStructure;
    54.  
      NVIC_InitTypeDef NVIC_InitStructure;
    55.  
      EXTI_InitTypeDef EXTI_InitStructure;
    56.  
       
    57.  
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);//使能GPIOA和复用功能时钟
    58.  
       
    59.  
      GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0; //PA.0
    60.  
      GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPD;//上拉输入
    61.  
      GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO
    62.  
      //使用外部中断方式
    63.  
      GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //中断线0连接GPIOA.0
    64.  
       
    65.  
      EXTI_InitStructure.EXTI_Line = EXTI_Line0; //设置按键所有的外部线路
    66.  
      EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设外外部中断模式:EXTI线路为中断请求
    67.  
      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发
    68.  
      EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    69.  
      EXTI_Init(&EXTI_InitStructure); // 初始化外部中断
    70.  
       
    71.  
      NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键所在的外部中断通道
    72.  
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
    73.  
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级2级
    74.  
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
    75.  
      NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    76.  
       
    77.  
      if(Check_WKUP()==0) Sys_Standby(); //不是开机,进入待机模式
    78.  
       
    79.  
      }
    1.  
      int main(void)
    2.  
      {
    3.  
       
    4.  
      delay_init(); //延时函数初始化
    5.  
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    6.  
      uart_init(115200); //串口初始化为115200
    7.  
      LED_Init(); //LED端口初始化
    8.  
      WKUP_Init(); //待机唤醒初始化
    9.  
      LCD_Init(); //LCD初始化
    10.  
      POINT_COLOR=RED;
    11.  
       
    12.  
      LCD_ShowString(30,50,200,16,16,"Warship STM32");
    13.  
      LCD_ShowString(30,70,200,16,16,"WKUP TEST");
    14.  
      LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
    15.  
      LCD_ShowString(30,110,200,16,16,"2014/1/14");
    16.  
       
    17.  
      while(1)
    18.  
      {
    19.  
      LED0=!LED0;
    20.  
      delay_ms(250);
    21.  
      }
    22.  
      }

    STM32控制程序分析

    WKUP_Init()函数:初始化GPIO、外部中断等准备工作。

    由于WK_UP键有两个功能:正常模式下,长按3秒进入待机模式;待机模式下,长按3秒退出待机模式。

    本案例中的实现是:

    • 正常模式下,将WK_UP键设置成外部中断,一旦按下,进入中断处理函数,在中断处理函数中进行3秒的时间判断是否进入待机模式;
    1.  
      void WKUP_Init(void)
    2.  
      {
    3.  
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);//使能GPIOA和复用功能时钟
    4.  
       
    5.  
      GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0; //PA.0
    6.  
      GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPD;//上拉输入
    7.  
      GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO
    8.  
      //使用外部中断方式
    9.  
      GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //中断线0连接GPIOA.0
    10.  
       
    11.  
      EXTI_Init(&EXTI_InitStructure); // 初始化外部中断
    12.  
       
    13.  
      NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    14.  
       
    15.  
      }
    1.  
      void EXTI0_IRQHandler(void)
    2.  
      {
    3.  
      EXTI_ClearITPendingBit(EXTI_Line0); // 清除LINE10上的中断标志位
    4.  
      if(Check_WKUP())//关机?
    5.  
      {
    6.  
      Sys_Enter_Standby();
    7.  
      }
    8.  
      }
    • 待机模式下,设置WK_UP键用来退出待机模式,一旦按下,退出待机模式,重新执行main主函数,在主函数中进行3秒的时间判断,如果没有3秒,重新进入待机模式,否则继续正常执行。
    1.  
      void WKUP_Init(void)
    2.  
      {
    3.  
              //初始化过程
    4.  
      if(Check_WKUP()==0) Sys_Standby(); //不是开机,进入待机模式
    5.  
       
    6.  
      }

    而其中进入待机模式的程序代码块,就是之前的待机模式的一般步骤:

    1.  
      void Sys_Standby(void)
    2.  
      {
    3.  
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //使能PWR外设时钟
    4.  
      PWR_WakeUpPinCmd(ENABLE); //使能唤醒管脚功能
    5.  
      PWR_EnterSTANDBYMode(); //进入待命(STANDBY)模式
    6.  
      }
       
       
       
       
      重要:在待机模式下,PA0唤醒,reset重跑main 按下按键3s,需要判断标志位,不然在待机模式下断电后重启,会无法正常:
      代码:PWR_GetFlagStatus (PWR_FLAG_SB)。
       
       
  • 相关阅读:
    GitLab 介绍
    git 标签
    git 分支
    git 仓库 撤销提交 git reset and 查看本地历史操作 git reflog
    git 仓库 回退功能 git checkout
    python 并发编程 多进程 练习题
    git 命令 查看历史提交 git log
    git 命令 git diff 查看 Git 区域文件的具体改动
    POJ 2608
    POJ 2610
  • 原文地址:https://www.cnblogs.com/linxw-blog/p/14269059.html
Copyright © 2011-2022 走看看