一、低功耗模式簡介
系統提供了多個低功耗模式,可在 CPU 不需要運行時(例如等待外部事件時)節省功耗,由用戶根據應用選擇具體的低功耗模式,以在低功耗、短啟動時間和可用喚醒源之間尋求最佳平衡,
睡眠模式、停止模式及待機模式中,若備份域電源正常供電,備份域內的 RTC 都可以正常運行,備份域內的暫存器的資料會被保存,不受功耗模式影響,
從表中可以看到,這三種低功耗模式層層遞進,運行的時鐘或芯片功能越來越少,因而功耗越來越低,
| 模式名稱 | 說明 | 進入方式 | 喚醒方式 | 對1.8V區域時鐘的影響 | 對VDD區域時鐘的影響 | 調壓器 |
|---|---|---|---|---|---|---|
| 睡眠模式 | 內核停止,所有外設包括M3核心的外設,如NVIC、系統時鐘(SysTick)等仍在運行 | 呼叫WFI命令 | 任意中斷 | 內核時鐘關,對其他時鐘和ADC時鐘無影響 | 無 | 開 |
| 睡眠模式 | 內核停止,所有外設包括M3核心的外設,如NVIC、系統時鐘(SysTick)等仍在運行 | 呼叫WFE命令 | 喚醒事件 | 內核時鐘關,對其他時鐘和ADC時鐘無影響 | 無 | 開 |
| 停止模式 | 所有的時鐘都已停止 | 配置PWR_CR暫存器的PDDS+LPDS位+SLEEPDEEP位+WFI或WFE命令 | 任意外部中斷EXTI(在外部中斷暫存器中設定) | 關閉所有1.8V區域的時鐘 | HSI和HSE的振蕩器關閉 | 開啟或處于低功耗模式(依據電源控制暫存器的設定) |
| 待機模式 | 1.8V電源關閉 | 配置PWR_CR暫存器的PDDS+SLEEPDEEP位+WFI或WFE命令 | WKUP上升沿、引腳的RTC鬧鐘事件、NRST引腳上的外部復位、IWDG復位 | 關閉所有1.8V區域的時鐘 | HSI和HSE的振蕩器關閉 | 關 |
1.1 睡眠模式
在睡眠模式中,僅關閉了內核時鐘,內核停止運行,但其片上外設,CM3 核心的外設全都還照常運行,有兩種方式進入睡眠模式,它的進入方式決定了從睡眠喚醒的方式,分別是 WFI(wait for interrupt) 和 WFE(wait for event),即由等待“中斷”喚醒和由“事件”喚醒,
特性和說明:
- 立即睡眠: 在執行
WFI或WFE指令時立即進入睡眠模式,- 退出時睡眠: 在退出優先級最低的中斷服務程式后才進入睡眠模式,
- 進入方式: 內核暫存器的
SLEEPDEEP=0,然后呼叫WFI或WFE指令即可進入睡眠模式;SLEEPONEXIT=1時,進入“退出時睡眠”模式,- 喚醒方式: 如果是使用
WFI指令睡眠的,則可使用任意中斷喚醒;如果是使用WFE指令睡眠的,則由事件喚醒,- 睡眠時: 關閉內核時鐘,內核停止,而外設正常運行,在軟體上表現為不再執行新的代碼,這個狀態會保留睡眠前的內核暫存器、記憶體的資料,
- 喚醒延遲: 無延遲,
- 喚醒后: 若由中斷喚醒,先進入中斷,退出中斷服務程式后,接著執行
WFI指令后的程式;若由事件喚醒,直接接著執行WFE后的程式,
1.2 停止模式
在停止模式中,進一步關閉了其它所有的時鐘,于是所有的外設都停止了作業,但由于其 1.8V 區域的部分電源沒有關閉,還保留了內核的暫存器、記憶體的資訊,所以從停止模式喚醒,并重新開啟時鐘后,還可以從上次停止處繼續執行代碼,停止模式可以由任意一個外部中斷(EXTI)喚醒,在停止模式中可以選擇電壓調節器為開模式或低功耗模式,
特性和說明:
- 調壓器低功耗模式: 在停止模式下調壓器可作業在正常模式或低功耗模式,可進一步降低功耗,
- 進入方式: 內核暫存器的
SLEEPDEEP=1,PWR_CR 暫存器中的PDDS=0,然后呼叫WFI或WFE指令即可進入停止模式;PWR_CR 暫存器的LPDS=0時,調壓器作業在正常模式,LPDS=1時作業在低功耗模式,- 喚醒方式: 如果是使用
WFI指令睡眠的,可使用任意 EXTI 線的中斷喚醒;如果是使用WFE指令睡眠的,可使用任意配置為事件模式的 EXTI 線事件喚醒,- 停止時: 內核停止,片上外設也停止,這個狀態會保留停止前的內核暫存器、記憶體的資料,
- 喚醒延遲: 基礎延遲為 HSI 振蕩器的啟動時間,若調壓器作業在低功耗模式,還需要加上調壓器從低功耗切換至正常模式下的時間,
- 喚醒后: 若由中斷喚醒,先進入中斷,退出中斷服務程式后,接著執行
WFI指令后的程式;若由事件喚醒,直接接著執行WFE后的程式,喚醒后,STM32 會使用 HSI 作為系統時鐘,
1.3 待機模式
待機模式,它除了關閉所有的時鐘,還把 1.8V 區域的電源也完全關閉了,也就是說,從待機模式喚醒后,由于沒有之前代碼的運行記錄,只能對芯片復位,重新檢測 boot 條件,從頭開始執行程式,它有四種喚醒方式,分別是 WKUP(PA0)引腳的上升沿,RTC 鬧鐘事件,NRST 引腳的復位和 IWDG(獨立看門狗)復位,
特性和說明:
- 進入方式: 內核暫存器的
SLEEPDEEP=1,PWR_CR 暫存器中的PDDS=1,PWR_CR 暫存器中的喚醒狀態位WUF=0,然后呼叫WFI或WFE指令即可進入待機模式,- 喚醒方式: 通過 WKUP 引腳的上升沿,RTC 鬧鐘、喚醒、入侵、時間戳事件或 NRST 引腳外部復位及 IWDG 復位喚醒,
- 待機時: 內核停止,片上外設也停止;內核暫存器、記憶體的資料會丟失;除復位引腳、RTC_AF1 引腳及 WKUP 引腳,其它 I/O 口均作業在高阻態,
- 喚醒延遲: 芯片復位的時間,
- 喚醒后: 相當于芯片復位,在程式表現為從頭開始執行代碼,
1.4 WFI與WFE命令
我們了解到進入各種低功耗模式時都需要呼叫 WFI 或 WFE 命令,它們實質上都是內核指令,在庫檔案 core_cm3.h 中把這些指令封裝成了函式,
/** brief 等待中斷
等待中斷 是一個暫停執行指令
暫停至任意中斷產生后被喚醒
*/
#define __WFI __wfi
/** brief 等待事件
等待事件 是一個暫停執行指令
暫停至任意事件產生后被喚醒
*/
#define __WFE __wfe
對于這兩個指令,我們應用時一般只需要知道,呼叫它們都能進入低功耗模式,需要使用函式的格式“__WFI();”和“__WFE();”來呼叫(因為__wfi 及__wfe 是編譯器內置的函式,函式內部呼叫了相應的匯編指令),
其中
WFI指令決定了它需要用中斷喚醒,而WFE則決定了它可用事件來喚醒,
二、新建工程
1. 打開 STM32CubeMX 軟體,點擊“新建工程”

