在單片機(jī)構(gòu)成的微型計(jì)算機(jī)系統(tǒng)中,由于單片機(jī)的工作容易受到來自外界電磁場的干擾,導(dǎo)致程序跑飛,陷入死循環(huán),程序的正常運(yùn)行被打斷,由單片機(jī)控制的系統(tǒng)無法繼續(xù)工作,會造成整個(gè)系統(tǒng)的陷入停滯狀態(tài),發(fā)生不可預(yù)料的后果。
所以出于對單片機(jī)運(yùn)行狀態(tài)進(jìn)行實(shí)時(shí)監(jiān)測的考慮,便產(chǎn)生了一種專門用于監(jiān)測單片機(jī)程序運(yùn)行狀態(tài)的模塊或者芯片,俗稱“看門狗”(watchdog) 。
在啟動正常運(yùn)行的時(shí)候,若系統(tǒng)不能復(fù)位,或者在系統(tǒng)跑飛(程序異常執(zhí)行)的情況下,看門狗可以觸發(fā)系統(tǒng)復(fù)位,程序重新執(zhí)行。
STM32F10x 內(nèi)置 兩個(gè)看門狗
提供了更高的安全性、時(shí)間的精確性和使用的靈活性。
兩個(gè)看門狗設(shè)備(獨(dú)立看門狗和窗口看門狗)可用來檢測和解決由軟件錯(cuò)誤引起的故障;當(dāng)計(jì)數(shù)器達(dá)到給定的超時(shí)值時(shí),觸發(fā)一個(gè)中斷(僅適用于窗口型看門狗)或產(chǎn)生系統(tǒng)復(fù)位。
獨(dú)立看門狗(IWDG)由專用的低速時(shí)鐘(LSI)驅(qū)動,即使主時(shí)鐘發(fā)生故障它也仍然有效。
窗口看門狗由從APB1時(shí)鐘分頻后得到的時(shí)鐘驅(qū)動,通過可配置的時(shí)間窗口來檢測應(yīng)用程序非正常的過遲或過早的操作。
看門狗應(yīng)用場景
獨(dú)立看門狗使用專用的低速時(shí)鐘(LSI)驅(qū)動),適合應(yīng)用于需要看門狗作為一個(gè)在主程序之外 能夠完全獨(dú)立工作,并且對時(shí)間精度要求低的場合。
窗口看門狗從APB1時(shí)鐘分頻后得到時(shí)鐘驅(qū)動,最適合那些要求看門狗在精確計(jì)時(shí)窗口起作用的程序。
在鍵值寄存器(IWDG_KR)中寫入0xCCCC,開始啟用獨(dú)立看門狗。
此時(shí)計(jì)數(shù)器開始從其復(fù)位值0xFFF遞減,當(dāng)計(jì)數(shù)器值計(jì)數(shù)到尾值0x000時(shí)會產(chǎn)生一個(gè)復(fù)位信號(IWDG_RESET)。
無論何時(shí),只要在鍵值寄存器IWDG_KR中寫入0xAAAA(通常說的喂狗), 自動重裝載寄存器IWDG_RLR的值就會重新加載到計(jì)數(shù)器,從而避免看門狗復(fù)位。
如果程序異常,就無法正常喂狗,從而系統(tǒng)復(fù)位
時(shí)鐘頻率為40khz,若選擇: 預(yù)分頻 4 ,重轉(zhuǎn)載值0xFFF
最長時(shí)間:1s / (40000hz /4) * 0x1000 * 1000 = 409.6ms
取消寄存器寫保護(hù):0x5555使能
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);
設(shè)置獨(dú)立看門狗的預(yù)分頻系數(shù),確定時(shí)鐘,寫PR
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);
設(shè)置重裝載值:確定溢出時(shí)間,寫RLR
void IWDG_SetReload(uint16_t Reload);
使能看門狗:寫0xCCCC到KR
void IWDG_Enable(void);
喂狗:寫0xAAAA到KR
void IWDG_ReloadCounter(void);
獲取狀態(tài):重裝載/預(yù)分頻 更新
FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);
代碼部署如下:
喂狗標(biāo)志為0時(shí),不執(zhí)行喂狗,系統(tǒng)一直復(fù)位;
喂狗標(biāo)志不為0時(shí),執(zhí)行喂狗,系統(tǒng)正常運(yùn)行;
int sign; //喂狗標(biāo)記 int main(void) { IWDG_Init(4,625); //與分頻數(shù)為64,重載值為625,溢出時(shí)間為1s while(1) { if(sign != 0) { IWDG_Feed();//如果WK_UP按下,則喂狗 } }; }
在初始化處打斷點(diǎn),
設(shè)置sign = 0時(shí),每個(gè)一秒重新執(zhí)行初始化;
再設(shè)置sign = 3時(shí),不重新初始化,正常運(yùn)行;
重新設(shè)置sign = 0時(shí),重新執(zhí)行初始化;
窗口看門狗,之所以稱為窗口是因?yàn)槠湮构窌r(shí)間是一個(gè)有上下限的范圍(窗口),喂狗的時(shí)間不能過早也不能過晚。(上限:0x7FH-0x40H,下限:0x3FH,若上限值小于0x3FH,則無窗口直接復(fù)位 )
使用窗口看門狗,可以根據(jù)預(yù)測的程序正常執(zhí)行的時(shí)間設(shè)置刷新看門狗的時(shí)間窗口,保證不會提前刷新看門狗也不會滯后刷新看門狗,就可以檢測程序是否正常運(yùn)行,非正常地跳過某些程序段的情況。
當(dāng)喂狗的時(shí)候如果計(jì)數(shù)器的值大于某一設(shè)定數(shù)值W[6:0]時(shí),此設(shè)定數(shù)值在WWDG_CFR寄存器定義。
當(dāng)計(jì)數(shù)器的數(shù)值從0x40減到0x3F時(shí)【T6位跳變到0】
PCLK1 = 36MHZ,若WDGTB = 0,則:
最長時(shí)間:1000ms / (36000000hz) * 4096 * 2 o * (0x3F +1) = 7.2818ms
使能看門狗時(shí)鐘
RCC_APB1PeriphClockCmd();
設(shè)置分頻系數(shù)
WWDG_SetPrescaler();
設(shè)置上窗口值
WWDG_SetWindowValue();
開啟提前喚醒中斷并分組(可選)
WWDG_EnableIT();
NVIC_Init();
使能看門狗
WWDG_Enable();
喂狗
WWDG_SetCounter();
編寫中斷服務(wù)函數(shù)
WWDG_IRQHandler();
注釋 main 中 while 內(nèi)的喂狗部分代碼,通過 “Record”獲取喂狗計(jì)數(shù)值。
“WWDG_IRQHandler” 在計(jì)數(shù)值為 0x40時(shí)觸發(fā)。
由于監(jiān)視窗口刷新問題,可知 “Record”至少為 266369 ;
則開放 main 中 while 內(nèi)的喂狗部分代碼,將“sign”設(shè)為50000(小于Record值,沒有標(biāo)準(zhǔn)計(jì)時(shí),故測試了幾個(gè)值,需要保證喂狗時(shí),看門狗計(jì)數(shù)值在窗口值與0x3F之間,選擇合適的50000),進(jìn)行喂狗,則不觸發(fā)看門狗中斷,也不進(jìn)行復(fù)位。此時(shí)修改sign為20000,過早喂狗,相當(dāng)于程序運(yùn)行不正常,系統(tǒng)復(fù)位初始化;