天天看點

STM32基于固件庫學習筆記(5)電源管理之低功耗模式(睡眠、停止、待機)

低功耗模式

功耗的高低,決定了系統工作的時間,在需要長久間隔時間檢測資料,又不可能人實時去操作的項目,最先考慮的就是功耗問題了, 功耗越低産品使用時間就更久。也就是說當CPU不需繼續運作時,就可以利用多種低功耗模式來節省功耗,例如等待某個外部事件時。 使用者需要根據最低電源消耗、最快速啟動時間和可用的喚醒源等條件,標明一個最佳的低功耗模式。

STM32F10xx有三種低功耗模式:

1. 睡眠模式:(Cortex™-M3核心停止,所有外設包括Cortex-M3核心的外設,如NVIC、系統時鐘(SysTick)等仍在運作)

2. 停止模式: 所有的時鐘都停止。

3. 待機模式: 1.8V電源關閉,是最低功耗模式

  當處于運作模式,還可以使用降低系統時鐘、關閉APB和AHB總線上沒有使用的外設時鐘兩種方式降低功耗。

(一)睡眠模式

1. 進入睡眠模式

STM32基于固件庫學習筆記(5)電源管理之低功耗模式(睡眠、停止、待機)
  1. SLEEP-NOW:如果SLEEPONEXIT位被清除,當WRI或WFE被執行時,微控制器立即進。
  2. SLEEP-ON-EXIT:如果SLEEPONEXIT位被置位,系統從最低優先級的中斷處理程式中退出時,微控制器就立即進入睡眠模式。

2. 喚醒睡眠模式

  1. 如果執行WFI指令進入睡眠模式,任意一個被嵌套向量中斷控制器響應的外設中斷都能将系統從睡眠模式喚醒。
  2. 如果執行WFE指令進入睡眠模式,則一旦發生喚醒事件時,微處理器都将從睡眠模式退出。産生方式:

      在外設控制寄存器中使能一個中斷,而不是在NVIC(嵌套向量中斷控制器)中使能,并且在Cortex-M3系統控制寄存器中使能SEVONPEND位。當MCU從WFE中喚醒後,外設的中斷挂起位和外設的NVIC中斷通道挂起位(在NVIC中斷清除挂起寄存器中)必須被清除。

      配置一個外部或内部的EXIT線為事件模式。當MCU從WFE中喚醒後,因為與事件線對應的挂起位未被設定,不必清除外設的中斷挂起位或外設的NVIC中斷通道挂起位。

    注:Cortex-M3 權威指南第13章(182-183頁)也有講解。

(二)停止模式

STM32基于固件庫學習筆記(5)電源管理之低功耗模式(睡眠、停止、待機)

  停止模式是在Cortex™-M3的深睡眠模式基礎上結合了外設的時鐘控制機制,在停止模式下電壓調節器可運作在正常或低功耗模式。此時在1.8V供電區域的的所有時鐘都被停止,PLL、HSI和HSE RC振蕩器的功能被禁止,SRAM和寄存器内容被保留下來。在停止模式下,所有的I/O引腳都保持它們在運作模式時的狀态。

1. 進入

  在停止模式下,通過設定 的LPDS位使内部調節器進入低功耗模式,能夠降低更多的功耗。

  如果正在進行閃存程式設計,直到對記憶體通路完成,系統才進入停止模式。

  如果正在進行對APB的通路,直到對APB通路完成,系統才進入停止模式。

   ●獨立看門狗(IWDG):可通過寫入看門狗的鍵寄存器或硬體選擇來啟動IWDG。一旦啟動了獨立看門狗,除了系統複位,它不能再被停止。

  ● 實時時鐘(RTC):通過備份域控制寄存器 (RCC_BDCR)的RTCEN位來設定。

  ● 内部RC振蕩器(LSI RC):通過控制/狀态寄存器 (RCC_CSR)的LSION位來設定。

  ● 外部32.768kHz振蕩器(LSE):通過備份域控制寄存器 (RCC_BDCR)的LSEON位設定。在停止模式下,如果在進入該模式前ADC和DAC沒有被關閉,那麼這些外設仍然消耗電流。通過設定寄存器ADC_CR2的ADON位和寄存器DAC_CR的ENx位為0可關閉這2個外設。

