第42章 電源管理—實現低功耗
全套200集視頻教程和1000頁PDF教程請到秉火論壇下載:www.firebbs.cn
野火視頻教程優酷觀看網址:http://i.youku.com/firege
本章參考數據:《STM32F4xx 中文參考手冊》、《STM32F4xx規格書》、庫說明文檔《stm32f4xx_dsp_stdperiph_lib_um.chm》。
42.1 STM32的電源管理簡介
電源對電子設備的重要性不言而喻,它是保證系統穩定運行的基礎,而保證系統能穩定運行后,又有低功耗的要求。在很多應用場合中都對電子設備的功耗要求非常苛刻,如某些傳感器信息采集設備,僅靠小型的電池提供電源,要求工作長達數年之久,且期間不需要任何維護;由於智慧穿戴設備的小型化要求,電池體積不能太大導致容量也比較小,所以也很有必要從控制功耗入手,提高設備的續行時間。因此,STM32有專門的電源管理外設監控電源並管理設備的運行模式,確保系統正常運行,並盡量降低器件的功耗。
42.1.1 電源監控器
STM32芯片主要通過引腳VDD從外部獲取電源,在它的內部具有電源監控器用於檢測VDD的電壓,以實現復位功能及掉電緊急處理功能,保證系統可靠地運行。
1. 上電復位與掉電復位(POR與PDR)
當檢測到VDD的電壓低於閾值VPOR及VPDR時,無需外部電路輔助,STM32芯片會自動保持在復位狀態,防止因電壓不足強行工作而帶來嚴重的后果。見圖 421,在剛開始電壓低於VPOR時(約1.72V),STM32保持在上電復位狀態(POR,Power On Reset),當VDD電壓持續上升至大於VPOR時,芯片開始正常運行,而在芯片正常運行的時候,當檢測到VDD電壓下降至低於VPDR閾值(約1.68V),會進入掉電復位狀態(PDR,Power Down Reset)。

圖 421 POR與PDR
2. 欠壓復位(BOR)
POR與PDR的復位電壓閾值是固定的,如果用戶想要自行設定復位閾值,可以使用STM32的BOR功能(Brownout Reset)。它可以編程控制電壓檢測工作在表 421中的閾值級別,通過修改"選項字節"(某些特殊寄存器)中的BOR_LEV位即可控制閾值級別。其復位控制示意圖見圖 422。
表 421 BOR欠壓閾值等級
| 等級 |
條件 |
電壓值 |
| 1級欠壓閾值 |
下降沿 |
2.19V |
| 上升沿 |
2.29V |
|
| 2級欠壓閾值 |
下降沿 |
2.50V |
| 上升沿 |
2.59V |
|
| 3級欠壓閾值 |
下降沿 |
2.83V |
| 上升沿 |
2.92V |

圖 422 BOR復位控制
3. 可編程電壓檢測器PVD
上述POR、PDR以及BOR功能都是使用其電壓閾值與外部供電電壓VDD比較,當低於工作閾值時,會直接進入復位狀態,這可防止電壓不足導致的誤操作。除此之外,STM32還提供了可編程電壓檢測器PVD,它也是實時檢測VDD的電壓,當檢測到電壓低於VPVD閾值時,會向內核產生一個PVD中斷(EXTI16線中斷)以使內核在復位前進行緊急處理。該電壓閾值可通過電源控制寄存器PWR_CSR設置。
使用PVD可配置8個等級,見表 422。其中的上升沿和下降沿分別表示類似圖 422中VDD電壓上升過程及下降過程的閾值。
表 422 PVD的閾值等級
| 閾值等級 |
條件 |
最小值 |
典型值 |
最大值 |
單位 |
| 級別0 |
上升沿 |
2.09 |
2.14 |
2.19 |
V |
| 下降沿 |
1.98 |
2.04 |
2.08 |
V |
|
| 級別1 |
上升沿 |
2.23 |
2.3 |
2.37 |
V |
| 下降沿 |
2.13 |
2.19 |
2.25 |
V |
|
| 級別2 |
上升沿 |
2.39 |
2.45 |
2.51 |
V |
| 下降沿 |
2.29 |
2.35 |
2.39 |
V |
|
| 級別3 |
上升沿 |
2.54 |
2.6 |
2.65 |
V |
| 下降沿 |
2.44 |
2.51 |
2.56 |
V |
|
| 級別4 |
上升沿 |
2.7 |
2.76 |
2.82 |
V |
| 下降沿 |
2.59 |
2.66 |
2.71 |
V |
|
| 級別5 |
上升沿 |
2.86 |
2.93 |
2.99 |
V |
| 下降沿 |
2.65 |
2.84 |
3.02 |
V |
|
| 級別6 |
上升沿 |
2.96 |
3.03 |
3.1 |
V |
| 下降沿 |
2.85 |
2.93 |
2.99 |
V |
|
| 級別7 |
上升沿 |
3.07 |
3.14 |
3.21 |
V |
| 下降沿 |
2.95 |
3.03 |
3.09 |
V |
42.1.2 STM32的電源系統
為了方便進行電源管理,STM32把它的外設、內核等模塊跟據功能划分了供電區域,其內部電源區域划分見圖 423。

圖 423 STM32的電源系統
從框圖了解到,STM32的電源系統主要分為備份域電路、內核電路以及ADC電路三部分,介紹如下:
備份域電路
STM32的LSE振盪器、RTC、備份寄存器及備份SRAM這些器件被包含進備份域電路中,這部分的電路可以通過STM32的VBAT引腳獲取供電電源,在實際應用中一般會使用3V的鈕扣電池對該引腳供電。
在圖中備份域電路的左側有一個電源開關結構,它的功能類似圖 424中的雙二極管,在它的上方連接了VBAT電源,下方連接了VDD主電源(一般為3.3V),右側引出到備份域電路中。當VDD主電源存在時,由於VDD電壓較高,備份域電路通過VDD供電,當VDD掉電時,備份域電路由鈕扣電池通過VBAT供電,保證電路能持續運行,從而可利用它保留關鍵數據。

