看門狗是在軟件跑飛的情況下CPU自恢復的一個方式,看門狗分為硬狗和軟狗,硬狗就是由專門的看門狗硬件電路實現看門狗功能,看門狗芯片也比較多,比如DS1232,除了看門狗功能外還有電源電壓監測功能。軟狗就是由軟件實現的看門狗功能,現在很多CPU都自帶了軟狗,很難說硬狗好還是軟狗好,如果軟狗夠用,盡量使用軟狗簡化設計,看門狗說白了就是一個定時器!,當軟件在選定的時間間隔內不能置位看門狗定時器(WDT),WDT就復位系統。看門狗可用於電噪聲,電源故障或靜電放電等惡劣工作環境或高可靠性要求的環境。如果系統不需要應用到看門狗,則WDT可配置成間隔定時器,當時間間隔到達產生中斷。 WDT的特性如下:
- 4個可選擇的時間間隔
- 看門狗模式
- 定時器模式
- 定時器模式下產生中斷請求
CC2541的看門狗定時器(WDT)可以配置成看門狗模式或者普通的間隔定時器,WDT包括一個15位定時/計數器,它的頻率由32.768KHz的晶振決定,用戶不能查看計數器的值。
看門狗的模式由寄存器WDCTL來配置,寄存器WDCTL的定義如下:
WDCTL.INT[1:0]:定時器定時間隔選擇位,有四種可選的時間間隔,32.768KHz時鍾下,1s、0.25s、15.625ms、1.9ms分別對應32768、8192、512和64個時鍾周期。注意,定時時間間隔只能在看門狗處於空閑(IDLE)模式下才能配置有效。
WDCTL.MODE[1:0]:模式選擇位,有三種模式可選擇,空閑模式、看門狗模式和計時器模式,在計時器模式下,設置該位為00空閑模式則停止該計數器,當需要從計數器模式轉換到看門狗模式,必須首先使該位為00使之處於空閑模式,然后再賦值10,轉換到看門狗模式。如果處於看門狗模式,則不管向該位寫入什么值都不起作用了,始終處於看門狗模式。一般來說,也不會在程序里切換模式,都是作單一用途的。
WDCTL.CLR[3:0]:看門狗定時器清零位,在看門狗模式下,先向該位寫入0xa,再寫入0x5,定時器計數值清0,注意的是寫入0x5必須緊跟着寫入0xa,這兩條語句之間不能插入其他語句。當處於空閑模式下,寫該位不會產生任何影響
1 /****************************************************************************** 2 *函 數 名:FeetDog 3 *功 能:喂狗,計數器清0 4 *入口參數:無 5 *出口參數:無 6 ******************************************************************************/ 7 void FeetDog(void) 8 { 9 WDCTL = 0xa0; //清除定時器。當0xA 跟隨0x5 寫到這些位,定時器被清除 10 WDCTL = 0x50; 11 }
計時器模式下WDCTL.CLR[0]位置1(其他三位不管寫入什么值),則計數器清0(0x0000),但計數器不會停止計數,WDCTL.MODE[1:0]設置為00,計時器模式下計數器才停止並且計數值清0。
1、看門狗模式
系統復位后默認是處於空閑模式的,所以需要人為設置為看門狗模式,將WDCTL.MODE[1:0]設置為10,此時看門狗計數器開始從0計數,一旦處於看門狗模式,就沒有辦法停止該計數器了,向WDCTL.MODE[1:0]寫入00或者其他值都沒有作用了。
如果計數器計數到設定的計數值(32768、8192、512或者64),就會產生一個系統復位信號,如果計數器被清0,則此時計數器又從0開始計數,此過程稱為”喂狗“,所以在程序合適的位置放置喂狗代碼,程序運行一次循環則會清除計數器一次(喂狗一次),計數器就不會溢出,如果程序跑飛了,就執行不到喂狗代碼,超過設定的時間間隔,計數器就會溢出,對系統復位。看門狗模式下不會產生中斷。另外前面說過定時間隔只能在看門狗處於空閑(IDLE)模式下才能配置有效,而一旦設定為看門狗模式,就不會回到空閑(IDLE)模式,所以定時時間間隔也是不可更改的了。注意:看門狗的時間間隔應該大於喂狗程序執行一次所需的時間!不然還沒喂狗計數器就溢出復位了。一般的1s都夠了,沒有哪個程序執行一次的時間會超過1s吧,呵呵。
2、計時器模式
將WDCTL.MODE[1:0]設置為11,WDT處於計時器模式。一旦設定WDCTL.MODE[1:0]為11,計數器就開始從0計數,當計數值達到設定的的計數值(32768、8192、512或者64),便會產生看門狗中斷請求,IEN2.WDTIE看門狗中斷使能的情況下,IRCON2.WDTIF看門狗中斷標志位變為1。注意中斷使能信號放在WDCTL.MODE[1:0]配置前面,不然計數器開始計時了,還沒有開中斷。
在計數器模式下,WDCTL.CLR[0]為1則清除計數器,然后從0開始計數,並不會停止計數器,WDCTL.MODE[1:0]設置為00,計數器停止工作並且計數值清0。在計數器工作的時候,寫入
WDCTL.INT[1:0] 無效,定時時間間隔無法改變,當計數器達到設定值時,並不會產生系統復位信號。如果定時器不夠用的時候可以用該定時器,但是定時的時間只有4種選擇。
看門狗模式
示例程序:WDT為看門狗模式,時間間隔為1s,定時喂狗,如果沒有喂狗,則系統不斷復位,LED燈每隔1s亮滅一次,無需第87行延時程序,因為看門狗的時間間隔設定為1s,LED剛好亮1s。
1 /****************************************************************************** 2 *文 件 名:WDT.c 3 *作 者:陳照 4 *時 間:2015-06-01 5 *版 本:1.0 6 *描 述:看門狗程序 7 ******************************************************************************/ 8 #include <iocc2541.h> 9 10 #define LED1 P1_0 11 12 /****************************************************************************** 13 *函 數 名:Delay1ms 14 *功 能:延時1ms 15 *入口參數:uiDelay,延時參數,值越大,延時越長 16 *出口參數:無 17 ******************************************************************************/ 18 void Delay1ms(unsigned int uiDelay) 19 { 20 unsigned int i,j; 21 for(i = 0; i < uiDelay; i++) 22 { 23 for(j = 0;j < 1322; j++); 24 } 25 } 26 27 /**************************************************************** 28 *函 數 名:InitClock 29 *功 能:系統時鍾初始化 30 *入口參數:無 31 *出口參數:無 32 *****************************************************************/ 33 void InitClock(void) 34 { 35 CLKCONCMD &= ~(1 << 6); //選擇32MHz晶振 36 while(CLKCONSTA & (1 << 6)); //等待時鍾穩定 37 CLKCONCMD &= ~0x47; //系統時鍾和定時器時鍾都是32M 38 } 39 40 /****************************************************************************** 41 *函 數 名:InitLED 42 *功 能:LED燈初始化 43 *入口參數:無 44 *出口參數:無 45 ******************************************************************************/ 46 void InitLED(void) 47 { 48 P1SEL &= ~0x01; //P1.0設置為通用I/O口 49 P1DIR |= 0x01; //P1.0設置為輸出 50 } 51 52 /****************************************************************************** 53 *函 數 名:Init_Watchdog 54 *功 能:看門狗初始化 55 *入口參數:無 56 *出口參數:無 57 ******************************************************************************/ 58 void Init_Watchdog(void) 59 { 60 WDCTL = 0x00; //打開IDLE 才能設置看門狗 61 WDCTL |= 0x08; //定時器間隔選擇,間隔一秒,設定為看門狗模式 62 } 63 64 /****************************************************************************** 65 *函 數 名:FeetDog 66 *功 能:喂狗,計數器清0 67 *入口參數:無 68 *出口參數:無 69 ******************************************************************************/ 70 void FeetDog(void) 71 { 72 WDCTL = 0xa0; //清除定時器。當0xA 跟隨0x5 寫到這些位,定時器被清除 73 WDCTL = 0x50; 74 LED1 = 1; //系統不復位LED1 燈長亮 75 } 76 77 /****************************************************************************** 78 *程序入口函數 79 ******************************************************************************/ 80 int main(void) 81 { 82 InitClock(); //時鍾初始化,32MHz 83 InitLED(); //LED初始化 84 LED1 = 0; //熄滅LED1 85 Delay1ms(1000); 86 LED1 = 1; //點亮LED1 87 //Delay1ms(1000); 88 Init_Watchdog(); //看門狗初始化 89 90 while(1) 91 { 92 FeetDog(); //喂狗程序 93 //注釋掉次子函數,系統不斷復位,LED1閃爍 94 } 95 }
計時器模式
示例:WDT處於計時器模式,中斷方式,LED燈閃爍,0.25s狀態改變一次
1 /****************************************************************************** 2 *文 件 名:WDT.c 3 *作 者:陳照 4 *時 間:2015-06-01 5 *版 本:1.0 6 *描 述:WDT計時器模式 7 ******************************************************************************/ 8 #include <iocc2541.h> 9 10 typedef unsigned char uchar; 11 typedef unsigned int uint; 12 13 #define LED1 P1_0 14 15 /****************************************************************************** 16 *函 數 名:Delay1ms 17 *功 能:延時1ms 18 *入口參數:uiDelay,延時參數,值越大,延時越長 19 *出口參數:無 20 ******************************************************************************/ 21 void Delay1ms(unsigned int uiDelay) 22 { 23 unsigned int i,j; 24 for(i = 0; i < uiDelay; i++) 25 { 26 for(j = 0;j < 1322; j++); 27 } 28 } 29 30 /**************************************************************** 31 *函 數 名:InitClock 32 *功 能:系統時鍾初始化 33 *入口參數:無 34 *出口參數:無 35 *****************************************************************/ 36 void InitClock(void) 37 { 38 CLKCONCMD &= ~(1 << 6); //選擇32MHz晶振 39 while(CLKCONSTA & (1 << 6)); //等待時鍾穩定 40 CLKCONCMD &= ~0x47; //系統時鍾和定時器時鍾都是32M 41 } 42 43 /****************************************************************************** 44 *函 數 名:InitLED 45 *功 能:LED燈初始化 46 *入口參數:mode,mode為1則點亮所有LED,mode為0則熄滅所有LED 47 *出口參數:無 48 ******************************************************************************/ 49 void InitLED(uchar mode) 50 { 51 P1SEL &= ~0x01; //P1.0設置為通用I/O口 52 P1DIR |= 0x01; //P1.0設置為輸出 53 LED1 = mode; //LED燈亮熄控制 54 } 55 56 /****************************************************************************** 57 *函 數 名:Init_Watchdog 58 *功 能:看門狗初始化 59 *入口參數:無 60 *出口參數:無 61 ******************************************************************************/ 62 void Init_Watchdog(void) 63 { 64 WDCTL = 0x00; //打開IDLE 才能設置計時器間隔時間 65 WDCTL |= 0x0d; //設定為計時器模式,定時器間隔為0.25秒 66 } 67 68 /****************************************************************************** 69 *函 數 名:WDT_ISR 70 *功 能:WDT計時器模式中斷服務程序 71 *入口參數:無 72 *出口參數:無 73 ******************************************************************************/ 74 #pragma vector = WDT_VECTOR 75 __interrupt void WDT_ISR(void) 76 { 77 WDTIF = 0; //看門狗中斷清除 78 LED1 = ~LED1; //定時時間到,LED狀態翻轉 79 } 80 81 /****************************************************************************** 82 *程序入口函數 83 ******************************************************************************/ 84 int main(void) 85 { 86 InitClock(); //時鍾初始化,32MHz 87 InitLED(0); //LED初始化,熄滅LED1 88 IEN2 |= 0x20; //看門狗中斷使能 89 EA = 1; //開總中斷 90 Init_Watchdog(); //看門狗初始化 91 92 while(1) 93 { 94 }; 95 }
拓展問題:CC2541在睡眠模式下,看門狗如何工作。初步認識為看門狗繼續工作,計數器一直計數,有待后續驗證!