SATM32單片機的看門狗有獨立看門狗和窗口看門狗之分,這二者的工做原理卻徹底不一樣,今天來看一下他們的具體區別和配置方法。
▍STM32獨立看門狗由專門的低速時鐘(LSI)驅動,即使是主時鐘發生故障它仍可以有效,因此此狗狗能夠工做在與主時鐘無關的要求下,或者待機模塊下等,因此它叫獨立看門狗,注意一旦開啓此看門狗則只能由MCU復位後才清除,讓它再也不工做。它的時鐘是一個內部RC時鐘,它會在30KHZ到60KHZ之間變化,並不是是精確的40KHZ,而只是通常計算時取40KHZ。獨立看門狗需設置四個寄存器以下:
![watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=](http://static.javashuo.com/static/loading.gif)
其中,預分頻寄存器(IWDG_PR),最低三位PR[2:0](Prescaler divider)有效,可設置有8種不一樣的計數器時鐘預分頻因子。重裝載寄存器(IWDG_RLR)低12位RL[11:0]: 看門狗計數器重裝載值 (Watchdog counter reload value) 有效,用來設置計數器的重裝載值。注意要設置以上兩個寄存器的值需知足兩個條件,詳見以下:鍵寄存器(IWDG_KR),用來控制去除IWDG_PR和IWDG_RLR寫保護功能以便正常寫值,向此寄存器寫入0x5555則暫時去除IWDG_PR和IWDG_RLR的寫保護功能纔可向兩個寄存器中寫值。當向此寄存器寫入0xAAAA則IWDG_RLR的值會重裝載,防止MCU復位,向入0xCCCC是開啓狗立看門狗動做。狀態寄存器(IWDG_SR)最低兩位有效RVU: 看門狗計數器重裝載值更新 (Watchdog counter reload value update) 標識位和PVU: 看門狗預分頻值更新 (Watchdog prescaler value update) 標識位,分別用來指示此時是否可向IWDG_RLR 和 IWDG_PR寫值,此寄存器由硬件置1與清0,只有當爲0時纔可向上面兩個寄存器寫值。它的初始化過程大體以下 : //時間計算(大概):Tout=((4*2^prer)*rlr)/40 (ms)
void IWDG_Init(u8 prer,u16 rlr)
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(prer);
IWDG_SetReload(rlr);
IWDG_ReloadCounter();
IWDG_Enable();
}
喂狗可經過調用以下函數進行:ide
IWDG_ReloadCounter();//reload另外要注意不要使用硬件時鐘中斷喂狗,由於硬件時鐘中斷通常都有較高優先級且獨立於主控程序,這樣有時會出現主控程序雖然跑飛了,但仍可以正常喂狗的現象。獨立看門狗可以在必定程度上監控着程序正常運行,然而我認爲更增強大,應用更靈活及更能保證程序穩定運行的還屬窗口看門狗,雖然它開始時不太好理解。▍STM32窗口看門狗共三個寄存器,以下圖:
![watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=](http://static.javashuo.com/static/loading.gif)
看似簡單,但設置及應用起來有很多玄機。控制寄存器(WWDG_CR)中的值必須在0xFF與0xC0之間, 由於它的第0至第6位爲遞減計數器CNT,在它的第6位變爲0時將產生復位,因此在初始化時須要爲1,第7位WDGA是用來設置啓動或禁止窗口看門狗的,當爲1進纔會啓動窗口看門狗,因此第6和第7位都需爲1,即WWDG_CR 的值須要大於等於0xC0 。配置寄存器(WWDG_CFR) 第0至第6位 是設置窗口邊界值用的,只有當遞減計數器CNT的值小於邊界值時才能夠喂狗,過早不行,狗還不餓,撐死了。而且7位遞減計數器CNT減小到0x3F時即T6位變爲0,此時MCU也會復位,過晚了,狗餓死了。因此必須在指定的時間範圍喂狗,過早或過晚都將產生復位,而這樣設計能夠減小軟件跑飛了卻仍可以歪打正着地喂狗的發生機率。狀態寄存器(WWDG_CFR) 只用到了第0位,EWIF(Early wakeup interrupt flag )是提早喚醒中斷標識,當遞減計數器CNT的值到達0X40(若再減小一次則T6位變爲0,產生復位)時此位由硬件置1,且需用軟件清0,注意不管中斷是否使能此位都會被硬件置1。而提早喚醒中斷使能設置是在配置寄存器(WWDG_CFR)第9位EWI(Early wakeup interrupt),此位需由軟件置1,則會在當遞減計數器CNT的值到達0X40時產生中斷,而且與EWIF不一樣,此位是由硬件清0。另外控制寄存器(WWDG_CR)中第7位WDGA(Activation bit)激活位,需用軟件來置1,以啓動窗口看門狗,而且一旦啓動後,只能在復位或重啓後由硬件來清0。配置寄存器(WWDG_CFR)的第8位和第7位WDGTB[1:0]用來設置時基(Timer base)預分頻數。 以上描述可參考下圖以更清晰的理解:
![watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=](http://static.javashuo.com/static/loading.gif)
窗口看門狗應用時還要注意算準最小與最大喂狗時間,以便正確地喂狗,以下:
![watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=](http://static.javashuo.com/static/loading.gif)
在PCLK1頻率爲36MHz 時,則上窗口時間:T_min = 4096 * (2^WDGTB)*(WWDG_CR[6:0] - WWDG_CFR[6:0])/36 (us)下窗口時間:T_max = 4096 * (2^WDGTB)*(WWDG_CR[6:0] - 0x40)/36 (us) 。喂狗動做需在這段時間之間進行,而喂狗動做爲向控制寄存器(WWDG_CR)中寫值。窗口看門狗中斷函數void WWDG_IRQHandler(void) 是用來作什麼的呢?窗口看門狗中斷函數是在遞減計數器減小到0x40是被調用,由於它自己計數就比較慢,因此離數到0x3F復位還有一段時間,我認爲這樣設計是爲MCU復位以前留下一點時間,可以使工程設計人員根據須要在中斷函數保存一些重要的數據,這樣在復位後MCU可知道系統因異常復位的某此狀態,以使系統有更高穩定性。而且我以爲在窗口看門狗中斷函數中喂狗沒有什麼意義,程序原本已經不按正常運行了,還在中斷函數中喂狗防止復位只會錯上加錯,很差好利用它乾點正事, 更是浪費資源。這點上我我的認爲不要被點原子示例代碼誤導哦,但其仍是有部分借鑑意義的,如下爲初始化相關代碼: //窗口看門狗中斷服務設置程序
void WWDG_NVIC_Init()
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //WWDG 中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //搶佔2 子優先級3 組2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //搶佔2,子優先級3,組2
NVIC_Init(&NVIC_InitStructure); //NVIC 初始化
}//保存WWDG 計數器的設置值,默認爲最大.
u8 WWDG_CNT=0x7f; //初始化窗口看門狗
//tr :T[6:0],計數器值
//wr :W[6:0],窗口值
//fprer:分頻係數(WDGTB ),僅最低2 位有效
//Fwwdg=PCLK1/(4096*2^fprer).
void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG 時鐘使能
WWDG_CNT=tr&WWDG_CNT; //初始化WWDG_CNT.
WWDG_SetPrescaler(fprer); //設置IWDG 預分頻值
WWDG_SetWindowValue(wr); //設置窗口值
WWDG_Enable(WWDG_CNT); //使能看門狗,設置counter
WWDG_ClearFlag(); //清除提早喚醒中斷標誌位 (注:若沒有此句則會在初始化後先進入中斷一次)
WWDG_NVIC_Init(); //初始化窗口看門狗NVIC
WWDG_EnableIT(); //開啓窗口看門狗中斷
}
以上代碼朋友們也能夠跳到庫函數代碼中本身研究下,另外要說明下的是WWDG_EnableIT(); 函數相關代碼函數
#define CFR_EWI_BB (PERIPH_BB_BASE + (CFR_OFFSET * 32) + (EWI_BitNumber * 4))