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個模式進入函數
-
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry);
-
void PWR_EnterSTANDBYMode(void);
作用:前者進入停機狀態,后者進入待機狀態。
- 2個使能函數
-
void PWR_WakeUpPinCmd(FunctionalState NewState);
-
void PWR_BackupAccessCmd(FunctionalState NewState);
作用:前者使能WK_UP引腳喚醒(正常模式下,WK_UP引腳作為普通IO口,待機模式下設置成喚醒功能),后者使能BKP后備區域訪問使能。
- 2個狀態位函數
-
FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG);
-
void PWR_ClearFlag(uint32_t PWR_FLAG);
作用:前者獲取電源控制的狀態位,后者清除相應的狀態位。
- 2個內核指令函數
-
__WFI();
-
__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按鍵按下
-
void Sys_Standby(void)
-
{
-
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //使能PWR外設時鍾
-
PWR_WakeUpPinCmd(ENABLE); //使能喚醒管腳功能
-
PWR_EnterSTANDBYMode(); //進入待命(STANDBY)模式
-
}
-
//系統進入待機模式
-
void Sys_Enter_Standby(void)
-
{
-
RCC_APB2PeriphResetCmd( 0X01FC,DISABLE); //復位所有IO口
-
Sys_Standby();
-
}
-
//檢測WKUP腳的信號
-
//返回值1:連續按下3s以上
-
// 0:錯誤的觸發
-
u8 Check_WKUP( void)
-
{
-
u8 t= 0; //記錄按下的時間
-
LED0= 0; //亮燈DS0
-
while(1)
-
{
-
if(WKUP_KD)
-
{
-
t++; //已經按下了
-
delay_ms( 30);
-
if(t>=100) //按下超過3秒鍾
-
{
-
LED0= 0; //點亮DS0
-
return 1; //按下3s以上了
-
}
-
} else
-
{
-
LED0= 1;
-
return 0; //按下不足3秒
-
}
-
}
-
}
-
//中斷,檢測到PA0腳的一個上升沿.
-
//中斷線0線上的中斷檢測
-
-
-
void EXTI0_IRQHandler(void)
-
{
-
EXTI_ClearITPendingBit(EXTI_Line0); // 清除LINE10上的中斷標志位
-
if(Check_WKUP())//關機?
-
{
-
Sys_Enter_Standby();
-
}
-
}
-
//PA0 WKUP喚醒初始化
-
void WKUP_Init(void)
-
{
-
GPIO_InitTypeDef GPIO_InitStructure;
-
NVIC_InitTypeDef NVIC_InitStructure;
-
EXTI_InitTypeDef EXTI_InitStructure;
-
-
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); //使能GPIOA和復用功能時鍾
-
-
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.0
-
-
EXTI_InitStructure.EXTI_Line = EXTI_Line0; //設置按鍵所有的外部線路
-
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //設外外部中斷模式:EXTI線路為中斷請求
-
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿觸發
-
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
-
EXTI_Init(&EXTI_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_InitStruct中指定的參數初始化外設NVIC寄存器
-
-
if(Check_WKUP()==0) Sys_Standby(); //不是開機,進入待機模式
-
-
}
-
int main(void)
-
{
-
-
delay_init(); //延時函數初始化
-
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置中斷優先級分組為組2:2位搶占優先級,2位響應優先級
-
uart_init( 115200); //串口初始化為115200
-
LED_Init(); //LED端口初始化
-
WKUP_Init(); //待機喚醒初始化
-
LCD_Init(); //LCD初始化
-
POINT_COLOR=RED;
-
-
LCD_ShowString( 30,50,200,16,16,"Warship STM32");
-
LCD_ShowString( 30,70,200,16,16,"WKUP TEST");
-
LCD_ShowString( 30,90,200,16,16,"ATOM@ALIENTEK");
-
LCD_ShowString( 30,110,200,16,16,"2014/1/14");
-
-
while(1)
-
{
-
LED0=!LED0;
-
delay_ms( 250);
-
}
-
}
STM32控制程序分析
WKUP_Init()函數:初始化GPIO、外部中斷等准備工作。
由於WK_UP鍵有兩個功能:正常模式下,長按3秒進入待機模式;待機模式下,長按3秒退出待機模式。
本案例中的實現是:
- 正常模式下,將WK_UP鍵設置成外部中斷,一旦按下,進入中斷處理函數,在中斷處理函數中進行3秒的時間判斷是否進入待機模式;
-
void WKUP_Init(void)
-
{
-
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); //使能GPIOA和復用功能時鍾
-
-
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.0
-
-
EXTI_Init(&EXTI_InitStructure); // 初始化外部中斷
-
-
NVIC_Init(&NVIC_InitStructure); //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器
-
-
}
-
void EXTI0_IRQHandler(void)
-
{
-
EXTI_ClearITPendingBit(EXTI_Line0); // 清除LINE10上的中斷標志位
-
if(Check_WKUP())//關機?
-
{
-
Sys_Enter_Standby();
-
}
-
}
- 待機模式下,設置WK_UP鍵用來退出待機模式,一旦按下,退出待機模式,重新執行main主函數,在主函數中進行3秒的時間判斷,如果沒有3秒,重新進入待機模式,否則繼續正常執行。
-
void WKUP_Init(void)
-
{
-
//初始化過程
-
if(Check_WKUP()==0) Sys_Standby(); //不是開機,進入待機模式
-
-
}
而其中進入待機模式的程序代碼塊,就是之前的待機模式的一般步驟:
-
void Sys_Standby(void)
-
{
-
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //使能PWR外設時鍾
-
PWR_WakeUpPinCmd(ENABLE); //使能喚醒管腳功能
-
PWR_EnterSTANDBYMode(); //進入待命(STANDBY)模式
-
}重要:在待機模式下,PA0喚醒,reset重跑main 按下按鍵3s,需要判斷標志位,不然在待機模式下斷電后重啟,會無法正常:代碼:PWR_GetFlagStatus (PWR_FLAG_SB)。