在說低功耗之前,先要明白一個東西,那就是stm32中的事件和中斷。

事件是中斷的觸發源,開放了對應的中斷屏蔽位,則事件可以觸發相應的中斷。在STM32中,中斷與事件不是等價的,一個中斷肯定對應一個事件,但一個事件不一定對應一個中斷。
當外部有信號輸入時,如果通過了事件屏蔽寄存器,那么事件信號就進入脈沖觸發器,引發一個脈沖信號,直接傳遞給相應的外設,用於觸發,這就是一個純硬件的過程,理解DMA的應該知道,這個方式不需要CPU參與,但是這也有它的缺點,如功能比較單一,僅能提供信號,不能提供信息,也就是只能產生指定功能的事件。如果通過中斷屏蔽寄存器,就被直接送到CPU中,產生中斷,如進入上面的入口函數開始處理。從這就可看出,事件是單純硬件觸發執行的過程,與CPU本身設計支持有關,而中斷中則可以軟件實現各種功能,而低功耗模式的事件喚醒就是stm32支持的事件之一。

進入停止模式之后,任何外部中斷都可以喚醒低功耗,但是需要重新配置時鍾,不然系統將以默認時鍾(沒有經過倍頻)運行。

選擇事件喚醒低功耗之停止模式,可以更加快速,不需要中斷服務函數,自然也不需要配置NVIC的相關寄存器。
進入低功耗庫函數:
PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFE);
/** * @brief Enters STOP mode. * @param PWR_Regulator: specifies the regulator state in STOP mode. * This parameter can be one of the following values: * @arg PWR_Regulator_ON: STOP mode with regulator ON * @arg PWR_Regulator_LowPower: STOP mode with regulator in low power mode * @param PWR_STOPEntry: specifies if STOP mode in entered with WFI or WFE instruction. * This parameter can be one of the following values: * @arg PWR_STOPEntry_WFI: enter STOP mode with WFI instruction * @arg PWR_STOPEntry_WFE: enter STOP mode with WFE instruction * @retval None */ void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry) { uint32_t tmpreg = 0; /* Check the parameters */ assert_param(IS_PWR_REGULATOR(PWR_Regulator)); assert_param(IS_PWR_STOP_ENTRY(PWR_STOPEntry)); /* Select the regulator state in STOP mode ---------------------------------*/ tmpreg = PWR->CR; /* Clear PDDS and LPDS bits */ tmpreg &= CR_DS_MASK; /* Set LPDS bit according to PWR_Regulator value */ tmpreg |= PWR_Regulator; /* Store the new value */ PWR->CR = tmpreg; /* Set SLEEPDEEP bit of Cortex System Control Register */ SCB->SCR |= SCB_SCR_SLEEPDEEP; /* Select STOP mode entry --------------------------------------------------*/ if(PWR_STOPEntry == PWR_STOPEntry_WFI) { /* Request Wait For Interrupt */ __WFI(); } else { /* Request Wait For Event */ __WFE(); } /* Reset SLEEPDEEP bit of Cortex System Control Register */ SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP); }
可以選擇事件和中斷喚醒兩種方式,選擇哪種方式是根據庫函數的第二個參數決定的,這是一個宏:

進入低功耗之后,需要事件或者中斷去喚醒,這里用RTC鬧鍾事件選擇喚醒mcu。
RTC_SetAlarm( RTC_GetCounter()+600*N);
RTC_ITConfig(RTC_IT_ALR, ENABLE);
RTC_WaitForLastTask();
上面三句話需要放在進入低功耗的函數前,這樣當RTC鬧鍾時間到了之后,在沒有其他事件或者中斷喚醒的前提下,鬧鍾會喚醒進入停機模式的mcu。每次操作了RTC,需要等待RTC操作完成,這些在ST庫函數中都給我們做好了。
另外需要注意的是,停機模式下,mcu喚醒之后,時鍾和頻率是沒有經過倍頻的,在F1上,低功耗喚醒之后,是8M頻率運行,而正常運行是72M。所以,在喚醒停機模式之后,需要重新配置時鍾。
ST很貼心,直接調用庫函數:
SystemInit();
就可以了。那么整體流程就是:
RTC_SetAlarm( RTC_GetCounter()+600*N); RTC_ITConfig(RTC_IT_ALR, ENABLE); RTC_WaitForLastTask(); PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFE); SystemInit(); RTC_WaitForSynchro();
上面的代碼,裸機中推薦放在while(1)最后,帶os應該在空閑任務中。
Advance:
有低功耗的項目中,看門狗監測目前沒有找到好的方式,使用看門狗監測程序但它會破壞低功耗,查詢很多資料論壇后,還是選擇了放棄看門狗,看門狗被開啟,就不能再軟件關閉了。