圖 424 雙二極管結構
調壓器供電電路
在STM32的電源系統中調壓器供電的電路是最主要的部分,調壓器為備份域及待機電路以外的所有數字電路供電,其中包括內核、數字外設以及RAM,調壓器的輸出電壓約為1.2V,因而使用調壓器供電的這些電路區域被稱為1.2V域。
調壓器可以運行在"運行模式"、"停止模式"以及"待機模式"。在運行模式下,1.2V域全功率運行;在停止模式下1.2V域運行在低功耗狀態,1.2V區域的所有時鍾都被關閉,相應的外設都停止了工作,但它會保留內核寄存器以及SRAM的內容;在待機模式下,整個1.2V域都斷電,該區域的內核寄存器及SRAM內容都會丟失(備份區域的寄存器及SRAM不受影響)。
ADC電源及參考電壓
為了提高轉換精度,STM32的ADC配有獨立的電源接口,方便進行單獨的濾波。ADC的工作電源使用VDDA引腳輸入,使用VSSA作為獨立的地連接,VREF引腳則為ADC提供測量使用的參考電壓。
42.1.3 STM32的功耗模式
按功耗由高到低排列,STM32具有運行、睡眠、停止和待機四種工作模式。上電復位后STM32處於運行狀態時,當內核不需要繼續運行,就可以選擇進入后面的三種低功耗模式降低功耗,這三種模式中,電源消耗不同、喚醒時間不同、喚醒源不同,用戶需要根據應用需求,選擇最佳的低功耗模式。三種低功耗的模式說明見表 423。
表 423STM32的低功耗模式說明
| 模式 |
說明 |
進入方式 |
喚醒方式 |
對1.2V區域時鍾的影響 |
對VDD區域時鍾的影響 |
調壓器 |
| 睡眠 |
內核停止,所有外設包括M4核心的外設,如NVIC、系統時鍾(SysTick)等仍在運行 |
調用WFI命令 |
任一中斷 |
內核時鍾關,對其他時鍾和ADC時鍾無影響 |
無 |
開 |
| 調用WFE命令 |
喚醒事件 |
|||||
| 停止 |
所有的時鍾都已停止 |
配置PWR_CR寄存器的PDDS +LPDS 位+SLEEPDEEP位 +WFI或WFE命令 |
任一外部中斷( 在外部中斷寄存器中設置) |
關閉所有1.2V區域的時鍾 |
HSI和HSE的振盪器關閉 |
開啟或處於低功耗模式( 依據電源控制寄存器的設定) |
| 待機 |
1.2V 電源關閉 |
配置PWR_CR寄存器的PDDS +SLEEPDEEP位 +WFI或WFE命令 |
WKUP 引腳的上升沿、RTC鬧鍾事件、NRST 引腳上的外部復位、IWDG 復位 |
關 |
從表中可以看到,這三種低功耗模式層層遞進,運行的時鍾或芯片功能越來越少,因而功耗越來越低。
1. 睡眠模式
在睡眠模式中,僅關閉了內核時鍾,內核停止運行,但其片上外設,CM4核心的外設全都還照常運行。有兩種方式進入睡眠模式,它的進入方式決定了從睡眠喚醒的方式,分別是WFI(wait for interrupt)和WFE(wait for event),即由等待"中斷"喚醒和由"事件"喚醒。睡眠模式的各種特性見表 424。
表 424 睡眠模式的各種特性
| 特性 |
說明 |
| 立即睡眠 |
在執行WFI 或WFE 指令時立即進入睡眠模式。 |
| 退出時睡眠 |
在退出優先級最低的中斷服務程序后才進入睡眠模式。 |
| 進入方式 |
內核寄存器的SLEEPDEEP = 0 ,然后調用WFI或WFE指令即可進入睡眠模式; 另外若內核寄存器的SLEEPONEXIT=0時,進入"立即睡眠"模式,SLEEPONEXIT=1時,進入"退出時睡眠"模式。 |
| 喚醒方式 |
如果是使用WFI指令睡眠的,則可使用任意中斷喚醒; 如果是使用WFE指令睡眠的,則由事件喚醒。 |
| 睡眠時 |
關閉內核時鍾,內核停止,而外設正常運行,在軟件上表現為不再執行新的代碼。這個狀態會保留睡眠前的內核寄存器、內存的數據。 |
| 喚醒延遲 |
無延遲。 |
| 喚醒后 |
若由中斷喚醒,先進入中斷,退出中斷服務程序后,接着執行WFI指令后的程序;若由事件喚醒,直接接着執行WFE后的程序。 |
2. 停止模式
在停止模式中,進一步關閉了其它所有的時鍾,於是所有的外設都停止了工作,但由於其1.2V區域的部分電源沒有關閉,還保留了內核的寄存器、內存的信息,所以從停止模式喚醒,並重新開啟時鍾后,還可以從上次停止處繼續執行代碼。停止模式可以由任意一個外部中斷(EXTI)喚醒。在停止模式中可以選擇電壓調節器為開模式或低功耗模式,可選擇內部FLASH工作在正常模式或掉電模式。停止模式的各種特性見表 425。
表 425 停止模式的各種特性
| 特性 |
說明 |
| 調壓器低功耗模式 |
在停止模式下調壓器可工作在正常模式或低功耗模式,可進一步降低功耗 |
| FLASH掉電模式 |
在停止模式下FLASH可工作在正常模式或掉電模式,可進一步降低功耗 |
| 進入方式 |
內核寄存器的SLEEPDEEP =1,PWR_CR寄存器中的PDDS=0,然后調用WFI或WFE指令即可進入停止模式; PWR_CR 寄存器的LPDS=0時,調壓器工作在正常模式,LPDS=1時工作在低功耗模式; PWR_CR 寄存器的FPDS=0時,FLASH工作在正常模式,FPDS=1時進入掉電模式。 |
| 喚醒方式 |
如果是使用WFI指令睡眠的,可使用任意EXTI線的中斷喚醒; 如果是使用WFE指令睡眠的,可使用任意配置為事件模式的EXTI線事件喚醒。 |
| 停止時 |
內核停止,片上外設也停止。這個狀態會保留停止前的內核寄存器、內存的數據。 |
| 喚醒延遲 |
基礎延遲為HSI振盪器的啟動時間,若調壓器工作在低功耗模式,還需要加上調壓器從低功耗切換至正常模式下的時間,若FLASH工作在掉電模式,還需要加上FLASH從掉電模式喚醒的時間。 |
| 喚醒后 |
若由中斷喚醒,先進入中斷,退出中斷服務程序后,接着執行WFI指令后的程序;若由事件喚醒,直接接着執行WFE后的程序。喚醒后,STM32會使用HIS作為系統時鍾。 |
3. 待機模式
待機模式,它除了關閉所有的時鍾,還把1.2V區域的電源也完全關閉了,也就是說,從待機模式喚醒后,由於沒有之前代碼的運行記錄,只能對芯片復位,重新檢測boot條件,從頭開始執行程序。它有四種喚醒方式,分別是WKUP(PA0)引腳的上升沿,RTC鬧鍾事件,NRST引腳的復位和IWDG(獨立看門狗)復位。
表 426 待機模式的各種特性
| 特性 |
說明 |
| 進入方式 |
內核寄存器的SLEEPDEEP =1,PWR_CR寄存器中的PDDS=1,PWR_CR寄存器中的喚醒狀態位WUF=0,然后調用WFI或WFE指令即可進入待機模式; |
| 喚醒方式 |
通過WKUP引腳的上升沿,RTC鬧鍾、喚醒、入侵、時間戳事件或NRST引腳外部復位及IWDG復位喚醒。 |
| 待機時 |
內核停止,片上外設也停止;內核寄存器、內存的數據會丟失;除復位引腳、RTC_AF1引腳及WKUP引腳,其它I/O口均工作在高阻態。 |
| 喚醒延遲 |
芯片復位的時間 |
| 喚醒后 |
相當於芯片復位,在程序表現為從頭開始執行代碼。 |
在以上講解的睡眠模式、停止模式及待機模式中,若備份域電源正常供電,備份域內的RTC都可以正常運行、備份域內的寄存器及備份域內的SRAM數據會被保存,不受功耗模式影響。
42.2 電源管理相關的庫函數及命令
STM32標准庫對電源管理提供了完善的函數及命令,使用它們可以方便地進行控制,本小節對這些內容進行講解。
42.2.1 配置PVD監控功能
PVD可監控VDD的電壓,當它低於閾值時可產生PVD中斷以讓系統進行緊急處理,這個閾值可以直接使用庫函數PWR_PVDLevelConfig配置成前面表 422中說明的閾值等級。
42.2.2 WFI與WFE命令
我們了解到進入各種低功耗模式時都需要調用WFI或WFE命令,它們實質上都是內核指令,在庫文件core_cmInstr.h中把這些指令封裝成了函數,見代碼清單 241。
代碼清單 421 WFI與WFE的指令定義(core_cmInstr.h文件)
1
2 /** \brief Wait For Interrupt
3
4 Wait For Interrupt is a hint instruction that suspends execution
5 until one of a number of events occurs.
6 */
7 #define __WFI __wfi
8
9
10 /** \brief Wait For Event
11
12 Wait For Event is a hint instruction that permits the processor to enter
13 a low-power state until one of a number of events occurs.
14 */
15 #define __WFE __wfe
對於這兩個指令,我們應用時一般只需要知道,調用它們都能進入低功耗模式,需要使用函數的格式"__WFI();"和"__WFE();"來調用(因為__wfi及__wfe是編譯器內置的函數,函數內部使用調用了相應的匯編指令)。其中WFI指令決定了它需要用中斷喚醒,而WFE則決定了它可用事件來喚醒,關於它們更詳細的區別可查閱《cortex-CM3/CM4權威指南》了解。
42.2.3 進入停止模式
直接調用WFI和WFE指令可以進入睡眠模式,而進入停止模式則還需要在調用指令前設置一些寄存器位,STM32標准庫把這部分的操作封裝到PWR_EnterSTOPMode函數中了,它的定義見代碼清單 402。
代碼清單 422 進入停止模式
1 /**
2 * @brief 進入停止模式
3 *
4 * @note 在停止模式下所有I/O的會保持在停止前的狀態
5 * @note 從停止模式喚醒后,會使用HSI作為時鍾源
6 * @note 調壓器若工作在低功耗模式,可減少功耗,但喚醒時會增加延遲
7 * @param PWR_Regulator: 設置停止模式時調壓器的工作模式
8 * @arg PWR_MainRegulator_ON: 調壓器正常運行
9 * @arg PWR_LowPowerRegulator_ON: 調壓器低功耗運行
10 * @param PWR_STOPEntry: 設置使用WFI還是WFE進入停止模式
11 * @arg PWR_STOPEntry_WFI: WFI進入停止模式
12 * @arg PWR_STOPEntry_WFE: WFE進入停止模式
13 * @retval None
14 */
15 void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry)
16 {
17 uint32_t tmpreg = 0;
18
19 /* 設置調壓器的模式 ------------*/
20 tmpreg = PWR->CR;
21 /* 清除 PDDS 及 LPDS 位 */
22 tmpreg &= CR_DS_MASK;
23
24 /* 根據PWR_Regulator 的值(調壓器工作模式)配置LPDS,MRLVDS及LPLVDS位 */
25 tmpreg |= PWR_Regulator;
26
27 /* 寫入參數值到寄存器 */
28 PWR->CR = tmpreg;
29
30 /* 設置內核寄存器的SLEEPDEEP位 */
31 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
32
33 /* 設置進入停止模式的方式-----------------*/
34 if (PWR_STOPEntry == PWR_STOPEntry_WFI) {
35 /* 需要中斷喚醒*/
36 __WFI();
37 } else {
38 /* 需要事件喚醒 */
39 __WFE();
40 }
41 /* 以下的程序是當重新喚醒時才執行的,清除SLEEPDEEP位的狀態*/
42 SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
43 }
這個函數有兩個輸入參數,分別用於控制調壓器的模式及選擇使用WFI或WFE停止,代碼中先是根據調壓器的模式配置PWR_CR寄存器,再把內核寄存器的SLEEPDEEP位置1,這樣再調用WFI或WFE命令時,STM32就不是睡眠,而是進入停止模式了。函數結尾處的語句用於復位SLEEPDEEP位的狀態,由於它是在WFI及WFE指令之后的,所以這部分代碼是在STM32被喚醒的時候才會執行。
要注意的是進入停止模式后,STM32的所有I/O都保持在停止前的狀態,而當它被喚醒時,STM32使用HSI作為系統時鍾(16MHz)運行,由於系統時鍾會影響很多外設的工作狀態,所以一般我們在喚醒后會重新開啟HSE,把系統時鍾設置會原來的狀態。
前面提到在停止模式中還可以控制內部FLASH的供電,控制FLASH是進入掉電狀態還是正常供電狀態,這可以使用庫函數PWR_FlashPowerDownCmd配置,它其實只是封裝了一個對FPDS寄存器位操作的語句,見代碼清單 423。這個函數需要在進入停止模式前被調用,即應用時需要把它放在上面的PWR_EnterSTOPMode之前。
代碼清單 423 控制FLASH的供電狀態
1 /**
2 * @brief 設置內部FLASH在停止模式時是否工作在掉電狀態
3 * 掉電狀態可使功耗更低,但喚醒時會增加延遲
4 * @param NewState:
5 ENABLE:FLASH掉電
6 DISABLE:FLASH正常運行
7 * @retval None
8 */
9 void PWR_FlashPowerDownCmd(FunctionalState NewState)
10 {
11 /*配置FPDS寄存器位*/
12 *(__IO uint32_t *) CR_FPDS_BB = (uint32_t)NewState;
13 }
42.2.4 進入待機模式
類似地,STM32標准庫也提供了控制進入待機模式的函數,其定義見代碼清單 403。
代碼清單 424 進入待機模式
1 /**
2 * @brief 進入待機模式
3 * @note 待機模式時,除以下引腳,其余引腳都在高阻態:
4 * -復位引腳
5 * - RTC_AF1 引腳 (PC13) (需要使能侵入檢測、時間戳事件或RTC鬧鍾事件)
6 * - RTC_AF2 引腳 (PI8) (需要使能侵入檢測或時間戳事件)
7 * - WKUP 引腳 (PA0) (需要使能WKUP喚醒功能)
8 * @note 在調用本函數前還需要清除WUF寄存器位
9 * @param None
10 * @retval None
11 */
12 void PWR_EnterSTANDBYMode(void)
13 {
14 /* 選擇待機模式 */
15 PWR->CR |= PWR_CR_PDDS;
16
17 /* 設置內核寄存器的SLEEPDEEP位 */
18 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
19
20 /* 存儲操作完畢時才能進入待機模式,使用以下語句確保存儲操作執行完畢 */
21
22 __force_stores();
23
24 /* 等待中斷喚醒 */
25 __WFI();
26 }
該函數中先配置了PDDS寄存器位及SLEEPDEEP寄存器位,接着調用__force_stores函數確保存儲操作完畢后再調用WFI指令,從而進入待機模式。這里值得注意的是,待機模式也可以使用WFE指令進入的,如果您有需要可以自行修改;另外,由於這個函數沒有操作WUF寄存器位,所以在實際應用中,調用本函數前,還需要清空WUF寄存器位才能進入待機模式。
在進入待機模式后,除了被使能了的用於喚醒的I/O,其余I/O都進入高阻態,而從待機模式喚醒后,相當於復位STM32芯片,程序重新從頭開始執行。
42.3 PWR—睡眠模式實驗
在本小節中,我們以實驗的形式講解如何控制STM32進入低功耗睡眠模式。
42.3.1 硬件設計
實驗中的硬件主要使用到了按鍵、LED彩燈以及使用串口輸出調試信息,這些硬件都與前面相應實驗中的一致,涉及到硬件設計的可參考原理圖或前面章節中的內容。
42.3.2 軟件設計
本小節講解的是"PWR—睡眠模式"實驗,請打開配套的代碼工程閱讀理解。
1. 程序設計要點
(1) 初始化用於喚醒的中斷按鍵;
(2) 進入睡眠狀態;
(3) 使用按鍵中斷喚醒芯片;
2. 代碼分析
main函數
睡眠模式的程序比較簡單,我們直接閱讀它的main函數了解執行流程,見代碼清單 242。
代碼清單 425 睡眠模式的main函數(main.c文件)
1
2 /**
3 * @brief 主函數
4 * @param 無
5 * @retval 無
6 */
7 int main(void)
8 {
9
10 LED_GPIO_Config();
11
12 /*初始化USART1*/
13 Debug_USART_Config();
14
15 /* 初始化按鍵為中斷模式,按下中斷后會進入中斷服務函數 */
16 EXTI_Key_Config();
17
18 printf("\r\n歡迎使用秉火 STM32 F429 開發板。\r\n");
19 printf("\r\n秉火F429 睡眠模式例程\r\n");
20
21 printf("\r\n實驗說明:\r\n");
22
23 printf("\r\n 1.本程序中,綠燈表示STM32正常運行,紅燈表示睡眠狀態,藍燈表示剛從睡眠狀態被喚醒\r\n");
24 printf("\r\n 2.程序運行一段時間后自動進入睡眠狀態,在睡眠狀態下,可使用KEY1或KEY2喚醒\r\n");
25 printf("\r\n 3.本實驗執行這樣一個循環:\r\n");
26printf("\r\n --》亮綠燈(正常運行)->亮紅燈(睡眠模式)->按KEY1或KEY2喚醒->亮藍燈(剛被喚醒)--》\r\n");
27 printf("\r\n 4.在睡眠狀態下,DAP下載器無法給STM32下載程序,\r\n");
28 printf("\r\n可按KEY1、KEY2喚醒后下載,\r\n");
29 printf("\r\n或按復位鍵使芯片處於復位狀態,然后在電腦上點擊下載按鈕,再釋放復位按鍵,即可下載\r\n");
30
31 while (1) {
32 /*********執行任務***************************/
33 printf("\r\n STM32正常運行,亮綠燈\r\n");
34
35 LED_GREEN;
36 Delay(0x3FFFFFF);
37
38 /*****任務執行完畢,進入睡眠降低功耗***********/
39
40
41 printf("\r\n進入睡眠模式,按KEY1或KEY2按鍵可喚醒\r\n");
42
43 //使用紅燈指示,進入睡眠狀態
44 LED_RED;
45 //進入睡眠模式
46 __WFI(); //WFI指令進入睡眠
47
48 //等待中斷喚醒 K1或K2按鍵中斷
49
50 /***被喚醒,亮藍燈指示***/
51 LED_BLUE;
52 Delay(0x1FFFFFF);
53
54 printf("\r\n已退出睡眠模式\r\n");
55 //繼續執行while循環
56 }
57 }
這個main函數的執行流程見圖 425。