2. 選擇 MCU 和封裝

3. 配置時鐘
RCC 設定,選擇 HSE(外部高速時鐘) 為 Crystal/Ceramic Resonator(晶振/陶瓷諧振器)
開啟 LSE(外部低速時鐘) 為 Crystal/Ceramic Resonator(晶振/陶瓷諧振器)

選擇 Clock Configuration,配置系統時鐘 SYSCLK 為 72MHz
修改 HCLK 的值為 72 后,輸入回車,軟體會自動修改所有配置

4. 配置除錯模式
非常重要的一步,否則會造成第一次燒錄程式后續無法識別除錯器
SYS 設定,選擇 Debug 為 Serial Wire

三、睡眠模式
3.1 WFI任意中斷喚醒
3.1.1 流程圖

3.1.2 HAL庫與標準庫代碼比較
STM32CubeMX 使用 HAL 庫的代碼:
// 掛起(暫停)系統時鐘中斷
HAL_SuspendTick();
/* 進入睡眠模式, 任意中斷喚醒 */
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
/* 恢復系統時鐘中斷 */
HAL_ResumeTick();
使用 STM32 標準庫的代碼:
__WFI(); // WFI 指令進入睡眠
3.1.3 添加按鍵
初始化按鍵 PA0 中斷模式,以便當系統進入睡眠模式的時候可以通過按鍵來喚醒,
查看 STM32CubeMX學習筆記(3)——EXTI(外部中斷)介面使用
3.1.4 添加LED燈
添加綠燈 PB0 表示運行狀態,紅燈 PB5 表示睡眠狀態,藍燈 PB1 表示剛從睡眠狀態中被喚醒,
查看 STM32CubeMX學習筆記(2)——GPIO介面使用
3.1.5 生成代碼
輸入專案名和專案路徑

選擇應用的 IDE 開發環境 MDK-ARM V5

每個外設生成獨立的 ’.c/.h’ 檔案
不勾:所有初始化代碼都生成在 main.c
勾選:初始化代碼生成在對應的外設檔案, 如 GPIO 初始化代碼生成在 gpio.c 中,

點擊 GENERATE CODE 生成代碼

