關(guān)于本博文的介紹:
- 基于STM32F103ZET芯片和3.5V標(biāo)準(zhǔn)庫
- 分開介紹兩種模式:獨立看門狗IWDG和窗口看門狗WWDG
- 從寄存器,介紹到對應(yīng)的庫函數(shù);
一 什么是看門狗?
單片機系統(tǒng)在正常執(zhí)行程序時,當(dāng)收到外界各種物理干擾或其他原因出現(xiàn)程序跑飛或者陷入死循環(huán)的現(xiàn)象,而使得正常的程序無法正常運行,導(dǎo)致MCU掛掉,看門狗就是為了解決這么個問題而出現(xiàn)的;
二 工作原理
在一定時間內(nèi)(時間由看門狗定時計數(shù)器決定)沒有接收到喂狗信號(表示MCU掛了),便實現(xiàn)處理器自動復(fù)位重啟(發(fā)出復(fù)位信號);
** IWDG和WWDG的時鐘源 **

從圖中可以看出:
1.獨立看門狗IWDG有自己獨立的時鐘源——LSI
2. 窗口看門狗WWDG的時鐘源——PCLK1
由此圖可以看出:在編程時,IWDG不需要使能時鐘源,而WWDG需要;所以IWDG的操作會比較簡單一些;
獨立看門狗定時器IWDG
一 相關(guān)寄存器以及功能
(1)鍵值寄存器IWDG_KR

功能和使用方法:
- 當(dāng)[15:0]位被寫入0xCCCC時,使能,此時寄存器從其0xFFF開始遞減計數(shù),當(dāng)遞減到0x0000時,會產(chǎn)生一個復(fù)位信號(IWDG_RESET)
- 當(dāng)[15 : 0]位被寫入0xAAAA時,IWDG_RLR寄存器中的值將會被重新加載到計數(shù)器中(這就是喂狗的過程),就是通過這個功能,從而避免產(chǎn)生MCU復(fù)位;
- 當(dāng)寄存器被寫入0x5555時,可以訪問IWDG_PR和IWDG_RLR寄存器;(這里要注意了,這個重要,因為如果IWDG_PR和IWDG_RLR不能被寫入數(shù)據(jù),也就是相當(dāng)于無法給IWDG預(yù)分頻和重載值)
(2)預(yù)分頻寄存器IWDG_PR

功能和使用:
對照著對[2:0]位的介紹選擇分頻因子;
(3)重載寄存器IWDG_RLR

功能和使用方法:看方框中吧;
(4)狀態(tài)寄存器IWDG_SR

功能和使用方法:看方框中吧;
二 編程步驟
-
取消寄存器寫保護(也即是先IWDG_KR中寫入0x5555)
目的:取消PR和RLR寄存器寫保護,從而可以操作這兩個寄存器
庫函數(shù):
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);
-
設(shè)置預(yù)分頻系數(shù)和重裝載值
庫函數(shù):
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);
void IWDG_SetReload(uint16_t Reload);
這里要明白一個重要的概念:
Tout(ms) = ((4*2^prer) * rlr)/40;
Tout:要設(shè)置的溢出時間,也就是多久初始化一次MCU,單位是ms
prer :分頻系數(shù)
rlr :重載值;
比如:prer = 4,rlr = 625時,Tout = 1000ms
-
重載計數(shù)值喂狗(向IWDG_KR寫入0xAAAA)
庫函數(shù):
void IWDG_ReloadCounter(void);
-
啟動看門狗(向IWDG_KR 寫入0xCCCC)
庫函數(shù):
void IWDG_Enable(void);
自此,整個程序就完成了;比較簡單;
窗口看門狗WWDG
“窗口”的原因:
因為喂狗的時間有一個時間上的限制,必須在一定時間范圍內(nèi)(窗口);這個時間范圍(窗口)上限是相關(guān)寄存器配置;下限時間是0x40;在這段時間內(nèi)要完成喂狗,否則將會發(fā)生MCU復(fù)位;
一 WWDG發(fā)出復(fù)位信號的條件
- 計數(shù)器的數(shù)值從0x40減到0x3F時候;
- 喂狗的時候,計數(shù)器的值大于WWDG_CFG寄存器設(shè)置的數(shù)值;
注意: 上面第二點需要特別注意,在后面進行編程的時候,我們會發(fā)現(xiàn)有兩個喂狗函數(shù):
1.看門狗設(shè)置計數(shù)器(喂狗)函數(shù)WWDG_SetCounter(0xXX),這是一個經(jīng)常放在WWDG中斷函數(shù)中的一個專門又來喂狗的函數(shù),0XX被送往CR寄存器;
2.看門狗啟動函數(shù)**WWDG_Enable(0xXX)**的這個括號里有一個0xXX值,也同樣被送到CR函數(shù)執(zhí)行了一次喂狗操作;
所以一定要注意一個原則:這兩個函數(shù)的實參都不能是大于窗口值,否則就直接發(fā)生復(fù)位了;
**二 WWDG的特點 **
當(dāng)MCU受到外界干擾或者內(nèi)部干擾時候,導(dǎo)致程序出現(xiàn)跑飛或者死循環(huán)現(xiàn)象的時候,有一種情況是:程序在死循環(huán)的時候同時執(zhí)行了喂狗程序,這就尷尬了,看門狗就無法起到了作用;
如果使用窗口看門狗,程序員可以根據(jù)程序執(zhí)行的時間設(shè)置刷新看門狗的一個時間窗口,保證不會提前刷新看門狗或滯后刷新看門狗,這樣可以檢測出程序有沒有正常的執(zhí)行程序;
三 相關(guān)寄存器功能
先總結(jié)一下:
控制寄存器——WWDG_CR——使能WWDG,WWDG倒計數(shù)計時器;
配置寄存器——WWDG_CFG——設(shè)置喚醒中斷標(biāo)志位,設(shè)置分頻因子,設(shè)置上窗口的值;
狀態(tài)寄存器——WWDG_SR——喚醒中斷位中斷標(biāo)志;
- 控制寄存器WWDG_CR