圖 425 睡眠模式實驗流程圖
(1) 程序中首先初始化了LED燈及串口以便用於指示芯片的運行狀態,並且把實驗板上的兩個按鍵都初始化成了中斷模式,以便當系統進入睡眠模式的時候可以通過按鍵來喚醒。這些硬件的初始化過程都跟前面章節中的一模一樣。
(2) 初始化完成后使用LED及串口表示運行狀態,在本實驗中,LED彩燈為綠色時表示正常運行,紅燈時表示睡眠狀態,藍燈時表示剛從睡眠狀態中被喚醒。
(3) 程序執行一段時間后,直接使用WFI指令進入睡眠模式,由於WFI睡眠模式可以使用任意中斷喚醒,所以我們可以使用按鍵中斷喚醒。
(4) 當系統進入停止狀態后,我們按下實驗板上的KEY1或KEY2按鍵,即可使系統回到正常運行的狀態,當執行完中斷服務函數后,會繼續執行WFI指令后的代碼。
中斷服務函數
系統剛被喚醒時會進入中斷服務函數,見代碼清單 243。
代碼清單 426 按鍵中斷的服務函數(stm32f4xx_it.c文件)
1
2 void KEY1_IRQHandler(void)
3 {
4 //確保是否產生了EXTI Line中斷
5 if (EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) {
6 LED_BLUE;
7 printf("\r\n KEY1 按鍵中斷喚醒 \r\n");
8 EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
9 }
10 }
11
12 void KEY2_IRQHandler(void)
13 {
14 //確保是否產生了EXTI Line中斷
15 if (EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) {
16 LED_BLUE;
17 printf("\r\n KEY2 按鍵中斷喚醒 \r\n");
18 //清除中斷標志位
19 EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
20 }
21 }
用於喚醒睡眠模式的中斷,其中斷服務函數也沒有特殊要求,跟普通的應用一樣。
42.3.3 下載驗證
下載這個實驗測試時,可連接上串口,在電腦端的串口調試助手獲知調試信息。當系統進入睡眠狀態的時候,可以按KEY1或KEY2按鍵喚醒系統。
注意:
當系統處於睡眠模式低功耗狀態時(包括后面講解的停止模式及待機模式),使用DAP下載器是無法給芯片下載程序的,所以下載程序時要先把系統喚醒。或者使用如下方法:按着板子的復位按鍵,使系統處於復位狀態,然后點擊電腦端的下載按鈕下載程序,這時再釋放復位按鍵,就能正常給板子下載程序了。
42.4 PWR—停止模式實驗
在睡眠模式實驗的基礎上,我們進一步講解如何進入停止模式及喚醒后的狀態恢復。
42.4.1 硬件設計
本實驗中的硬件與睡眠模式中的一致,主要使用到了按鍵、LED彩燈以及使用串口輸出調試信息。
42.4.2 軟件設計
本小節講解的是"PWR—停止模式"實驗,請打開配套的代碼工程閱讀理解。
1. 程序設計要點
(1) 初始化用於喚醒的中斷按鍵;
(2) 設置停止狀態時的FLASH供電或掉電;
(3) 選擇電壓調節器的工作模式並進入停止狀態;
(4) 使用按鍵中斷喚醒芯片;
(5) 重啟HSE時鍾,使系統完全恢復停止前的狀態。
2. 代碼分析
重啟HSE時鍾
與睡眠模式不一樣,系統從停止模式被喚醒時,是使用HSI作為系統時鍾的,在STM32F429中,HSI時鍾一般為16MHz,與我們常用的180MHz相關太遠,它會影響各種外設的工作頻率。所以在系統從停止模式喚醒后,若希望各種外設恢復正常的工作狀態,就要恢復停止模式前使用的系統時鍾,本實驗中定義了一個SYSCLKConfig_STOP函數,用於恢復系統時鍾,它的定義見代碼清單 243。
代碼清單 427 恢復系統時鍾(main.c文件)
1 /**
2 * @brief 停機喚醒后配置系統時鍾: 使能 HSE, PLL
3 * 並且選擇PLL作為系統時鍾.
4 * @param None
5 * @retval None
6 */
7 static void SYSCLKConfig_STOP(void)
8 {
9 /* After wake-up from STOP reconfigure the system clock */
10 /* 使能 HSE */
11 RCC_HSEConfig(RCC_HSE_ON);
12
13 /* 等待 HSE 准備就緒 */
14 while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);
15
16 /* 使能 PLL */
17 RCC_PLLCmd(ENABLE);
18
19 /* 等待 PLL 准備就緒 */
20 while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
21
22 /* 選擇PLL作為系統時鍾源 */
23 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
24
25 /* 等待PLL被選擇為系統時鍾源 */
26 while (RCC_GetSYSCLKSource() != 0x08);
27 }
這個函數主要是調用了各種RCC相關的庫函數,開啟了HSE時鍾、使能PLL並且選擇PLL作為時鍾源,從而恢復停止前的時鍾狀態。
main函數
停止模式實驗的main函數流程與睡眠模式的類似,主要是調用指令方式的不同及喚醒后增加了恢復時鍾的操作,見代碼清單 242。
代碼清單 428 停止模式的main函數(main.c文件)
1
2 /**
3 * @brief 主函數
4 * @param 無
5 * @retval 無
6 */
7 int main(void)
8 {
9 LED_GPIO_Config();
10
11 /*初始化USART1*/
12 Debug_USART_Config();
13
14 /* 初始化按鍵為中斷模式,按下中斷后會進入中斷服務函數 */
15 EXTI_Key_Config();
16
17 printf("\r\n歡迎使用秉火 STM32 F429 開發板。\r\n");
18 printf("\r\n秉火F429 停止模式例程\r\n");
19
20 printf("\r\n實驗說明:\r\n");
21
22 printf("\r\n 1.本程序中,綠燈表示STM32正常運行,紅燈表示停止狀態,藍燈表示剛從停止狀態被喚醒\r\n");
23 printf("\r\n 2.程序運行一段時間后自動進入停止狀態,在停止狀態下,可使用KEY1或KEY2喚醒\r\n");
24 printf("\r\n 3.本實驗執行這樣一個循環:\r\n");
25printf("\r\n --》亮綠燈(正常運行)->亮紅燈(停止模式)->按KEY1或KEY2喚醒->亮藍燈(剛被喚醒)---》\r\n");
26 printf("\r\n 4.在停止狀態下,DAP下載器無法給STM32下載程序,\r\n");
27 printf("\r\n可按KEY1、KEY2喚醒后下載,\r\n");
28 printf("\r\n或按復位鍵使芯片處於復位狀態,然后在電腦上點擊下載按鈕,再釋放復位按鍵,即可下載\r\n");
29
30 while (1) {
31 /*********執行任務***************************/
32 printf("\r\n STM32正常運行,亮綠燈\r\n");
33
34 LED_GREEN;
35 Delay(0x3FFFFFF);
36
37 /*****任務執行完畢,進入停止降低功耗***********/
38
39 printf("\r\n進入停止模式,按KEY1或KEY2按鍵可喚醒\r\n");
40
41 //使用紅燈指示,進入停止狀態
42 LED_RED;
43
44 /*設置停止模式時,FLASH進入掉電狀態*/
45 PWR_FlashPowerDownCmd (ENABLE);
46 /* 進入停止模式,設置電壓調節器為低功耗模式,等待中斷喚醒 */
47 PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);
48
49 //等待中斷喚醒 K1或K2按鍵中斷
50 /*********************被喚醒***********************/
51 //獲取剛被喚醒時的時鍾狀態
52 //時鍾源
53 clock_source_wakeup = RCC_GetSYSCLKSource ();
54 //時鍾頻率
55 RCC_GetClocksFreq(&clock_status_wakeup);
56
57 //從停止模式下被喚醒后使用的是HSI時鍾,此處重啟HSE時鍾,使用PLLCLK
58 SYSCLKConfig_STOP();
59
60 //獲取重新配置后的時鍾狀態
61 //時鍾源
62 clock_source_config = RCC_GetSYSCLKSource ();
63 //時鍾頻率
64 RCC_GetClocksFreq(&clock_status_config);
65
66 //因為剛喚醒的時候使用的是HSI時鍾,會影響串口波特率,輸出不對,所以在重新配置時鍾源后才使用串口輸出。
67 printf("\r\n重新配置后的時鍾狀態:\r\n");
68 printf(" SYSCLK頻率:%d,\r\n HCLK頻率:%d,\r\n PCLK1頻率:%d,\r\n PCLK2頻率:%d,\r\n時鍾源:%d (0表示HSI,8表示PLLCLK)\n",
69 clock_status_config.SYSCLK_Frequency,
70 clock_status_config.HCLK_Frequency,
71 clock_status_config.PCLK1_Frequency,
72 clock_status_config.PCLK2_Frequency,
73 clock_source_config);
74
75 printf("\r\n剛喚醒的時鍾狀態:\r\n");
76 printf(" SYSCLK頻率:%d,\r\n HCLK頻率:%d,\r\n PCLK1頻率:%d,\r\n PCLK2頻率:%d,\r\n時鍾源:%d (0表示HSI,8表示PLLCLK)\n",
77 clock_status_wakeup.SYSCLK_Frequency,
78 clock_status_wakeup.HCLK_Frequency,
79 clock_status_wakeup.PCLK1_Frequency,
80 clock_status_wakeup.PCLK2_Frequency,
81 clock_source_wakeup);
82
83 /*指示燈*/
84 LED_BLUE;
85 Delay(0x1FFFFFF);
86
87 printf("\r\n已退出停止模式\r\n");
88 //繼續執行while循環
89 }
90 }
這個main函數的執行流程見圖 425。