3.1.6 修改中斷回呼函式
當系統進入停止狀態后,我們按下實驗板上的 KEY1 按鍵,即可使系統回到正常運行的狀態,當執行完中斷服務函式后,會繼續執行
WFI指令后的代碼,
打開 stm32f1xx_it.c 中斷服務函式檔案,找到 EXTI0 中斷的服務函式 EXTI0_IRQHandler()
中斷服務函式里面就呼叫了 GPIO 外部中斷處理函式 HAL_GPIO_EXTI_IRQHandler()

打開 stm32f1xx_hal_gpio.c 檔案,找到外部中斷處理函式原型 HAL_GPIO_EXTI_IRQHandler(),其主要作用就是判斷是幾號線中斷,清除中斷標識位,然后呼叫中斷回呼函式 HAL_GPIO_EXTI_Callback(),

/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
這個函式不應該被改變,如果需要使用回呼函式,請重新在用戶檔案中實作該函式,
HAL_GPIO_EXTI_Callback() 按照官方提示我們應該再次定義該函式,__weak 是一個榷訓標識,帶有這個的函式就是一個榷訓函式,就是你可以在其他地方寫一個名稱和引數都一模一樣的函式,編譯器就會忽略這一個函式,而去執行你寫的那個函式;而 UNUSED(GPIO_Pin) ,這就是一個防報錯的定義,當傳進來的GPIO埠號沒有做任何處理的時候,編譯器也不會報出警告,其實我們在開發的時候已經不需要去理會中斷服務函式了,只需要找到這個中斷回呼函式并將其重寫即可而這個回呼函式還有一點非常便利的地方這里沒有體現出來,就是當同時有多個中斷使能的時候,STM32CubeMX會自動地將幾個中斷的服務函式規整到一起并呼叫一個回呼函式,也就是無論幾個中斷,我們只需要重寫一個回呼函并判斷傳進來的埠號即可,
接下來我們就在 stm32f1xx_it.c 這個檔案的最下面添加 HAL_GPIO_EXTI_Callback()
/* USER CODE BEGIN 1 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// 亮藍燈
HAL_GPIO_WritePin(GPIOB, LED_B_Pin, GPIO_PIN_RESET);
}
/* USER CODE END 1 */
3.1.7 修改main函式
初始化完成后使用 LED 及串口表示運行狀態,LED 燈為綠色時表示正常運行,紅燈時表示睡眠狀態,藍燈時表示剛從睡眠狀態中被喚醒,
程式執行一段時間后,直接使用
WFI指令進入睡眠模式,由于WFI睡眠模式可以使用任意中斷喚醒,所以我們可以使用按鍵中斷喚醒,在實際應用中,您也可以把它改成串口中斷、定時器中斷等,
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// 使用綠燈指示,運行狀態
HAL_GPIO_WritePin(GPIOB, LED_G_Pin, GPIO_PIN_RESET);
HAL_Delay(2000);
HAL_GPIO_WritePin(GPIOB, LED_G_Pin, GPIO_PIN_SET);
// 任務執行完畢,進入睡眠降低功耗
// 使用紅燈指示,進入睡眠狀態
HAL_GPIO_WritePin(GPIOB, LED_R_Pin, GPIO_PIN_RESET);
// 暫停滴答時鐘,防止通過滴答時鐘中斷喚醒
HAL_SuspendTick();
// 進入睡眠模式
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI);
// 被喚醒后,恢復滴答時鐘
HAL_GPIO_WritePin(GPIOB, LED_R_Pin, GPIO_PIN_SET);
HAL_ResumeTick();
HAL_Delay(2000);
HAL_GPIO_WritePin(GPIOB, LED_B_Pin, GPIO_PIN_SET);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
四、注意事項
用戶代碼要加在
USER CODE BEGIN N和USER CODE END N之間,否則下次使用 STM32CubeMX 重新生成代碼后,會被洗掉,

進入低功耗之前可以將引腳全部配置為浮空輸入或者Anglog模式,這樣最省電,如果你是用STM32CUBEMX,在這里可以看到這么一項配置就是將沒有用到的引腳配置為了Anglog模式:

當系統處于睡眠模式低功耗狀態時(包括后面講解的停止模式及待機模式),使用 DAP 下載器是無法給芯片下載程式的,所以下載程式時要先把系統喚醒,或者使用如下方法:按著板子的復位按鍵,使系統處于復位狀態,然后點擊電腦端的下載按鈕下載程式,這時再釋放復位按鍵,就能正常給板子下載程式了,
? 由 Leung 寫于 2021 年 3 月 3 日
? 參考:STM32CubeMX系列教程14:電源控制器(PWR)
STM32MX電源管理低功耗模式
STM32F1系列使用HAL庫低功耗STOP和STANDBY模式喚醒(RTC時鐘喚醒+外部中斷喚醒示例)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/266000.html
標籤:其他
上一篇:codeforces1494D. Dogeforces
下一篇:[HNOI2006]公路修建問題
