STM32的獨立看門狗由內(nèi)部專門的40Khz低速時鐘驅(qū)動,即使主時鐘發(fā)生故障,它也仍然有效。
看門狗的原理:單片機系統(tǒng)在外界的干擾下會出現(xiàn)程序跑飛的現(xiàn)象導(dǎo)致出現(xiàn)死循環(huán),看門狗電路就是為了避免這種情況的發(fā)生??撮T狗的作用就是在一定時間內(nèi)(通過定時計數(shù)器實現(xiàn))沒有接收喂狗信號(表示MCU已經(jīng)掛了),便實現(xiàn)處理器的自動復(fù)位重啟(發(fā)送復(fù)位信號)。
在鍵值寄存器(IWDG_KR)中寫入0xCCCC,開始啟用獨立看門狗;此時計數(shù)器開始從其復(fù)位值0xFFF遞減計數(shù)。當計數(shù)器計數(shù)到末尾0x000時,會產(chǎn)生一個復(fù)位信號(IWDG_RESET)。無論何時,只要鍵寄存器IWDG_KR中被寫入0xAAAA,IWDG_RLR中的值就會被重新加載到計數(shù)器中從而避免產(chǎn)生看門狗復(fù)位。
IWDG_PR和IWDG_RLR寄存器具有寫保護功能。要修改這兩個寄存器的值,必須先向IWDG_KR寄存器中寫入0x5555。將其他值寫入這個寄存器將會打亂操作順序,寄存器將重新被保護。重裝載操作(即寫入0xAAAA)也會啟動寫保護功能。
只要對以上三個寄存器進行相應(yīng)的設(shè)置,我們就可以啟動STM32的獨立看門狗,啟動過程可以按如下步驟實現(xiàn)(獨立看門狗相關(guān)的庫函數(shù)和定義分布在文件stm32f10x_iwdg.h和stm32f10x_iwdg.c中):
1)取消寄存器寫保護(向IWDG_KR寫入0X5555)
通過這步,我們?nèi)∠鸌WDG_PR和IWDG_RLR的寫保護,使后面可以操作這兩個寄存器,設(shè)置IWDG_PR和IWDG_RLR的值。這在庫函數(shù)中的實現(xiàn)函數(shù)是:
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
2)設(shè)置獨立看門狗的預(yù)分頻系數(shù)和重裝載值
設(shè)置看門狗的分頻系數(shù)的函數(shù)是:
voidIWDG_SetPrescaler(uint8_tIWDG_Prescaler);//設(shè)置IWDG預(yù)分頻值
設(shè)置看門狗的重裝載值的函數(shù)是:
voidIWDG_SetReload(uint16_tReload);//設(shè)置IWDG重裝載值
設(shè)置好看門狗的分頻系數(shù)prer和重裝載值就可以知道看門狗的喂狗時間(也就是看門狗溢出時間),該時間的計算方式為:
Tout=((4×2^prer)×rlr)/40
其中Tout為看門狗溢出時間(單位為ms);prer為看門狗時鐘預(yù)分頻值(IWDG_PR值),范圍為0~7;rlr為看門狗的重裝載值(IWDG_RLR的值);
比如我們設(shè)定prer值為4,rlr值為625,那么就可以得到Tout=64×625/40=1000ms,這樣,看門狗的溢出時間就是1s,只要你在一秒鐘之內(nèi),有一次寫入0XAAAA到IWDG_KR,就不會導(dǎo)致看門狗復(fù)位(當然寫入多次也是可以的)。這里需要提醒大家的是,看門狗的時鐘不是準確的40Khz,所以在喂狗的時候,最好不要太晚了,否則,有可能發(fā)生看門狗復(fù)位。
3)重載計數(shù)值喂狗(向IWDG_KR寫入0XAAAA)
庫函數(shù)里面重載計數(shù)值的函數(shù)是:
IWDG_ReloadCounter();//按照IWDG重裝載寄存器的值重裝載IWDG計數(shù)器
通過這句,將使STM32重新加載IWDG_RLR的值到看門狗計數(shù)器里面。即實現(xiàn)獨立看門狗的喂狗操作。
4)啟動看門狗(向IWDG_KR寫入0XCCCC)
庫函數(shù)里面啟動獨立看門狗的函數(shù)是:
IWDG_Enable();//使能IWDG
通過這句,來啟動STM32的看門狗。注意IWDG在一旦啟用,就不能再被關(guān)閉!想要關(guān)閉,只能重啟,并且重啟之后不能打開IWDG,否則問題依舊,所以在這里提醒大家,如果不用IWDG的話,就不要去打開它,免得麻煩。
點擊(此處)折疊或打開
#include"sys.h"
#include"iwdg.h"
/**
* 初始化獨立看門狗
* prer:分頻數(shù):0~7(只有低 3 位有效!)
* 分頻因子=4*2^prer.但最大值只能是 256!
* rlr:重裝載寄存器值:低 11 位有效.
* 時間計算(大概):Tout=((4*2^prer)*rlr)/40 (ms).
*/
void IWDG_Init(u8 prer,u16 rlr)
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);/* 使能對寄存器IWDG_PR和IWDG_RLR的寫操作*/
IWDG_SetPrescaler(prer);/*設(shè)置IWDG預(yù)分頻值:設(shè)置IWDG預(yù)分頻值*/
IWDG_SetReload(rlr); /*設(shè)置IWDG重裝載值*/
IWDG_ReloadCounter();/*按照IWDG重裝載寄存器的值重裝載IWDG計數(shù)器*/
IWDG_Enable();/*使能IWDG*/
}
/**
* 喂獨立看門狗
*/
void IWDG_Feed(void)
{
IWDG_ReloadCounter();/*reload*/
}