圖 426 停止模式實驗流程圖
(1) 程序中首先初始化了LED燈及串口以便用於指示芯片的運行狀態,並且把實驗板上的兩個按鍵都初始化成了中斷模式,以便當系統進入停止模式的時候可以通過按鍵來喚醒。這些硬件的初始化過程都跟前面章節中的一模一樣。
(2) 初始化完成后使用LED及串口表示運行狀態,在本實驗中,LED彩燈為綠色時表示正常運行,紅燈時表示停止狀態,藍燈時表示剛從停止狀態中被喚醒。在停止模式下,I/O口會保持停止前的狀態,所以LED彩燈在停止模式時也會保持亮紅燈。
(3) 程序執行一段時間后,我們先用庫函數PWR_FlashPowerDownCmd設置FLASH的在停止狀態時使用掉電模式,接着調用庫函數PWR_EnterSTOPMode把調壓器設置在低功耗模式,並使用WFI指令進入停止狀態。由於WFI停止模式可以使用任意EXTI的中斷喚醒,所以我們可以使用按鍵中斷喚醒。
(4) 當系統進入睡眠狀態后,我們按下實驗板上的KEY1或KEY2按鍵,即可喚醒系統,當執行完中斷服務函數后,會繼續執行WFI指令(即PWR_EnterSTOPMode函數)后的代碼。
(5) 為了更清晰地展示停止模式的影響,在剛喚醒后,我們調用了庫函數RCC_GetSYSCLKSource以及RCC_GetClocksFreq獲取剛喚醒后的系統的時鍾源以及時鍾頻率,在使用SYSCLKConfig_STOP恢復時鍾后,我們再次獲取這些時狀態,最后再通過串口打印出來。
(6) 通過串口調試信息我們會知道剛喚醒時系統時鍾使用的是HIS時鍾,頻率為16MHz,恢復后的系統時鍾采用HSE倍頻后的PLL時鍾,時鍾頻率為180MHz。
42.4.3 下載驗證
下載這個實驗測試時,可連接上串口,在電腦端的串口調試助手獲知調試信息。當系統進入停止狀態的時候,可以按KEY1或KEY2按鍵喚醒系統。
注意:
當系統處於停止模式低功耗狀態時(包括睡眠模式及待機模式),使用DAP下載器是無法給芯片下載程序的,所以下載程序時要先把系統喚醒。或者使用如下方法:按着板子的復位按鍵,使系統處於復位狀態,然后點擊電腦端的下載按鈕下載程序,這時再釋放復位按鍵,就能正常給板子下載程序了。
42.5 PWR—待機模式實驗
最后我們來學習最低功耗的待機模式。
42.5.1 硬件設計
本實驗中的硬件與睡眠模式、停止模式中的一致,主要使用到了按鍵、LED彩燈以及使用串口輸出調試信息。要強調的是,由於WKUP引腳(PA0)必須使用上升沿才能喚醒待機狀態的系統,所以我們硬件設計的PA0引腳連接到按鍵KEY1,且按下按鍵的時候會在PA0引腳產生上升沿,從而可實現喚醒的功能,按鍵的具體電路請查看配套的原理圖。
42.5.2 軟件設計
本小節講解的是"PWR—待機模式"實驗,請打開配套的代碼工程閱讀理解。
1. 程序設計要點
(1) 清除WUF標志位;
(2) 使能WKUP喚醒功能;
(3) 進入待機狀態。
2. 代碼分析
main函數
待機模式實驗的執行流程比較簡單,見代碼清單 242。
代碼清單 429 停止模式的main函數(main.c文件)
1
2 /**
3 * @brief 主函數
4 * @param 無
5 * @retval 無
6 */
7 int main(void)
8 {
9 LED_GPIO_Config();
10
11 /*初始化USART1*/
12 Debug_USART_Config();
13
14 /*初始化按鍵,不需要中斷,僅初始化KEY2即可,只用於喚醒的PA0引腳不需要這樣初始化*/
15 Key_GPIO_Config();
16
17 printf("\r\n歡迎使用秉火 STM32 F429 開發板。\r\n");
18 printf("\r\n秉火F429 待機模式例程\r\n");
19
20 printf("\r\n實驗說明:\r\n");
21
22 printf("1.綠燈表示本次復位是上電或引腳復位,紅燈表示即將進入待機狀態,藍燈表示本次是待機喚醒的復位\r\n");
23 printf("\r\n 2.長按KEY2按鍵后,會進入待機模式\r\n");
24 printf("\r\n 3.在待機模式下,按KEY1按鍵可喚醒,喚醒后系統會進行復位,程序從頭開始執行\r\n");
25 printf("\r\n 4.可通過檢測WU標志位確定復位來源\r\n");
26
27 printf("\r\n 5.在待機狀態下,DAP下載器無法給STM32下載程序,需要喚醒后才能下載");
28
29 //檢測復位來源
30 if (PWR_GetFlagStatus(PWR_FLAG_WU) == SET) {
31 LED_BLUE;
32 printf("\r\n待機喚醒復位 \r\n");
33 } else {
34 LED_GREEN;
35 printf("\r\n非待機喚醒復位 \r\n");
36 }
37 while (1) {
38 // K2 按鍵長按進入待機模式
39 if (KEY2_LongPress()) {
40
41 printf("\r\n即將進入待機模式,進入待機模式后可按KEY1喚醒,喚醒后會進行復位,程序從頭開始執行\r\n");
42 LED_RED;
43 Delay(0xFFFFFF);
44 /*清除WU狀態位*/
45 PWR_ClearFlag (PWR_FLAG_WU);
46
47 /* 使能WKUP引腳的喚醒功能,使能PA0*/
48 PWR_WakeUpPinCmd (ENABLE);
49
50 /* 進入待機模式 */
51 PWR_EnterSTANDBYMode();
52 }
53 }
54 }
這個main函數的執行流程見圖 425。

