1. 程式人生 > 實用技巧 >STM32-電源控制、低功耗模式

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. void EXTI0_IRQHandler(void)
  41. {
  42. EXTI_ClearITPendingBit(EXTI_Line0); // 清除LINE10上的中斷標誌位
  43. if(Check_WKUP())//關機?
  44. {
  45. Sys_Enter_Standby();
  46. }
  47. }
  48. //PA0 WKUP喚醒初始化
  49. void WKUP_Init(void)
  50. {
  51. GPIO_InitTypeDef GPIO_InitStructure;
  52. NVIC_InitTypeDef NVIC_InitStructure;
  53. EXTI_InitTypeDef EXTI_InitStructure;
  54. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);//使能GPIOA和複用功能時鐘
  55. GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0; //PA.0
  56. GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPD;//上拉輸入
  57. GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO
  58. //使用外部中斷方式
  59. GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //中斷線0連線GPIOA.0
  60. EXTI_InitStructure.EXTI_Line = EXTI_Line0; //設定按鍵所有的外部線路
  61. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //設外外部中斷模式:EXTI線路為中斷請求
  62. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿觸發
  63. EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  64. EXTI_Init(&EXTI_InitStructure); // 初始化外部中斷
  65. NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按鍵所在的外部中斷通道
  66. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先佔優先順序2級
  67. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //從優先順序2級
  68. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中斷通道
  69. NVIC_Init(&NVIC_InitStructure); //根據NVIC_InitStruct中指定的引數初始化外設NVIC暫存器
  70. if(Check_WKUP()==0) Sys_Standby(); //不是開機,進入待機模式
  71. }
  1. int main(void)
  2. {
  3. delay_init(); //延時函式初始化
  4. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設定中斷優先順序分組為組2:2位搶佔優先順序,2位響應優先順序
  5. uart_init(115200); //串列埠初始化為115200
  6. LED_Init(); //LED埠初始化
  7. WKUP_Init(); //待機喚醒初始化
  8. LCD_Init(); //LCD初始化
  9. POINT_COLOR=RED;
  10. LCD_ShowString(30,50,200,16,16,"Warship STM32");
  11. LCD_ShowString(30,70,200,16,16,"WKUP TEST");
  12. LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
  13. LCD_ShowString(30,110,200,16,16,"2014/1/14");
  14. while(1)
  15. {
  16. LED0=!LED0;
  17. delay_ms(250);
  18. }
  19. }

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. GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0; //PA.0
  5. GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPD;//上拉輸入
  6. GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO
  7. //使用外部中斷方式
  8. GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //中斷線0連線GPIOA.0
  9. EXTI_Init(&EXTI_InitStructure); // 初始化外部中斷
  10. NVIC_Init(&NVIC_InitStructure); //根據NVIC_InitStruct中指定的引數初始化外設NVIC暫存器
  11. }
  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. }

而其中進入待機模式的程式程式碼塊,就是之前的待機模式的一般步驟:

  1. void Sys_Standby(void)
  2. {
  3. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //使能PWR外設時鐘
  4. PWR_WakeUpPinCmd(ENABLE); //使能喚醒管腳功能
  5. PWR_EnterSTANDBYMode(); //進入待命(STANDBY)模式
  6. }