本內容基于江協科技STM32視頻學習之后整理而得。
文章目錄
- 1. PWR
- 1.1 PWR簡介
- 1.2 電源框圖
- 1.3 上電復位和掉電復位
- 1.4 可編程電壓監測器
- 1.5 低功耗模式
- 1.6 模式選擇
- 1.7 睡眠模式
- 1.8 停止模式
- 1.9 待機模式
- 1.10 庫函數
- 2. WDG看門狗
- 2.1 WDG簡介
- 2.2 IWDG框圖
- 2.3 IWDG鍵寄存器
- 2.4 IWDG超時時間
- 2.5 WWDG框圖
- 2.6 WWDG工作特性
- 2.7 WWDG超時時間
- 2.8 IWDG和WWDG對比
- 2.9 獨立看門狗庫函數
- 2.10 窗口看門狗庫函數
1. PWR
1.1 PWR簡介
- PWR(Power Control)電源控制
- PWR負責管理STM32內部的電源供電部分,可以實現可編程電壓監測器和低功耗模式的功能
- 可編程電壓監測器(PVD)可以監控VDD電源電壓,當VDD下降到PVD閥值以下或上升到PVD閥值之上時,PVD會觸發中斷,用于執行緊急關閉任務
- 低功耗模式包括睡眠模式(Sleep)、停機模式(Stop)和待機模式(Standby),可在系統空閑時,降低STM32的功耗,延長設備使用時間
1.2 電源框圖
- 上面是模擬部分供電:包括AD轉換器、溫度傳感器、復位模塊、PLL鎖相環。供電正極是VDDA,負極是VSSA。AD轉換器還有兩個參考電壓的引腳VREF+和VREF-。
- 中間是數字部分供電,包括VDD供電區域和1.8V供電區域。VDD供電區域包括I/O電路、待機電路(喚醒邏輯、IWDG),右邊是VDD通過電壓調節器降壓到1.8V。1.8V供電區域包括CPU核心、存儲器和內置數字外設。
- 下面是后備供電VBAT,包括LSE_32K晶體振蕩器、后備寄存器、RCC_BDCR寄存器(是RCC的寄存器,叫做備份域控制寄存器)、RTC
1.3 上電復位和掉電復位
當VDD、VDDA電壓過低時,內部電路直接產生復位,讓STM32復位住,不要亂操作。在復位與不復位之間設置了一個40mV遲滯電壓,大于上限POR時解除復位,小于下限PDR時復位。設置兩個閾值的作用,
就是防止電壓在某個閾值附近波動時,造成輸出也來回抖動。復位信號Reset是低電平有效的,所以在前面和后面,電壓過低時,是復位的。
中間電壓正常的時候,不復位。
1.4 可編程電壓監測器
與上電復位和掉電復位差不多。但首先它的這個閾值電壓是可以使用程序指定的,可以自定義調節。
1.5 低功耗模式
- 睡眠模式通過WFI和WFE就可進入,WFI和WFE是內核的指令。
- WFI(Wait For Interrupt)等待中斷。喚醒條件是任一中斷,通過WFI指令進入睡眠模式,當任何外設發生任何中斷時,芯片就會立刻醒來,醒來后就是處理中斷函數。
- WFE(Wait For Event)等待事件,喚醒條件是喚醒事件,該事件可以是外部中斷配置為事件模式,也可以是使能了中斷,但沒有配置NVIC。調用WFE進入的睡眠模式,產生喚醒事件時,會立刻醒來,醒來之后,一般不需要進中斷函數,直接從睡的地方繼續運行。
- 睡眠模式對電路的影響是:只把CPU時鐘關了,對其他電路沒有任何操作。CPU時鐘關了,程序就會暫停,不會繼續運行了。CPU 不運行,芯片功耗就會降低。關閉電路一般有兩個做法:一個是關閉時鐘,另一個是關閉電源。關閉時鐘,所有的運算和涉及時序的操作都會暫停。但寄存器和存儲器里保存的數據還可以維持,不會消失。關閉電源,就是電路直接斷電。電路的操作和數據會直接丟失。所以關閉電源比關閉時鐘更省電。
- 停機模式:SLEEPDEEP設置為1,即將深度睡眠。
- PDDS是用來區分是停機模式還是待機模式,PDDS=0進入停機模式,PDDS=1進入待機模式,LPDS用來設置電壓調節器,LPDS=0開啟,LPDS=1進入低功耗模式。再調用WFI或WFE,芯片就進入停止模式了。任一外部中斷喚醒。PVD、TRC鬧鐘、USB喚醒、ETH喚醒借道了外部中斷,這4個信號也可以喚醒停止模式。
- 對時鐘的影響:CPU、定時器、串口都會停止運行,但由于沒有關閉電源,所以CPU和外設的寄存器數據都是維持原狀的。HSI和HSE的振蕩器關閉。
- 待機模式:SLEEPDEEP置1,PDDS=1,再調用WFI或WFE,芯片就進入待機模式了。
- 普通外設的中斷和外部中斷都無法喚醒待機模式,只有:WKUP引腳的上升沿、RTC鬧鐘事件、NRST引腳上的外部復位、IWDG復位。把能關的全關了,只保留幾個喚醒的功能。
1.6 模式選擇
- 執行WFI(Wait For Interrupt)或者WFE(Wait For Event)指令后,STM32進入低功耗模式
1.7 睡眠模式
- 執行完WFI/WFE指令后,STM32進入睡眠模式,程序暫停運行,喚醒后程序從暫停的地方繼續運行
- SLEEPONEXIT位決定STM32執行完WFI或WFE后,是立刻進入睡眠,還是等STM32從最低優先級的中斷處理程序中退出時進入睡眠
- 在睡眠模式下,所有的I/O引腳都保持它們在運行模式時的狀態
- WFI指令進入睡眠模式,可被任意一個NVIC響應的中斷喚醒
- WFE指令進入睡眠模式,可被喚醒事件喚醒
1.8 停止模式
- 執行完WFI/WFE指令后,STM32進入停止模式,程序暫停運行,喚醒后程序從暫停的地方繼續運行
- 1.8V供電區域的所有時鐘都被停止,PLL、HSI和HSE被禁止,SRAM和寄存器內容被保留下來
- 在停止模式下,所有的I/O引腳都保持它們在運行模式時的狀態
- 當一個中斷或喚醒事件導致退出停止模式時,HSI被選為系統時鐘
- 當電壓調節器處于低功耗模式下,系統從停止模式退出時,會有一段額外的啟動延時
- WFI指令進入停止模式,可被任意一個EXTI中斷喚醒
- WFE指令進入停止模式,可被任意一個EXTI事件喚醒
1.9 待機模式
- 執行完WFI/WFE指令后,STM32進入待機模式,喚醒后程序從頭開始運行
- 整個1.8V供電區域被斷電,PLL、HSI和HSE也被斷電,SRAM和寄存器內容丟失,只有備份的寄存器和待機電路維持供電
- 在待機模式下,所有的I/O引腳變為高阻態(浮空輸入)
- WKUP引腳的上升沿、RTC鬧鐘事件的上升沿、NRST引腳上外部復位、IWDG復位退出待機模式
1.10 庫函數
// 恢復缺省配置
void PWR_DeInit(void);
// 使能后備區域的訪問
void PWR_BackupAccessCmd(FunctionalState NewState);
// 使能PVD
void PWR_PVDCmd(FunctionalState NewState);
// 配置PVD的閾值電壓
void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel);
// 使能位于PA0位置的WKUP引腳,配合待機模式使用
void PWR_WakeUpPinCmd(FunctionalState NewState);
// 進入停止模式
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry);
// 進入待機模式
void PWR_EnterSTANDBYMode(void);FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG);
void PWR_ClearFlag(uint32_t PWR_FLAG);
2. WDG看門狗
2.1 WDG簡介
- WDG(Watchdog)看門狗
- 看門狗可以監控程序的運行狀態,當程序因為設計漏洞、硬件故障、電磁干擾等原因,出現卡死或跑飛現象時,看門狗能及時復位程序,避免程序陷入長時間的罷工狀態,保證系統的可靠性和安全性
- 看門狗本質上是一個定時器,當指定時間范圍內,程序沒有執行喂狗(重置計數器)操作時,看門狗硬件電路就自動產生復位信號
- STM32內置兩個看門狗
- 獨立看門狗(IWDG):獨立工作,對時間精度要求較低
- 窗口看門狗(WWDG):要求看門狗在精確計時窗口起作用
2.2 IWDG框圖
預分頻器的輸入時鐘是LSI(內部低速時鐘),時鐘頻率是40kHz。之后,時鐘進入預分頻器進行分頻,預分頻器只有8位,最大只能進行256分頻。預分頻寄存器IWDG_PR,可以配置分頻系數。經過預分頻器進行分頻之后,時鐘驅動遞減計數器,每來一個時鐘,自減一個數,遞減計數器是12位的,所以最大值是2^12-1=4095,當自減到0之后,產生IWDG復位。為了避免提前復位,可以提前在重裝寄存器寫一個值,IWDG_RLR和定時器的ARR一樣,預先寫好值之后,在鍵寄存器里寫一個特定數據,控制電路,進行喂狗,這時重裝值就會復制到當前的計數器中,這樣計數器就會回到重裝值,重新自減運行了。
狀態寄存器SR:標志電路運行的狀態,
2.3 IWDG鍵寄存器
- 鍵寄存器本質上是控制寄存器,用于控制硬件電路的工作
- 在可能存在干擾的情況下,一般通過在整個鍵寄存器寫入特定值來代替控制寄存器寫入一位的功能,以降低硬件電路受到干擾的概率
寫入鍵寄存器的值 | 作用 |
---|---|
0xCCCC | 啟用獨立看門狗 |
0xAAAA | IWDG_RLR中的值重新加載到計數器(喂狗) |
0x5555 | 解除IWDG_PR和IWDG_RLR的寫保護 |
0x5555之外的其他值 | 啟用IWDG_PR和IWDG_RLR的寫保護 |
2.4 IWDG超時時間
超時時間:TIWDG = TLSI × PR預分頻系數 × (RL + 1)
其中:TLSI = 1 / FLSI
2.5 WWDG框圖
- 時鐘來源是PCLK1,即APB1的時鐘,默認是36MHz,時鐘進來之后,先經過一個預分頻器進行分頻,分頻之后的時鐘驅動計數器進行計數,每來一個時鐘,自減一次。該計數器之后T5~T0是有效的計數值,最高位T6用來當作溢出標志位,T6=1表示計數器沒溢出,T6=0表示計數器溢出。
- WDGA是窗口看門狗的激活位,也是使能,WDGA寫入1,啟用窗口看門狗,使能位作用于這個與門,與門的作用就類似于一個開關,左邊是控制信號,右邊是輸入,上邊是輸出,控制信號為1,則輸出等于輸入,開關導通,控制信號給0,則輸出等于0,與輸入無關,開關斷開。開關右邊就是復位信號的來源,有兩個來源,用或門連接,也就是這兩個來源任意一個都可以復位,下面這一路來源于溢出標志位T6,當計數器溢出時T6等于0。然后輸入進來,這里輸入有個小圓圈,代表輸入取反,所以0變為1,或門有效,輸出1,當最后這個使能位給1,開啟看門狗后,溢出信號就直接通向復位了。T6位一旦等于0,就表示計數器溢出,就產生復位信號。在程序正常運行狀態下,必須始終保證T6位為1,這樣才能避免復位。
- 喂狗的最早界限由上面的看門狗配置寄存器設置。首先需要計算一個最早界限的計數值,寫入W6~W0。這些值寫入之后是固定不變的。一旦執行寫入WWDG_CR操作時,與門開關就會打開。寫入CR就是寫入計數器,也就是喂狗。在喂狗時,比較器開始工作,一旦當前計數器T6:0>窗口值W6:0,比較結果就=1,這個1,通過或門也可以去申請復位。
- 總結:喂狗太晚,6位計數器減到0了,復位;喂狗太早,計數器的值超過窗口值了,復位。
2.6 WWDG工作特性
- 遞減計數器T[6:0]的值小于0x40時,WWDG產生復位(0x3F)
- 遞減計數器T[6:0]在窗口W[6:0]外被重新裝載時,WWDG產生復位----不能過早喂狗
- 遞減計數器T[6:0]等于0x40時可以產生早期喚醒中斷(EWI),用于重裝載計數器以避免WWDG復位----
- 定期寫入WWDG_CR寄存器(喂狗)以避免WWDG復位
2.7 WWDG超時時間
-
超時時間:就是喂狗的最晚時間
TWWDG = TPCLK1 × 4096 × WDGTB預分頻系數 × (T[5:0] + 1)
-
窗口時間:喂狗的最早時間
TWIN = TPCLK1 × 4096 × WDGTB預分頻系數 × (T[5:0] - W[5:0])
-
其中:TPCLK1 = 1 / FPCLK1
2.8 IWDG和WWDG對比
WDG獨立看門狗 | WWDG窗口看門狗 | |
---|---|---|
復位 | 計數器減到0后 | 計數器T[5:0]減到0后、過早重裝計數器 |
中斷 | 無 | 早期喚醒中斷 |
時鐘源 | LSI(40KHz) | PCLK1(36MHz) |
預分頻系數 | 4、8、32、64、128、256 | 1、2、4、8 |
計數器 | 12位 | 6位(有效計數) |
超時時間 | 0.1ms~26214.4ms | 113us~58.25ms |
喂狗方式 | 寫入鍵寄存器,重裝固定值RLR | 直接寫入計數器,寫多少重裝多少 |
防誤操作 | 鍵寄存器和寫保護 | 無 |
用途 | 獨立工作,對時間精度要求較低 | 要求看門狗在精確計時窗口起作用 |
2.9 獨立看門狗庫函數
// 寫使能控制,0x5555
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);
// 寫預分頻器
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);
// 寫重裝值
void IWDG_SetReload(uint16_t Reload);
// 重新裝載寄存器,即喂狗,0xAAAA
void IWDG_ReloadCounter(void);
// 啟動獨立看門狗,0xCCCC
void IWDG_Enable(void);FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);// 查看標志位函數,來看復位是不是看門狗引起的
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG);
void RCC_ClearFlag(void);
2.10 窗口看門狗庫函數
// 恢復缺省配置
void WWDG_DeInit(void);// 寫入預分頻器
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);
// 寫入窗口值
void WWDG_SetWindowValue(uint8_t WindowValue);
// 使能中斷
void WWDG_EnableIT(void);
// 寫入計數器,即喂狗
void WWDG_SetCounter(uint8_t Counter);
// 使能窗口看門狗
void WWDG_Enable(uint8_t Counter);FlagStatus WWDG_GetFlagStatus(void);
void WWDG_ClearFlag(void);