圖 427 待機模式實驗流程圖
(1) 程序中首先初始化了LED燈及串口以便用於指示芯片的運行狀態,由於待機模式喚醒使用WKUP引腳並不需要特別的引腳初始化,所以我們調用的按鍵初始化函數Key_GPIO_Config它的內部只初始化了KEY2按鍵,而且是普通的輸入模式,對喚醒用的PA0引腳可以不初始化。當然,如果不初始化PA0的話,在正常運行模式中KEY1按鍵是不能正常運行的,我們這里只是強調待機模式的WKUP喚醒不需要中斷,也不需要像按鍵那樣初始化。本工程中使用的Key_GPIO_Config函數定義如代碼清單 4210所示。
代碼清單 4210 Key_GPIO_Config函數(bsp_key.c文件)
1
2 /**
3 * @brief 配置按鍵用到的I/O口
4 * @param 無
5 * @retval 無
6 */
7 void Key_GPIO_Config(void)
8 {
9 GPIO_InitTypeDef GPIO_InitStructure;
10
11 /*開啟按鍵GPIO口的時鍾*/
12 RCC_AHB1PeriphClockCmd(KEY2_GPIO_CLK,ENABLE);
13
14 /*設置引腳為輸入模式*/
15 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
16
17 /*設置引腳不上拉也不下拉*/
18 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
19
20 /*選擇按鍵的引腳*/
21 GPIO_InitStructure.GPIO_Pin = KEY2_PIN;
22
23 /*使用上面的結構體初始化按鍵*/
24 GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);
25 }
(2) 使用庫函數PWR_GetFlagStatus檢測PWR_FLAG_WU標志位,當這個標志位為SET狀態的時候,表示本次系統是從待機模式喚醒的復位,否則可能是上電復位。我們利用這個區分兩種復位形式,分別使用藍色LED燈或綠色LED燈來指示。
(3) 在while循環中,使用自定義的函數KEY2_LongPress來檢測KEY2按鍵是否被長時間按下,若長時間按下則進入待機模式,否則繼續while循環。KEY2_LongPress函數不是本章分析的重點,感興趣的讀者請自行查閱工程中的代碼。
(4) 檢測到KEY2按鍵被長時間按下,要進入待機模式。在使用庫函數PWR_EnterSTANDBYMode發送待機命令前,要先使用庫函數PWR_ClearFlag清除PWR_FLAG_WU標志位,並且使用庫函數PWR_WakeUpPinCmd使能WKUP喚醒功能,這樣進入待機模式后才能使用WKUP喚醒。
(5) 在進入待機模式前我們控制了LED彩燈為紅色,但在待機狀態時,由於I/O口會處於高阻態,所以LED燈會熄滅。
(6) 按下KEY1按鍵,會使PA0引腳產生一個上升沿,從而喚醒系統。
(7) 系統喚醒后會進行復位,從頭開始執行上述過程,與第一次上電時不同的是,這樣的復位會使PWR_FLAG_WU標志位改為SET狀態,所以這個時候LED彩燈會亮藍色。
42.5.3 下載驗證
下載這個實驗測試時,可連接上串口,在電腦端的串口調試助手獲知調試信息。長按實驗板上的KEY2按鍵,系統會進入待機模式,按KEY1按鍵可喚醒系統。
注意:
當系統處於待機模式低功耗狀態時(包括睡眠模式及停止模式),使用DAP下載器是無法給芯片下載程序的,所以下載程序時要先把系統喚醒。或者使用如下方法:按着板子的復位按鍵,使系統處於復位狀態,然后點擊電腦端的下載按鈕下載程序,這時再釋放復位按鍵,就能正常給板子下載程序了。
42.6 PWR—PVD電源監控實驗
這一小節我們學習如何使用PVD監控供電電源,增強系統的魯棒性。
42.6.1 硬件設計
本實驗中使用PVD監控STM32芯片的VDD引腳,當監測到供電電壓低於閾值時會產生PVD中斷,系統進入中斷服務函數進入緊急處理過程。所以進行這個實驗時需要使用一個可調的電壓源給實驗板供電,改變給STM32芯片的供電電壓,為此我們需要先了解實驗板的電源供電系統,見圖 428。

