電源對電子設備的重要性不言而喻,它是保證系統穩定運行的基礎,而保證系統能穩定運行后,又有低功耗的要求。
在很多應用場合中都對電子設備的功耗要求非常苛刻,如某些傳感器信息采集設備,僅靠小型的電池提供電源,要求工作長達數年之久,且期間不需要任何維護;由于智慧穿戴設備的小型化要求,電池體積不能太大導致容量也比較小,所以也很有必要從控制功耗入手,提高設備的續行時間。
STM32有專門的電源管理外設監控電源并管理設備的運行模式,確保系統正常運行,并盡量降低器件的功耗。
- STM32電源管理系統
①備份域
STM32的備份域包括LSE振蕩器、RTC(RTC是一個實時時鐘,當主系統掉電后,內部RTC專門由一個外部備用電源給它供電,也就是說它有兩個供電源,為RTC備份一個電源是確保整個STM32系統的時間是正常運行的)、備份寄存器及備份SRAM這些器件,這部分的電路可以通過STM32的VBAT引腳獲取供電電源,在實際應用中一般會使用3V的鈕扣電池對該引腳供電。
在圖中備份域電路的左側有一個電源開關結構,它的功能類似圖中的雙二極管,在它的上方連接了VBAT電源,下方連接了VDD主電源(一般為3.3V,紐扣電池電壓為3V),右側引出到備份域電路中。當VDD主電源存在時,由于VDD電壓較高,備份域電路通過VDD供電,當VDD掉電時,備份域電路由鈕扣電池通過VBAT供電,保證電路能持續運行,從而可利用它保留關鍵數據。
②調壓器供電電路
在STM32的電源系統中調壓器供電的電路是最主要、最核心的部分,調壓器為備份域及待機電路以外的所有數字電路供電,其中包括內核、數字外設以及RAM,調壓器的輸出電壓約為1.2V,因而使用調壓器供電的這些電路區域被稱為1.2V域。整個電路系統想要實現睡眠模式、待機模式等都離不開調壓電路。
調壓器可控制調節供電電路使系統運行在“運行模式”、“停止模式”以及“待機模式”下:
運行模式:調壓器為 1.2 V 域(內核、存儲器和數字外設)提供全功率。
停止模式:1.2V域運行在低功耗狀態,1.2V區域的所有時鐘都被關閉,相應的外設都停止了工作,但它會保留內核寄存器以及SRAM的內容;
待機模式:整個1.2V域都斷電,該區域的內核寄存器及SRAM內容都會丟失(備份區域的寄存器及SRAM不受影響)。
為了提高轉換精度,STM32的ADC配有獨立的電源接口,方便進行單獨的濾波。ADC的工作電源使用VDDA引腳輸入,使用VSSA作為獨立的地連接,VREF引腳則為ADC提供測量使用的參考電壓。
- STM32低功耗模式
很多單片機都有低功耗模式,STM32F4 也不例外 ,運行狀態下的 HCLK 為 CPU 提供時鐘,內核執行程序代碼。當 CPU 不需繼續運行時,可以利用多個低功耗模式來節省功耗,例如等待某個外部事件時。STM32F4 按功耗由高到低排列具有運行、睡眠、停止和待機四種工作模式。
上電復位后STM32處于運行狀態時,當內核不需要繼續運行,就可以選擇進入后面的三種低功耗模式降低功耗,這三種模式中,電源消耗不同、喚醒時間不同、喚醒源不同,用戶需要根據應用需求,選擇最佳的低功耗模式。這三種低功耗模式層層遞進,運行的時鐘或芯片功能越來越少,因而功耗越來越低。
1.睡眠模式
在睡眠模式中,僅關閉了內核時鐘,內核停止運行,但其片上外設,CM4核心的外設以及相關的外設時鐘全都還照常運行。
有兩種方式進入睡眠模式,它的進入方式決定了從睡眠喚醒的方式,分別是WFI(wait for interrupt,只要有中斷就可以喚醒)和WFE(wait for event),即由等待“中斷”喚醒和由“事件”喚醒。睡眠模式的各種特性見下表:
2.停止模式:
在停止模式中,進一步關閉了其它所有的時鐘,于是所有的外設都停止了工作,但由于其1.2V區域的部分電源沒有關閉,還保留了內核的寄存器、內存的信息,所以內核和外設的工作信息并不會丟失,記憶仍留存,喚醒后仍然可以從原狀態繼續執行。
所以從停止模式喚醒,并重新開啟時鐘后,還可以從上次停止處繼續執行代碼。停止模式可以由任意一個外部中斷線(EXTI),喚醒,注意這里不是任意的中斷。在停止模式中可以選擇電壓調節器為開模式或低功耗模式,可選擇內部FLASH工作在正常模式或掉電模式。
需要注意的是,停止模式下,關閉了所有的外設,包括時鐘系統也關閉了,被喚醒之后首先默認選擇HSI內部時鐘,如果停止模式之前工作時使用的是HSE外部時鐘,整個系統還需要重新切換為HSE外部時鐘。
3.待機模式
待機模式,它除了關閉所有的時鐘,還把1.2V區域的電源也完全關閉了,也就是說,從待機模式喚醒后,由于沒有之前代碼的運行記錄,只能對芯片復位,重新檢測boot條件,從頭開始執行程序。它有四種喚醒方式,分別是WKUP(PA0)引腳的上升沿,RTC鬧鐘事件,NRST引腳的復位和IWDG(獨立看門狗)復位。
- STM32實現睡眠模式
進入方式:內核寄存器的SLEEPDEEP = 0 ,然后調用WFI或WFE指令即可進入睡眠模式;另外若內核寄存器的SLEEPONEXIT=0時,進入“立即睡眠”模式,SLEEPONEXIT=1時,進入“退出時睡眠”模式。
實驗內容:令指示燈處于工作狀態表明系統正常運行,之后調用WFI指令使系統進入睡眠模式,同時指示燈熄滅。使用按鍵中斷喚醒系統,同時喚醒時蜂鳴器工作表示系統已喚醒。
實驗步驟:
1.配置RCC
2.配置GPIO管腳
3.配置中斷優先級
4.編寫代碼
//main.c
#include "main.h"
#include "stm32f4xx_hal.h"
#include "usart.h"
#include "gpio.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
printf("this is sleep mode testn");
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
while (1)
{
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET);
//指示燈亮表示系統正常運行
HAL_Delay(2000);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_SET); //指示燈滅表示系統進入睡眠模式
HAL_SuspendTick(); //關閉systick中斷,否則系統會被此中斷喚醒
//注意:關閉systick中斷后,下面的代碼不能使用HAL_Delay函數,此函數依賴systick中斷
//調用封裝好的函數,進入睡眠模式內部主要是調用__WFI()命令
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); //進入睡眠模式
//PWR_MAINREGULATOR_ON這個參數時保留的一個接口,用來調節調壓器,但是睡眠狀態下外設仍然工作
//因此此參數無效,PWR_SLEEPENTRY_WFI表示通過WFI指令進入睡眠
//進入睡眠模式,下面的代碼不會執行
//喚醒后,才會依次執行下面的代碼
printf("系統被喚醒!n");
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET); //燈亮表示喚醒
}
}
//gpio.c
//進入中斷處理函數
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_0)
{
HAL_ResumeTick(); //回復systick中斷,否則系統不能使用HAL_Delay
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_SET); //蜂鳴器響200ms表示系統被喚醒
HAL_Delay(200);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_RESET);
}
}
內核停止運行時,無法向開發板燒錄代碼,此時向開發板燒錄代碼會提示內部錯誤。但是可以同時按下開發板復位鍵與燒錄按鈕并馬上放開復位鍵(動作要迅速且流暢),就可以燒錄代碼。
- STM32實現停止模式
停止模式下,內核不會工作,外設也不會工作,但是外設當下的狀態依舊保留,保留停止前的內核寄存器、內存的數據。因為只是停止了外設的時鐘,而不會停止供電。外設不會進一步工作,功耗自然就下降。系統運行的參數仍然保留,I/O口的狀態保留為停止前的狀態。
進入方式:內核寄存器的SLEEPDEEP =1,PWR_CR寄存器中的PDDS=0,然后調用WFI或WFE指令即可進入停止模式;PWR_CR寄存器的LPDS=0時,調壓器工作在正常模式,LPDS=1時工作在低功耗模式.
喚醒系統首先要恢復時鐘,默認情況下一恢復首先選擇HSI(內部時鐘),如果進入停止模式前一些外設使用的時HSE(外部時鐘)或者經過PLL倍頻后更高速的時鐘喚醒后就會導致由于時鐘頻率很低而無法正常工作。想要系統完全正常工作必須開啟HSE以及PLL單元。
實驗內容:令指示燈處于工作狀態表明系統正常運行,之后調用WFI指令使系統進入睡眠模式,同時指示燈熄滅。使用按鍵中斷喚醒系統,同時喚醒時蜂鳴器工作表示系統已喚醒。喚醒后系統默認選擇HSI,重新使能HSE和PLL。
實驗步驟:工程配置與睡眠模式下的配置相同.
編寫代碼:
//main.c
#include "main.h"
#include "stm32f4xx_hal.h"
#include "usart.h"
#include "gpio.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
printf("this is sleep mode testn");
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
while (1)
{
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET); //指示燈亮表示系統正常運行
HAL_Delay(2000);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_SET); //指示燈滅表示系統進入停止模式
//HAL_SuspendTick();不需要關閉systick中斷,因為要特定的中斷線才能喚醒
//調用封裝好的函數,進入睡眠模式內部主要是調用__WFI()命令
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); //進入停止模式
//PWR_MAINREGULATOR_ON表示調壓器處于正常模式
//PWR_LOWPOWERREGULATOR_ON表示調壓器處于低功耗模式(停止模式),
//PWR_SLEEPENTRY_WFI表示通過WFI指令進入睡眠
//進入停止模式,下面的代碼不會執行
//喚醒后,才會依次執行下面的代碼
printf("系統被喚醒!n");
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET); //燈亮表示喚醒
}
}
//gpio.c
//編寫時鐘恢復函數
void CLK_Resume()
{
//使能HSE
__HAL_RCC_HSE_CONFIG(RCC_HSE_ON);
while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
//等待振蕩器正常工作,振蕩起來
{
//使能PLL
__HAL_RCC_PLL_ENABLE();
while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)//等待PLL正常工作
{
}
//選擇PLL作為系統時鐘
__HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_PLLCLK);
while(__HAL_RCC_GET_SYSCLK_SOURCE() != 0x08 )
{
}
}
//進入中斷處理函數
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_0)
{
CLK_Resume(); //恢復時鐘,打開HSE和PLL
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_SET);
//蜂鳴器響200ms表示系統被喚醒
HAL_Delay(200);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_RESET);
}
}
- STM32實現待機模式
待機模式不僅關閉內核與外設的時鐘,而且也切斷了電源,這樣系統完全不能工作,狀態得不到不存,寄存器與內存信息丟失。相當于復位,喚醒后從頭開始運行。除復位引腳、RTC_AF1引腳及WKUP引腳,其它I/O口均工作在高阻態。
進入方式:內核寄存器的SLEEPDEEP =1,PWR_CR寄存器中的PDDS=1,PWR_CR寄存器中的喚醒狀態位WUF=0,然后調用WFI或WFE指令即可進入待機模式,喚醒后喚醒狀態位WUF=1。
待機模式的喚醒方式只能通過一些固定的方式,如:通過WKUP引腳的上升沿,RTC鬧鐘、喚醒、入侵、時間戳事件或NRST引腳外部復位及IWDG復位喚醒。
實驗內容:令指示燈處于工作狀態表明系統正常運行,之后調用WFI指令使系統進入睡眠模式,同時指示燈熄滅。使用按鍵喚醒系統,同時喚醒時蜂鳴器工作表示系統已喚醒。事實上,上述睡眠模式與停止模式的工程配置中,按鍵對應的PA0就是一個WKUP引腳,因此這里仍然使用按鍵喚醒。
實驗步驟:工程配置與睡眠模式下的配置相同
編寫代碼:
//main.c
#include "main.h"
#include "stm32f4xx_hal.h"
#include "usart.h"
#include "gpio.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
printf("this is stand mode testn");
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
while (1)
{
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET); //指示燈亮表示系統正常運行
HAL_Delay(2000);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_SET); //指示燈滅表示系統進入停止模式
//HAL_SuspendTick();不需要關閉systick中斷,因為要特定的中斷線才能喚醒
//進入待機模式前,必須使能喚醒管腳,且喚醒狀態位WUF應當清0
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); //使能喚醒引腳,f407只有一個喚醒管腳PA0
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);//清除WUF位為0,為1時表示被喚醒
HAL_PWR_EnterSTANDBYMode(); //進入待機模式
//進入待機模式,下面的代碼不會執行
//喚醒后,下面的代碼也不會執行
printf("系統被喚醒!n");
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET); //燈亮表示喚醒
}
}
//系統進入待機模式后,按下按鍵喚醒,并不會進入中斷,
//而是從頭開始進行工作,是一個復位操作
//原來的狀態得不到保存,因此進入待機模式HAL_PWR_EnterSTANDBYMode()
//下面的代碼永遠不會被執行到
評論