2. 退出停止模式

  當一個中斷或喚醒事件導緻退出停止模式時,HSI RC振蕩器被選為系統時鐘。

當電壓調節器處于低功耗模式下,當系統從停止模式退出時,将會有一段額外的啟動延時。如果在停止模式期間保持内部調節器開啟,則退出啟動時間會縮短,但相應的功耗會增加。

(三)待機模式

STM32基于固件庫學習筆記(5)電源管理之低功耗模式(睡眠、停止、待機)

  待機模式可實作系統的最低功耗。該模式是在Cortex-M3深睡眠模式時關閉電壓調節器。整個1.8V供電區域被斷電。PLL、HSI和HSE振蕩器也被斷電。SRAM和寄存器内容丢失。

 1. 進入

  可以通過設定獨立的控制位,選擇以下待機模式的功能:

  ● 獨立看門狗(IWDG):可通過寫入看門狗的鍵寄存器或硬體選擇來啟動IWDG。一旦啟動了獨立看門狗,除了系統複位,它不能再被停止。

  ● 實時時鐘(RTC):通過備用區域控制寄存器(RCC_BDCR)的RTCEN位來設定。

  ● 内部RC振蕩器(LSI RC):通過控制/狀态寄存器(RCC_CSR)的LSION位來設定。

  ● 外部32.768kHz振蕩器(LSE):通過備用區域控制寄存器(RCC_BDCR)的LSEON位設定。

 2. 退出待機模式

  當一個外部複位(NRST引腳)、IWDG複位、WKUP引腳上的上升沿或RTC鬧鐘事件的上升沿發生時(見圖154 簡化的RTC框圖),微控制器從待機模式退出。從待機喚醒後,除了 : 電源控制/狀态寄存器(PWR_CSR),所有寄存器被複位。

從待機模式喚醒後的代碼執行等同于複位後的執行(采樣啟動模式引腳、讀取複位向量等)。電源控制/狀态寄存器(PWR_CSR)将會訓示核心由待機狀态退出。

3.待機模式下的輸入/輸出端口狀态

  在待機模式下,所有的I/O引腳處于高阻态,除了以下的引腳:

  ● 複位引腳(始終有效)

  ● 當被設定為防侵入或校準輸出時的TAMPER引腳

  ● 被使能的喚醒引腳

實作待機模式功能

1.初始化先進入待機狀态,

2.當有按鍵按下進入運作模式,

3.在有按鍵按下3s又會進入待機模式,等到按鍵按下喚醒。

具體步驟:

  1. 使能電源時鐘(是沒次必不可少的)
  1. 設定PA0按鍵引腳作為喚醒源。
  1. 設定 SLEEPDEEP 位,置 設定 PDDS 位,執行 WFI 指令,進入待機模式。
  1. 編寫按鍵中斷函數。
void EXTI0_IRQHandler(void)
{
  EXTI_ClearITPendingBit(EXTI_Line0); // 清除 LINE10 上的中斷标志位  
  if(Check_WKUP()==2) //進入待機模式
  {
    mode= 0;//清零模式變量
    Sys_Enter_Standby();
  }
  }
           

完整程式

/*
  1.初始化先判斷data為0,就是待機狀态,
  2.當有按鍵按下30ms進入運作模式,
  3.在有按鍵按下3s會進入睡眠模式 
   1-> 2->3->2->3 循環
     硬體: PA0接下拉的按鍵;PB5接共陽LED(0亮1滅)
     MCU:STM32F103ZETx系列
*/
#include "stm32f10x.h"    
u8 mode=0; //待機、喚醒模式控制變量      
void delay_ms(u16 time)
{    
   u16 i = 0;  
   while(time--)
   {
      i = 12000;  
      while(i--);    
   }
}
//初始化PB5  LED燈
void LED_Init_PB5(void)
{
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  GPIO_InitTypeDef GPIO_ITDef_PB5; 
  GPIO_ITDef_PB5.GPIO_Pin = GPIO_Pin_5;
  GPIO_ITDef_PB5.GPIO_Mode = GPIO_Mode_Out_PP;//推挽輸出  
  GPIO_ITDef_PB5.GPIO_Speed = GPIO_Speed_2MHz;  
  GPIO_Init(GPIOB,&GPIO_ITDef_PB5);
  GPIO_SetBits(GPIOB,GPIO_Pin_5);// 置 1輸出高電平
//  GPIO_ResetBits(GPIOB,GPIO_Pin_5);// 0
}