圖 428 實驗板的電源供電系統
整個電源供電系統主要分為以下五部分:
(1) 6-12V的DC電源供電系統,這部分使用DC電源接口引入6-12V的電源,經過RT7272進行電壓轉換成5V電源,再與第二部分的"5V_USB"電源線連接在一起。
(2) 第二部分使用USB接口,使用USB線從外部引入5V電源,引入的電源經過電源開關及保險絲連接到"5V"電源線。
(3) 第三部分的是電源開關及保險絲,即當我們的實驗板使用DC電源或"5V_USB"線供電時,可用電源開關控制通斷,保險絲也會起保護作用。
(4) "5V"電源線遍布整個板子,板子上各個位置引出的標有"5V"絲印的排針都與這個電源線直接相連。5V電源線給板子上的某些工作電壓為5V的芯片供電。5V電源還經過LDO穩壓芯片,輸出3.3V電源連接到"3.3V"電源線。
(5) 同樣地,"3.3V"電源線也遍布整個板子,各個引出的標有"3.3V"絲印的排針都與它直接相連,3.3V電源給工作電壓為3.3V的各種芯片供電。STM32芯片的VDD引腳就是直接與這個3.3V電源相連的,所以通過STM32的PVD監控的就是這個"3.3V"電源線的電壓。
當我們進行這個PVD實驗時,為方便改變"3.3V"電源線的電壓,我們可以把可調電源通過實驗板上引出的"5V"及"GND"排針給實驗板供電,當可調電源電壓降低時,LDO在"3.3V"電源線的供電電壓會隨之降低,即STM32的PVD監控的VDD引腳電壓會降低,這樣我們就可以模擬VDD電壓下降的實驗條件,對PVD進行測試了。不過,由於這樣供電不經過保險絲,所以在調節電壓的時候要小心,不要給它供電遠高於5V,否則可能會燒壞實驗板上的芯片。
42.6.2 軟件設計
本小節講解的是"PWR—睡眠模式"實驗,請打開配套的代碼工程閱讀理解。為了方便把這個工程的PVD監控功能移植到其它應用,我們把PVD電壓監控相關的主要代碼編都寫到"bsp_pvd.c"及"bsp_pvd.h"文件中,這些文件是我們自己編寫的,不屬於標准庫的內容,可根據您的喜好命名文件。
1. 程序設計要點
(1) 初始化PVD中斷;
(2) 設置PVD電壓監控等級並使能PVD;
(3) 編寫PVD中斷服務函數,處理緊急任務。
2. 代碼分析
初始化PVD
使用PVD功能前需要先初始化,我們把這部分代碼封裝到PVD_Config函數中,見代碼清單 4211。
代碼清單 4211 初始化PVD(bsp_pvd.c文件)
1
2 /**
3 * @brief 配置PVD.
4 * @param None
5 * @retval None
6 */
7 void PVD_Config(void)
8 {
9 NVIC_InitTypeDef NVIC_InitStructure;
10 EXTI_InitTypeDef EXTI_InitStructure;
11
12 /*使能 PWR 時鍾 */
13 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
14
15 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
16
17 /* 使能 PVD 中斷 */
18 NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn;
19 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
20 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
21 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
22 NVIC_Init(&NVIC_InitStructure);
23
24 /* 配置 EXTI16線(PVD 輸出) 來產生上升下降沿中斷*/
25 EXTI_ClearITPendingBit(EXTI_Line16);
26 EXTI_InitStructure.EXTI_Line = EXTI_Line16;
27 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
28 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
29 EXTI_InitStructure.EXTI_LineCmd = ENABLE;
30 EXTI_Init(&EXTI_InitStructure);
31
32 //配置PVD級別5
33 // (PVD檢測電壓的閾值為2.8V,VDD電壓低於2.8V時產生PVD中斷,
34 //具體數據可查詢數據手冊獲知)
35 /*具體級別根據自己的實際應用要求配置*/
36 PWR_PVDLevelConfig(PWR_PVDLevel_5);
37
38 /* 使能PVD輸出 */
39 PWR_PVDCmd(ENABLE);
40 }
在這段代碼中,執行的流程如下:
(1) 配置PVD的中斷優先級。由於電壓下降是非常危急的狀態,所以請盡量把它配置成最高優先級。
(2) 配置了EXTI16線的中斷源,設置EXTI16是因為PVD中斷是通過EXTI16產生中斷的(GPIO的中斷是EXTI0-EXTI15)。
(3) 使用庫函數PWR_PVDLevelConfig設置PVD監控的電壓閾值等級,各個閾值等級表示的電壓值請查閱表 422或STM32的數據手冊。
(4) 最后使用庫函數PWR_PVDCmd使能PVD功能。
PVD中斷服務函數
配置完成PVD后,還需要編寫中斷服務函數,在其中處理緊急任務,本工程的PVD中斷服務函數見代碼清單 4212。
代碼清單 4212 PVD中斷服務函數(stm32f4xx_it.c文件)
1
2 /**
3 * @brief PVD中斷請求
4 * @param None
5 * @retval None
6 */
7 void PVD_IRQHandler(void)
8 {
9 /*檢測是否產生了PVD警告信號*/
10 if (PWR_GetFlagStatus (PWR_FLAG_PVDO)==SET) {
11 /* 亮紅燈,實際應用中應進入緊急狀態處理 */
12 LED_RED;
13
14 }
15 /* 清除中斷信號*/
16 EXTI_ClearITPendingBit(EXTI_Line16);
17
18 }
19
注意這個中斷服務函數的名是PVD_IRQHandler而不是EXTI16_IRQHandler(STM32沒有這樣的中斷函數名),示例中我們僅點亮了LED紅燈,不同的應用中要根據需求進行相應的緊急處理。
main函數
本電源監控實驗的main函數執行流程比較簡單,僅調用了PVD_Config配置監控功能,當VDD供電電壓正常時,板子亮綠燈,當電壓低於閾值時,會跳轉到中斷服務函數中,板子亮紅燈,見代碼清單 242。
代碼清單 4213 停止模式的main函數(main.c文件)
1 /**
2 * @brief 主函數
3 * @param 無
4 * @retval 無
5 */
6 int main(void)
7 {
8 LED_GPIO_Config();
9
10 //亮綠燈,表示正常運行
11 LED_GREEN;
12
13 //配置PVD,當電壓過低時,會進入中斷服務函數,亮紅燈
14 PVD_Config();
15
16 while (1) {
17
18 /*正常運行的程序*/
19
20 }
21
22 }
23
24
42.6.3 下載驗證
本工程的驗證步驟如下:
(1) 通過電腦把本工程編譯並下載到實驗板;
(2) 把下載器、USB及DC電源等外部供電設備都拔掉;
(3) 按"硬件設計"小節中的說明,使用可調電源通過"5V"及"GND"排針給實驗板供5V電源;(注意要先調好可調電源的電壓再連接,防止燒壞實驗板)
(4) 復位實驗板,確認板子亮綠燈,表示正常狀態;
(5) 持續降低可調電源的輸出電壓,直到實驗板亮紅燈,這時表示PVD檢測到電壓低於閾值。
本工程中,我們實測PVD閾值等級為"PWR_PVDLevel_5"時,當可調電源電壓降至4.4V時,板子亮紅燈,此時的"3.3V"電源引腳的實測電壓為2.75V;而PVD閾值等級為"PWR_PVDLevel_3"時,當可調電源電壓降至4.2V時,板子亮紅燈,此時的"3.3V"電源引腳的實測電壓為2.55V;
注意:
由於這樣使用可調電源供電不經過保險絲,所以在調節電壓的時候要小心,不要給它供電遠高於5V,否則可能會燒壞實驗板上的芯片。
42.7 每課一問
10. 在睡眠模式實驗的基礎上編寫程序,添加SYSTICK定時器,使用它控制LED燈1秒翻轉狀態1次,控制完畢后立即重新進入睡眠狀態。
11. 在停止模式實驗的基礎上改寫程序,嘗試在系統喚醒后(緊接着PWR_EnterSTOPMode函數之后)立即使用串口打印調試信息到電腦端,觀察實驗現象並解釋。
答:由於系統時鍾沒有恢復,導致串口波特率與原配置不符,導致通訊錯誤。
12. 在PVD電源監控實驗的基礎上,修改PVD監控的電壓閾值等級,進入PVD中斷時"3.3V"電源線的臨界電壓。
