CC2541藍牙學習——看門狗


看門狗是在軟件跑飛的情況下CPU自恢復的一個方式,看門狗分為硬狗和軟狗,硬狗就是由專門的看門狗硬件電路實現看門狗功能,看門狗芯片也比較多,比如DS1232,除了看門狗功能外還有電源電壓監測功能。軟狗就是由軟件實現的看門狗功能,現在很多CPU都自帶了軟狗,很難說硬狗好還是軟狗好,如果軟狗夠用,盡量使用軟狗簡化設計,看門狗說白了就是一個定時器!,當軟件在選定的時間間隔內不能置位看門狗定時器(WDT),WDT就復位系統。看門狗可用於電噪聲,電源故障或靜電放電等惡劣工作環境或高可靠性要求的環境。如果系統不需要應用到看門狗,則WDT可配置成間隔定時器,當時間間隔到達產生中斷。 WDT的特性如下:

  1. 4個可選擇的時間間隔
  2. 看門狗模式
  3. 定時器模式
  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在睡眠模式下,看門狗如何工作。初步認識為看門狗繼續工作,計數器一直計數,有待后續驗證!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM