記錄一下,方便以後翻閱~
主要內容:
1) STM32低功耗模式講解;
2) 寄存器和庫函數配置;
3) 實驗代碼解讀。
實驗功能:針對GPIOA,引腳0,啓動後系統進入待機模式,長按3秒待機喚醒,LED0和LED1閃爍,長按3秒進入待機模式,LED0和LED1滅。
官方資料:《STM32中文參考手冊V10》第4章——低功耗模式
1. 待機喚醒
很多單片機有低功耗模式,STM32也不例外。在系統或者電源復位後,微控制器處於運行狀態之下,HCLK爲CPU提供時鐘,內核執行代碼。當CPU不需要繼續運行時,可以利用多種低功耗模式來節省功耗,例如等待某個事件觸發。
2. 低功耗模式:
2.1 睡眠模式:內核停止,外設如NVIC,系統時鐘Systick仍運行;
2.2 停止模式:所有時鐘都已停止。1.8V內核電源工作。PLL,HIS和HSE RC振盪器功能禁止。寄存器和SRAM內容保留;
2.3 待機模式:1.8V內核電源關閉。只有備份寄存器和待機電路維持供電。寄存器和SRAM內容全部丟失。實現最低功耗。
功耗消耗排序:睡眠模式>停止模式>待機模式(功耗消耗最低)
2.4 運行模式下降低功耗的辦法:
2.4.1 降低系統時鐘;
2.4.2 關閉APB和AHB總線上未被使用的外設時鐘。
用戶可根據電源消耗,最快啓動時間和可用的喚醒源等條件,選擇一種最佳的低功耗模式。
3. STM32的待機模式
待機模式理想狀態下,只需要2uA電流。停機模式下典型電流爲20uA。
4. 相關寄存器
4.1 PWR_CR電源控制寄存器:
4.1.1 設置PDDS位進入深度睡眠時進入待機模式;
4.1.2 設置CWUF位,清除之前的WUF喚醒位。
4.2 PWR_CSR電源控制/狀態寄存器:
4.1.1 設置EWUP,使能WKUP引腳用於待機模式喚醒;
4.1.2 WUF喚醒標誌,用來判斷是否發生喚醒事件。
5. 相關庫函數
5.1 官方文件爲stm32f10x_pwr.c / stm32f10x_pwr.h;
5.2 主要庫函數:
voidPWR_EnterSTOPMode(); //進入停機模式
voidPWR_EnterSTANDBYMode(void); //進入待機模式
void PWR_WakeUpPinCmd(FunctionalState NewState); //使能Wakeup引腳喚醒
FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG);
void PWR_ClearFlag(uint32_t PWR_FLAG);
6. 待機喚醒配置步驟:
6.1 使能電源時鐘。因爲要配置電源控制寄存器,所以必須先使能電源時鐘:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
6.2 設置WK_UP引腳作爲喚醒源。設置PWR_CSR的EWUP位,使能WK_UP用於將CPU從待機模式喚醒:
PWR_WakeUpPinCmd(ENABLE); //使能喚醒管腳功能
6.3 設置SLEEPDEEP位,設置PDDS位,執行WFI指令,進入待機模式:
void PWR_EnterSTANDBYMode(void);
7. 程序思路
7.1 在待機模式下,WKUP用來喚醒。按下WKUP,就會從待機模式喚醒;
7.2 正常情況下(沒有進入低功耗模式),WKUP是可以作爲正常的輸入口,或者中斷觸發引腳來使用。
8. 相關實驗代碼解讀
8.1 wkup.h頭文件代碼
#ifndef __WKUP_H
#define __WKUP_H
#include "sys.h"
#define WKUP_KD PAin(0) //位帶操作,WKUP_KD對應GPIOA_IDR的0位//
//三個函數//
u8 Check_WKUP(void); //檢測WKUP腳的信號,返回u8格式數據//
void WKUP_Init(void); //PA0 WKUP喚醒初始化//
void Sys_Enter_Standby(void); //系統進入待機模式//
#endif
8.2 wkup.c文件代碼解讀
#include "wkup.h"
#include "led.h"
#include "delay.h"
//待機喚醒配置函數//
void Sys_Standby(void)
{
//第一步,使能PWR外設時鐘//
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
//第二步,設置PWR_CSR的EWUP位,使能WK_UP用於將CPU從待機模式喚醒//
PWR_WakeUpPinCmd(ENABLE);
//第三步,進入待機模式//
PWR_EnterSTANDBYMode();
}
//系統進入待機模式//
void Sys_Enter_Standby(void)
{
RCC_APB2PeriphResetCmd(0X01FC,DISABLE); //復位所有IO口
Sys_Standby();
}
//檢測WKUP腳的信號,純C語言//
//返回值1:連續按下3s以上;0:錯誤的觸發//
u8 Check_WKUP(void)
{
u8 t=0; //記錄按下的時間//
LED0=1; //LED0滅//
LED1=1; //LED1滅//
while(1)
{
if(WKUP_KD) //WK_UP按鍵對應PA0,即按下時爲高電平//
{
t++; //已經按下了//
LED0=!LED0;
LED1=!LED1;
delay_ms(30);
if(t>=100) //按下超過3秒鐘//
{
LED0=0; //LED0亮//
LED1=0;
return 1; //按下3s以上了//
}
}else
{
LED0=1; //LED0滅//
LED1=1; //LED0滅//
return 0; //按下不足3秒//
}
}
}
//編寫外部中斷服務函數//
void EXTI0_IRQHandler(void) //因爲檢測PA0,所以用EXTI0//
{
EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中斷標誌位//
if(Check_WKUP()) //檢查WK_UP是否按下3s以上//
{
Sys_Enter_Standby(); //按下3s以上,系統進入待機模式//
}
}
//編寫WK_UP初始化函數//
void WKUP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
//使能GPIOA和複用功能時鐘//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
//GPIOA,引腳0配置//
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0; //GPIOA,引腳0//
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPD; //上拉輸入//
GPIO_Init(GPIOA, &GPIO_InitStructure);
//使用外部中斷方式//
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //中斷線0連接GPIOA.0//
EXTI_InitStructure.EXTI_Line = EXTI_Line0; //設置按鍵所有的外部線路//
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中斷模式//
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿觸發//
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能//
EXTI_Init(&EXTI_InitStructure);
//中斷優先級初始化//
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按鍵所在的外部中斷通道//
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先佔優先級2級//
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //從優先級2級//
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中斷通道//
NVIC_Init(&NVIC_InitStructure);
if(Check_WKUP()==0) Sys_Standby(); //不是開機,進入待機模式//
}
8.3 main.c文件代碼
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "wkup.h"
int main(void)
{
delay_init(); //延時函數初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置中斷優先級分組爲組2//
uart_init(115200); //串口初始化爲115200
LED_Init(); //LED端口初始化
LED0=0;
LED1=0;
delay_ms(500);
WKUP_Init(); //待機喚醒初始化
while(1)
{
LED0=!LED0;
LED1=!LED1;
delay_ms(1000);
}
}
9. 舊知識點
1)複習如何新建工程模板,可參考STM32學習心得二:新建工程模板;
2)複習基於庫函數的初始化函數的一般格式,可參考STM32學習心得三:GPIO實驗-基於庫函數;
3)複習寄存器地址,可參考STM32學習心得四:GPIO實驗-基於寄存器;
4)複習位操作,可參考STM32學習心得五:GPIO實驗-基於位操作;
5)複習寄存器地址名稱映射,可參考STM32學習心得六:相關C語言學習及寄存器地址名稱映射解讀;
6)複習時鐘系統框圖,可參考STM32學習心得七:STM32時鐘系統框圖解讀及相關函數;
7)複習延遲函數,可參考STM32學習心得九:Systick滴答定時器和延時函數解讀;
8)複習ST-LINK仿真器的參數配置,可參考STM32學習心得十:在Keil MDK軟件中配置ST-LINK仿真器;
9)複習ST-LINK調試方法,可參考STM32學習心得十一:ST-LINK調試原理+軟硬件仿真調試方法;
10)複習如何對GPIO進行復用,可參考STM32學習心得十二:端口複用和重映射;
11)複習中斷相關知識,可參考STM32學習心得十三:NVIC中斷優先級管理;
12)複習串口通信相關知識,可參考STM32學習心得十四:串口通信相關知識及配置方法;
13)複習通用定時器基本原理,可參考STM32學習心得十八:通用定時器基本原理及相關實驗代碼解讀;
14)複習USMART調試工具,可參考STM32學習心得二十:USMART調試組件實驗。