定西市小企業(yè)網(wǎng)站建設(shè)建設(shè)西安專業(yè)seo
電源管理
STM32 HAL庫(kù)對(duì)電源管理提供了完善的函數(shù)和命令。
工作模式(高功耗->低功耗):運(yùn)行、睡眠、停止、待機(jī)。
若備份域電源正常供電,備份域內(nèi)的RTC都可以正常運(yùn)行,備份域內(nèi)的寄存器的數(shù)據(jù)會(huì)被保存,不受功耗模式影響。
上電復(fù)位(POR)和掉電復(fù)位(PDR)
當(dāng)檢測(cè)到VDD的電壓低于閾值VPOR及VPDR時(shí),無(wú)需外部電路輔助,STM32芯片會(huì)自動(dòng)保持在復(fù)位狀態(tài),防止因電壓不足強(qiáng)行工作而帶來(lái)嚴(yán)重的后果。
在剛開(kāi)始電壓低于VPOR時(shí)(約1.92V),STM32保持在上電復(fù)位狀態(tài)(POR,Power On Reset)。當(dāng)VDD電壓持續(xù)上升至大于VPOR時(shí),芯片開(kāi)始正常運(yùn)行。
而在芯片開(kāi)始正常運(yùn)行的時(shí)候,當(dāng)檢測(cè)到VDD電壓下降至低于VPDR閾值(約1.88V),會(huì)進(jìn)入掉電復(fù)位狀態(tài)(PDR,Power Down Reset)。
配置PVD監(jiān)控功能
PVD可監(jiān)控VDD的電壓,當(dāng)它低于閾值時(shí)可產(chǎn)生PVD中斷以讓系統(tǒng)進(jìn)行緊急處理,這個(gè)閾值可以直接使用庫(kù)函數(shù)PWR_PVDLevelConfig配置成某一個(gè)的閾值等級(jí)。
WFI和WFE命令
進(jìn)入各種低功耗模式時(shí)都需要調(diào)用WFI或WFE命令,實(shí)質(zhì)上都是內(nèi)核指令,在庫(kù)文件 core_cm3.h 或 cmsis_armcc.h 中把這些指令封裝成了函數(shù)。
/* 等待中斷。是一種暫停執(zhí)行指令,暫停至任意中斷產(chǎn)生后被喚醒 */
#define __WFI __wfi/* 等待事件。是一種暫停執(zhí)行指令,暫停至任意事件產(chǎn)生后被喚醒 */
#define __WFE __wfe
這兩個(gè)指令,調(diào)用后都能進(jìn)入低功耗模式,需要使用__WFI();和__WFE();來(lái)調(diào)用(因?yàn)開(kāi)_wfi和__wfe是編譯器內(nèi)置的函數(shù),函數(shù)內(nèi)部調(diào)用了相對(duì)應(yīng)的匯編指令)。
具體可查《cortex-CM3/CM4權(quán)威指南》。
進(jìn)入停止模式
直接調(diào)用WFI和WFE指令可以進(jìn)入睡眠模式,而進(jìn)入停止模式這還需要在調(diào)用指令前設(shè)置一些寄存器位,STM32 HAL庫(kù)把這部分的操作封裝到HAL_PWR_EnterSTOPMode()。
/*** @brief 進(jìn)入停止模式* @note 在停止模式下所有I/O都會(huì)保持在停止前的狀態(tài).* @note 當(dāng)使用中斷或喚醒事件退出停止模式時(shí),HSI RC振蕩器被選擇為系統(tǒng)時(shí)鐘。* @note 當(dāng)穩(wěn)壓器在低功率模式下工作時(shí),從停止模式喚醒時(shí)會(huì)產(chǎn)生額外的啟動(dòng)延遲。* 通過(guò)在停止模式中保持內(nèi)部穩(wěn)壓器打開(kāi),雖然啟動(dòng)時(shí)間減少,但消耗更高。* @param Regulator: 在停止模式下指定穩(wěn)壓器狀態(tài)。* @arg PWR_MAINREGULATOR_ON: 穩(wěn)壓器正常運(yùn)行* @arg PWR_LOWPOWERREGULATOR_ON: 穩(wěn)壓器低功耗運(yùn)行* @param STOPEntry: 指定是否使用WFI或WFE指令進(jìn)入停止模式。* @arg PWR_STOPENTRY_WFI: 使用WFI指令進(jìn)入停止模式* @arg PWR_STOPENTRY_WFE: 使用WFE指令進(jìn)入停止模式* @retval None*/
void HAL_PWR_EnterSTOPMode(uint32_t Regulator, uint8_t STOPEntry)
{/* 檢查參數(shù) */assert_param(IS_PWR_REGULATOR(Regulator));assert_param(IS_PWR_STOP_ENTRY(STOPEntry));/* 清除PWR寄存器中的PDDS位以指定當(dāng)CPU進(jìn)入深度睡眠時(shí)進(jìn)入停止模式 */CLEAR_BIT(PWR->CR, PWR_CR_PDDS);/* 根據(jù)穩(wěn)壓參數(shù)值,通過(guò)在PWR寄存器中設(shè)置LPDS位來(lái)選擇穩(wěn)壓模式 */MODIFY_REG(PWR->CR, PWR_CR_LPDS, Regulator);/* 設(shè)置內(nèi)核系統(tǒng)控制寄存器的SLEEPDEEP位 */SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));/* 選擇停止模式進(jìn)入 */if (STOPEntry == PWR_STOPENTRY_WFI){/* 請(qǐng)求等待中斷 */__WFI();}else{/* 請(qǐng)求等待事件 */__SEV();PWR_OverloadWfe(); /* 本地重新定義WFE */PWR_OverloadWfe(); /* 本地重新定義WFE */}/* 以下的程序是當(dāng)重新喚醒時(shí)才執(zhí)行的,清除內(nèi)核系統(tǒng)控制寄存器的SLEEPDEEP位 */CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
}
進(jìn)入停止模式后,STM32的所有I/O都保持在停止前的狀態(tài),而當(dāng)它被喚醒時(shí),STM32使用HSI作為系統(tǒng)時(shí)鐘(8MHz)運(yùn)行,由于系統(tǒng)是在會(huì)影響很多外設(shè)的工作狀態(tài),所以一般我們?cè)趩拘押髸?huì)重新開(kāi)始HSE,把系統(tǒng)時(shí)鐘設(shè)置成原來(lái)的狀態(tài)。
進(jìn)入待機(jī)模式
STM32 HAL庫(kù)把這部分的操作封裝到HAL_PWR_EnterSTANDBYMode()。
/*** @brief 進(jìn)入待機(jī)模式* @note 待機(jī)模式下,除以下情況外,所有I/O引腳均為高阻抗::* - 復(fù)位引腳(仍然有效)* - TAMPER pin if configured for tamper or calibration out.* - WKUP pin (PA0) (如果使能WKUP喚醒功能).* @retval None*/
void HAL_PWR_EnterSTANDBYMode(void)
{/* 選擇待機(jī)模式 */SET_BIT(PWR->CR, PWR_CR_PDDS);/* 設(shè)置內(nèi)核系統(tǒng)控制寄存器的SLEEPDEEP位*/SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));/* 存儲(chǔ)操作完畢時(shí)才能進(jìn)入待機(jī)模式,使用以下語(yǔ)句確保存儲(chǔ)操作執(zhí)行完畢 */
#if defined ( __CC_ARM)__force_stores();
#endif/* 請(qǐng)求等待中斷 */__WFI();
}
待機(jī)模式也可以使用WFE指令進(jìn)入的,如果有需要可以自行修改。
在進(jìn)入待機(jī)模式后,除了被使能用于喚醒的I/O,其余I/O都進(jìn)入高阻態(tài),而從待機(jī)模式喚醒后,想防御復(fù)位STM32芯片,程序重新從頭開(kāi)始執(zhí)行。
實(shí)驗(yàn)環(huán)節(jié)1:PWR_PVD監(jiān)控
實(shí)驗(yàn)操作
使用外部可調(diào)電源,調(diào)節(jié)成5V輸出,連接到開(kāi)發(fā)板5V和GND排針給板子進(jìn)行供電;
復(fù)位開(kāi)發(fā)板,電壓正常時(shí)LED為綠色;
向下調(diào)節(jié)可調(diào)電源的電壓,大約降到4V時(shí),LED為紅色。(程序中控制PVD監(jiān)控電壓約為2.8V,當(dāng)5V降到4V時(shí),連接STM32的VDD電源會(huì)降于2.8V,產(chǎn)生PVD事件,在中斷中控制亮紅燈)。
注意:其他電源線都拔掉(包括下載器、USB線)。不能遠(yuǎn)高于5V而導(dǎo)致燒壞開(kāi)發(fā)板。
PVD配置
void PVD_Config(void)
{PWR_PVDTypeDef sConfigPVD;/*使能 PWR 時(shí)鐘 */__HAL_RCC_PWR_CLK_ENABLE();/* 配置 PVD 中斷 */HAL_NVIC_SetPriority(PVD_IRQn, 0 ,0);HAL_NVIC_EnableIRQ(PVD_IRQn); /* 配置PVD級(jí)別6 (PVD檢測(cè)電壓的閾值為2.8V,VDD電壓低于2.8V時(shí)產(chǎn)生PVD中斷,具體數(shù)據(jù)可查詢數(shù)據(jù)手冊(cè)獲知) 具體級(jí)別根據(jù)自己的實(shí)際應(yīng)用要求配置*/sConfigPVD.PVDLevel = PWR_PVDLEVEL_6;sConfigPVD.Mode = PWR_PVD_MODE_IT_RISING_FALLING;HAL_PWR_ConfigPVD(&sConfigPVD);/* 使能PVD輸出 */HAL_PWR_EnablePVD();
}
測(cè)試環(huán)節(jié)
void PVD_IRQHandler(void)
{HAL_PWR_PVD_IRQHandler();
}void HAL_PWR_PVDCallback(void)
{LED紅燈
}void test(void)
{初始化LED綠燈// 配置PVD,當(dāng)電壓過(guò)低時(shí),會(huì)進(jìn)入中斷服務(wù)函數(shù),亮紅燈PVD_Config();while(1){}
}
實(shí)驗(yàn)環(huán)節(jié)2:PWR睡眠模式
實(shí)驗(yàn)操作
LED:綠燈正常運(yùn)行,紅燈睡眠狀態(tài),藍(lán)燈剛被喚醒。
KEY:key1和key2配置成IO中斷模式。
運(yùn)行一段時(shí)間后自動(dòng)進(jìn)入睡眠時(shí)間,通過(guò)按鍵(key1或key2)喚醒。
睡眠狀態(tài)下,DAP下載器無(wú)法給STM32下載程序,可喚醒后再下載或按復(fù)位鍵使芯片處于復(fù)位狀態(tài)下下載后松開(kāi)復(fù)位鍵。
測(cè)試環(huán)節(jié)
int main(void)
{初始化while (1){LED綠燈HAL_Delay(2000);LED紅燈HAL_SuspendTick(); //暫停滴答時(shí)鐘,防止通過(guò)滴答時(shí)鐘中斷喚醒//進(jìn)入睡眠模式HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);//等待中斷喚醒 K1或K2按鍵中斷LED藍(lán)燈HAL_ResumeTick(); //被喚醒后,恢復(fù)滴答時(shí)鐘HAL_Delay(2000);//繼續(xù)執(zhí)行while循環(huán)}
}
實(shí)驗(yàn)環(huán)節(jié)3:PWR待機(jī)模式
實(shí)驗(yàn)操作
LED:綠燈表示本次復(fù)位是上電或引腳復(fù)位,紅燈待機(jī)狀態(tài),藍(lán)燈剛被喚醒。
KEY:key2配置成輸入模式。
長(zhǎng)按KEY2按鍵會(huì)進(jìn)入待機(jī)模式,待機(jī)模式下KEY1按鍵可喚醒,喚醒后系統(tǒng)會(huì)復(fù)位??赏ㄟ^(guò)檢測(cè)PWR_CSR:WUF標(biāo)志確定復(fù)位來(lái)源。
待機(jī)模式下,DAP下載器無(wú)法給STM32下載程序,可喚醒后再下載。
注意:由于WKUP引腳(PA0)必須使用上升沿才能喚醒待機(jī)狀態(tài)的系統(tǒng),所以硬件設(shè)計(jì)PA0引腳連接到KEY1,且按下KEY1時(shí)會(huì)在PA0引腳產(chǎn)生上升沿,從而可實(shí)現(xiàn)喚醒的功能。
測(cè)試環(huán)節(jié)
/*** @brief 用于檢測(cè)按鍵是否被長(zhǎng)時(shí)間按下* @param 無(wú)* @retval 1 :按鍵被長(zhǎng)時(shí)間按下 0 :按鍵沒(méi)有被長(zhǎng)時(shí)間按下*/
static uint8_t KEY2_LongPress(void)
{uint8_t downCnt = 0; //記錄按下的次數(shù)uint8_t upCnt = 0; //記錄松開(kāi)的次數(shù)while (1) //死循環(huán),由return結(jié)束{ HAL_Delay(20); //延遲一段時(shí)間再檢測(cè)if (HAL_GPIO_ReadPin(KEY2_GPIO_PORT, KEY2_PIN) == SET) //檢測(cè)到按下按鍵{downCnt++; //記錄按下次數(shù)upCnt = 0; //清除按鍵釋放記錄if (downCnt >= 100) //按下時(shí)間足夠{return 1; //檢測(cè)到按鍵被時(shí)間長(zhǎng)按下}}else{upCnt++; //記錄釋放次數(shù)if (upCnt > 5) //連續(xù)檢測(cè)到釋放超過(guò)5次{return 0; //按下時(shí)間太短,不是按鍵長(zhǎng)按操作}}}
}int main(void)
{初始化/* 使能電源管理單元的時(shí)鐘,必須要使能時(shí)鐘才能進(jìn)入待機(jī)模式 */__HAL_RCC_PWR_CLK_ENABLE();//檢測(cè)復(fù)位來(lái)源if (__HAL_PWR_GET_FLAG(PWR_FLAG_WU) == SET){ // 復(fù)位前為待機(jī)模式__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);LED藍(lán)燈}else{// 復(fù)位前為正常運(yùn)行LED綠燈}while (1){// K2 按鍵長(zhǎng)按進(jìn)入待機(jī)模式if (KEY2_LongPress()){LED紅燈HAL_Delay(1000);/*清除WU狀態(tài)位*/__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);/* 使能WKUP引腳的喚醒功能,使能PA0*/HAL_PWR_EnableWakeUpPin(0x00000100U);//暫停滴答時(shí)鐘,防止通過(guò)滴答時(shí)鐘中斷喚醒HAL_SuspendTick();/* 進(jìn)入待機(jī)模式 */HAL_PWR_EnterSTANDBYMode();}}
}
實(shí)驗(yàn)現(xiàn)象
開(kāi)機(jī)正常運(yùn)行綠燈。長(zhǎng)按KEY2按鍵,顯紅燈,過(guò)1s后進(jìn)入待機(jī)模式LED滅。按下KEY1按鍵退出待機(jī)模式自動(dòng)復(fù)位,顯藍(lán)燈。按下復(fù)位鍵,重新運(yùn)行綠燈。
實(shí)驗(yàn)環(huán)節(jié)4:PWR停止模式
實(shí)驗(yàn)操作
LED:綠燈正常運(yùn)行,紅燈停止?fàn)顟B(tài),藍(lán)燈剛被喚醒。
KEY:key1和key2配置成IO中斷模式。
運(yùn)行一段時(shí)間后自動(dòng)進(jìn)入停止時(shí)間,通過(guò)按鍵(key1或key2)喚醒。
待機(jī)模式下,DAP下載器無(wú)法給STM32下載程序,可喚醒后再下載。
注意:由于WKUP引腳(PA0)必須使用上升沿才能喚醒待機(jī)狀態(tài)的系統(tǒng),所以硬件設(shè)計(jì)PA0引腳連接到KEY1,且按下KEY1時(shí)會(huì)在PA0引腳產(chǎn)生上升沿,從而可實(shí)現(xiàn)喚醒的功能。
測(cè)試環(huán)節(jié)
/*** @brief 從停止模式喚醒后配置系統(tǒng)時(shí)鐘:啟用HSE、PLL并選擇PLL作為系統(tǒng)時(shí)鐘源。* @param 無(wú)* @retval 無(wú)*/
static void SYSCLKConfig_STOP(void)
{RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};RCC_OscInitTypeDef RCC_OscInitStruct = {0};uint32_t pFLatency = 0;/* 啟用電源控制時(shí)鐘 */__HAL_RCC_PWR_CLK_ENABLE();/* 根據(jù)內(nèi)部RCC寄存器獲取振蕩器配置 */HAL_RCC_GetOscConfig(&RCC_OscInitStruct);/* 從停止模式喚醒后重新配置系統(tǒng)時(shí)鐘: 啟用HSE和PLL */RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){while(1) { ; }}/* 根據(jù)內(nèi)部RCC寄存器獲取時(shí)鐘配置 */HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &pFLatency);/* 選擇 PLL 作為系統(tǒng)時(shí)鐘源, 并配置 HCLK、PCLK1 和 PCLK2時(shí)鐘分頻系數(shù) */RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, pFLatency) != HAL_OK){while(1) { ; }}
}int main(void)
{uint32_t SYSCLK_Frequency = 0; uint32_t HCLK_Frequency = 0;uint32_t PCLK1_Frequency = 0;uint32_t PCLK2_Frequency = 0;uint32_t SYSCLK_Source = 0;初始化while(1){ LED綠燈HAL_Delay(2000); // 進(jìn)入停止模式,亮紅燈,按KEY1或KEY2按鍵可喚醒LED_RED;HAL_SuspendTick(); //暫停滴答時(shí)鐘,防止通過(guò)滴答時(shí)鐘中斷喚醒/* 進(jìn)入停止模式,設(shè)置電壓調(diào)節(jié)器為低功耗模式,等待中斷喚醒 */HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);// 等待中斷喚醒 K1或K2按鍵中斷 // 被喚醒,亮藍(lán)燈指示LED藍(lán)燈SystemCoreClockUpdate(); //根據(jù)時(shí)鐘寄存器的值更新SystemCoreClock變量//獲取喚醒后的時(shí)鐘狀態(tài) SYSCLK_Frequency = HAL_RCC_GetSysClockFreq(); HCLK_Frequency = HAL_RCC_GetHCLKFreq();PCLK1_Frequency = HAL_RCC_GetPCLK1Freq();PCLK2_Frequency = HAL_RCC_GetPCLK2Freq();SYSCLK_Source = __HAL_RCC_GET_SYSCLK_SOURCE();/* 從停止模式喚醒后配置系統(tǒng)時(shí)鐘:啟用HSE、PLL*//* 選擇PLL作為系統(tǒng)時(shí)鐘源(HSE和PLL在停止模式下被禁用)*/SYSCLKConfig_STOP();HAL_ResumeTick(); //被喚醒后,恢復(fù)滴答時(shí)鐘//獲取重新配置后的時(shí)鐘狀態(tài)SYSCLK_Frequency = HAL_RCC_GetSysClockFreq(); HCLK_Frequency = HAL_RCC_GetHCLKFreq();PCLK1_Frequency = HAL_RCC_GetPCLK1Freq();PCLK2_Frequency = HAL_RCC_GetPCLK2Freq();SYSCLK_Source = __HAL_RCC_GET_SYSCLK_SOURCE();HAL_Delay(2000); //繼續(xù)執(zhí)行while循環(huán)}
}