功能和使用:
[7]:WWDG功能的開關(guān)位;
[6:0] : 1. 這7位的值為要遞減的值;
2. 喂狗就是要對這7位賦值(賦值的時候絕對不能大于窗口值);
3. 這幾個位所能承受的最大值0x7F,最小值是0x40;
2.配置寄存器WWDG_CFG

[9] : EWI提前喚醒中斷,說白了此位置1會開啟WWDG中斷,調(diào)用相應(yīng)中斷相應(yīng)函數(shù);
[8:7]:設(shè)置分頻因子;經(jīng)過此處分頻后,即可得到CR寄存器中的遞減周期;
[6:0]:窗口值,是可以喂狗和不可以喂狗的臨界點,當(dāng)此處的值大于計數(shù)器的值時方可喂狗,否則不可喂狗;
3.狀態(tài)寄存器WWDG_SR

當(dāng)EWIF位被置1,說明程序正在執(zhí)行中斷函數(shù)或并沒有開啟WWDG中斷
四 窗口看門狗WWDG關(guān)于周期的計算:
《STM32f103使用手冊》中給出了下面這個超時公式,但是我覺得實在是有些無厘頭的計算,為什么要給一個T[5:0]的計算,并且我也沒搞懂所謂的超時公式這個“超時”到底超的是誰;所以我覺得要正確的配置窗口值和喂狗的值只要對計數(shù)器T[6:0]的遞減周期足夠理解就好了;

所以我總結(jié)如下:
一,計數(shù)器T[6:0]的遞減周期:T1 = (4096*2^WDGTB)/PCLK1;
PCLK1:APB1上的時鐘頻率,在庫函數(shù)提供的默認配置下,PCLK1默認為36MHz;
WDGTB:分頻系數(shù)(1,2,4,8);
二,在配置窗口值,喂狗值時要遵循的規(guī)則:
0x7F >= 窗口值 >= 喂狗值 >=0x41;
超時時間范圍:(圖片下方用我總結(jié)的計數(shù)器遞減周期公式計算一下怎么得到的下邊的這個表格)

例如:當(dāng)配置將使WDGTB=2^3時,PCLK1=36MHz時,可得遞減周期約為910us,然而我們又知道T[6:0]的最大值為0x7f,最小值為0x40,則(0x7f - 0x3f)=0x40=64(十進制),即 64*910=58240us=58.240≈58.25ms;當(dāng)窗口值和喂狗值同時設(shè)置為0x41時,中斷周期就是910us,為0x7f時,中斷周期就是58.25ms;所以當(dāng)WDGTB=8時,中斷周期就可以認為的在910us~58.25ms中間設(shè)定;事實就是這樣;
編程思路

五 編程步驟
一定要切記這個步驟,不然因為對EWIF位的不理解導(dǎo)致錯誤
(1) 開啟WWDG時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
(2)設(shè)置窗口值和分頻系數(shù)值(配置WWDG_CFG)
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);//設(shè)置分頻因子
void WWDG_SetWindowValue(uint8_t WindowValue);//設(shè)置窗口值
(3)使能WWDG,并加載初值
void WWDG_Enable(uint8_t Counter);
這里需要特別注意:如果說Counter的值為0x7F(MAX),會使得WWDG_SR寄存器中的EWIF位(提醒中斷標(biāo)志位)。
(4)配置WWDG的中斷NVIC
(5)開啟WWDG中斷并清除提醒中斷標(biāo)志位EWIF;
void WWDG_EnableIT(void); /
void WWDG_ClearFlag(void); //WWDG_SR的EWIF清零,如果不清零會使得程序無法進入到WWDG中斷函數(shù);
(6)中斷函數(shù)
void WWDG_IRQHandler(void)
{
if(WWDG_GetFlagStatus())
{
WWDG_SetCounter(喂狗值);
//邏輯代碼;
}
WWDG_ClearFlag();
}
IWDG和WWDG的區(qū)別;
- 從編程的角度來說,IWDG沒有相應(yīng)的中斷函數(shù),而WWDG有相應(yīng)的中斷函數(shù),所以如果想完成喂狗操作,IWDG只能是通過main函數(shù)里的循環(huán)執(zhí)行達到喂狗的操作,而WWDG可以通過在中斷函數(shù)內(nèi)執(zhí)行喂狗程序;也因此,在使用WWDG是要配置相應(yīng)的NVIC,而IWDG不用;
|