u8 Check_WKUP(void)
{
  u8 t=0;
  u8 tx=0; //記錄松開的次數
  GPIO_ResetBits(GPIOB,GPIO_Pin_5);// 置1  LED亮 
  while(1)
 {   
    if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))//已經按下了 
     delay_ms(5);//按鍵延時消鬥
    if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))//已經按下了
    {
       t++;
       tx=0;
    }
    else
     {   
        tx++;//超過300ms内沒有WKUP信号
       if(tx>1)
       {
         GPIO_SetBits(GPIOB,GPIO_Pin_5);//1
         return 0;//錯誤的按鍵,按下次數不夠
       }       
      }        
   delay_ms(30);
   if(mode== 0)
     {
        return mode=1;//有按鍵按下,喚醒待機模式
     }         
   if(t>=100&&mode== 1)//按下超過3秒鐘
      {
        GPIO_ResetBits(GPIOB,GPIO_Pin_5);// 0點亮 DS0
        return mode=2; //按下 3s 以上了,進入待機模式 
      }
 }
}
void WKUP_Init(void)
{
  //PA0(KEY中斷)作為喚醒條件
      //使能 GPIOA 和複用功能時鐘
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
  //初始化PA0的按鍵(上拉輸入)
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0;//PA.0
  GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPD; //上拉輸入
  GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 IO  
  //使用按鍵外部中斷方式
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
  //中斷線 0 連接配接 GPIOA. (按鍵)
  EXTI_InitTypeDef EXTI_InitStructure;
  EXTI_InitStructure.EXTI_Line = EXTI_Line0; //設定按鍵所有的外部線路
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //外部中斷模式
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿觸發
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure); // 初始化外部中斷
    //按鍵中斷設定
  NVIC_InitTypeDef   NVIC_InitStructure;
  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//使能外部中斷通道
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//先占優先級 2 級
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//從優先級 2 級
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//外部中斷通道使能
  NVIC_Init(&NVIC_InitStructure);//初始化 NVIC    
}

//系統進入待機模式
void Sys_Enter_Standby(void)
{
  RCC_APB2PeriphResetCmd(0X01FC,DISABLE); //複位所有 IO 口  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能PWR外設時鐘
  PWR_WakeUpPinCmd(ENABLE);//使能喚醒管腳功能
  PWR_EnterSTANDBYMode();//進入待命(STANDBY)模式
}
//中斷,檢測到 PA0 腳的一個上升沿.
//中斷線 0 線上的中斷檢測
void EXTI0_IRQHandler(void)
{
  EXTI_ClearITPendingBit(EXTI_Line0); // 清除 LINE10 上的中斷标志位  
  if(Check_WKUP()==2) //進入待機模式
  {
    mode= 0;//清零模式變量
    Sys_Enter_Standby();
  }
}
int main(void)
{
  LED_Init_PB5();
  WKUP_Init(); //待機喚醒初始化
  if(Check_WKUP()==1)  //不是開機,進入待機模式
  {
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能PWR外設時鐘
    PWR_WakeUpPinCmd(ENABLE);//使能喚醒管腳功能
    PWR_EnterSTANDBYMode();//進入待命(STANDBY)模式
  }
  while(1)
  {
     GPIO_ResetBits(GPIOB,GPIO_Pin_5);//LED亮
     delay_ms(50);        
     GPIO_SetBits(GPIOB,GPIO_Pin_5);//LED滅
     delay_ms(50);   
  }   
}
           

常用資料:

  STM32F10x_StdPeriph_Lib_V3.5.0(官方固件庫)

  連結:STM32固件庫使用手冊的中文翻譯版 提取碼:4lkx