一、看門狗介紹
在由單片機構成的系統中,由于單片機的工作有可能受到外界電磁場的幹擾,造成程式的跑飛,進而陷入死循環,程式的正常運作被打斷,單片機控制的系統便無法繼續工作,這樣會造成整個系統陷入停滞狀态,發生不可預測的後果,是以出于對單片機運作狀态進行實時監測的考慮,便産生了一種專門用于監測單片機程式運作狀态的晶片,俗稱“看門狗(Watch Dog)”。
加入看門狗電路的目的是使單片機可以在無人狀态下實作連續工作,其工作過程為:看門狗晶片和單片機的一個I/O引腳相連,該I/O引腳通過單片機的程式控制,使它定時地往看門狗晶片的這個引腳上送入高電平(或低電平),這一程式語句是分散地放在單片機其它控制語句中間的,一旦單片機由于幹擾造成程式跑飛而陷入某一程式段進入死循環狀态時,給看門狗引腳送電平的程式便不能被執行到,這時,看門狗電路就會由于得不到單片機送來的信号,便對它與單片機複位引腳相連的引腳送出一個複位信号,使單片機複位,進而使單片機從程式存儲器的起始位置重新開始執行程式,這樣便實作了單片機的自動複位。
通常,看門狗電路是通過将一個專門的看門狗晶片連接配接到單片機來實作的,不過這樣會給電路設計帶來複雜性,STC系列單片機内部自帶了看門狗,看門狗有一個15位的計數器,在預設狀态下,看門狗計數器不計數,看門狗功能禁止。如果使能了看門狗功能,則計數器由0開始計數,計數到最大值32767時,則單片機便産生複位。是以程式要定時對看門狗計數器進行清零,以避免計數器溢出而引起系統複位,這稱之為“喂狗”。如果程式跑飛陷入死循環,則無法喂狗,看門狗就可以迫使單片機複位。
通過對相應的特殊功能寄存器的設定就可實作看門狗的應用。STC89系列單片機内部有一個專門的看門狗定時器寄存器WDT_CONTR,這個寄存器的定義如下

這個寄存器中各位的定義分别為:
EN_WDT:看門狗允許位,當這一位設定為1時,使能看門狗。
CLR_WDT:看門狗清0位,當這一位設定為1時,将看門狗的計數器清0。
IDLE_WDT:看門狗空閑模式位,當這一位置1時,看門狗計數器在空閑模式下計數,當這一位清0時,看門狗計數器在空閑模式下不計數。
PS2~PS0:看門狗計數器預分頻系數。這三位用來設定看門狗計數器的計數周期。當采用12MHz的晶振,并采用12時鐘模式時,PS2~PS0對預分頻值和看門狗的溢出時間的設定如下表所示。
溢出時間是如何計算的呢,這需要對單片機的時鐘模式進行一定了解。
單片機的廠家不同,單片機的時鐘系統也會有些差别。我們隻介紹STC單片機的時鐘。單片機有一下幾個周期概念:
(1)時鐘周期:也稱為震蕩周期,它定義為時鐘頻率的倒數,例如單片機的外部晶振為12MHz,則它的時鐘周期就是1/12us,時鐘周期是單片機中最基本、最小的時間機關,在一個時鐘周期内CPU僅完成一個最基本的動作。時鐘脈沖是單片機最基本的工作脈沖,它控制着單片機的工作節奏。對于一個單片機來講,時鐘頻率越高,單片機的工作速度就越快,但是,由于不同的單片機内部硬體電路和電器結構不同,是以需要的時鐘頻率範圍也不一定相同,我們使用的STC89C系列單片機的時鐘範圍約為1MHz~40MHz。
(2)狀态周期:它是時鐘周期的兩倍。
(3)機器周期:單片機基本操作周期,在一個操作周期内,單片機完成一項基本的操作,如取指令、存儲器讀寫等。
(4)指令周期:它是CPU執行一條指令所需要的時間,一般一個指令周期含有1~4個機器周期。
STC單片機有兩種時鐘模式,一種是單倍速,也就是12時鐘模式,在該時鐘模式下,12個時鐘周期為一個機器周期;另一種是雙倍速,又稱為6時鐘模式,在該時鐘模式下,6個時鐘器為一個機器周期,比12時鐘模式快1倍。兩種時鐘模式可以通過燒寫軟體進行設定。如下圖所示。一般情況我們用12時鐘模式就可以了。
看門狗計數器的時鐘源為機器周期,采用12MHz晶振,則時鐘源的頻率為1MHz,時鐘源的周期為1us。若PS2~PS0設定為100,則分頻系數為32,那麼看門狗計數器的計數周期為32us,計數器由0計數到32767的時間長度為32us*32768=1048576us。即溢出時間為1.0485秒。
二、執行個體測試
這個實驗的代碼如下所示,
void main (void)
{
WDT_CONTR=0x34; //初始化看門狗,使能看門狗,溢出周期為1.0485s。
LED1=0; //将P00口指派0,對外輸出低電平,燈點亮。
delay1ms(500); //延時0.5秒
LED1=1; //将P00口指派1,對外輸出高電平,燈熄滅。
for(;;)
{
WDT_CONTR=0x34; //複位看門狗
delay1ms(500); //延時0.5秒
}
}
燒寫之後可以看到實驗現象,開發闆上的LED1閃1下之後熄滅。
在這個實驗中,程式首先使能了看門狗,并且讓LED1閃一下,之後,程式不對LED1進行操作,隻是每隔0.5秒喂一次看門狗。
對程式進行一定修改,将for循環中的喂狗語句WDT_CONTR=0x34; //複位看門狗 的前邊打上雙斜線//,将這一句隐去,這樣程式隻是使能了看門狗,而沒有定時喂狗。将程式編譯之後,将這個工程的HEX檔案燒寫到單片機中。燒寫之後可以看到實驗現象,開發闆上的LED1每隔大約1秒閃一次,這是因為沒有按時喂狗,單片機每隔1.0485s複位一次,每次複位之後LED1就閃一次。
程式中使用了WDT_CONTR這個寄存器。而這個寄存器在reg52.h頭檔案中沒有進行定義,是以程式在使用這個寄存器之前要對其進行定義。這個寄存器的位址為E1H,是以将其定義為:sfr WDT_CONTR = 0xE1;