在嵌入式系統中,由於MCU的工作常常受到來自外界電磁場的干擾,造成程序的跑飛,而陷入死循環,程序的正常運行被打斷,由單片機控制的系統無法繼續工作,會造成整個系統陷入停滯狀態,發送不可預料的后果,所以出於對單片機運行狀態實時監測的考慮,便產生了一種專門用於檢測程序運行狀態的模塊,俗稱“看門狗(watchdog)”;
在系統運行以后就啟動了看門狗的計數器,看門狗就開始自動計數,如果到了一定的時間還不去清看門狗,那么看門狗計數器就會溢出從而引起看門狗中斷,造成系統復位。所以在使用看門狗的時候要注意清除看門狗;
看門狗是恢復系統的正常運行及有效的監視管理器(具有鎖定光驅,鎖定任何指定程序的作用,可用在家庭中防止小孩無節制地玩游戲,上網等)具有很好的應用價值;
獨立看門狗:(使用的是獨立時鍾)
IWDG由專用的32KHZ的低速時鍾來驅動;因此,即使主時鍾發生故障它仍然有效。IWDG最適合應用於那些需要看門狗做為一個在主程序之外,能夠完全獨立工作,並且對時間精度要求較低的場合;
重要寄存器:
鍵值寄存器(IWDG_KR):與喂狗、允許訪問IWDG_PR\IWDG_RLR寄存器、啟動看門狗相關
預分頻寄存器(IWDG_PR):設置分頻值
重裝載寄存器(IWDG_RLR):
狀態寄存器(IWDG_SR)
操作步驟:(將獨立看門狗使能、開啟)
1、向IWDG_KR寫入0x5555.
通過這部,我們取消IWDG_PR和IWDG_RLR的寫保護,使后面可以操作這兩個寄存器。設置IWDG_PR和IWDG_RLR的值;
這兩步設置看門狗的分頻系數,和重裝載的值。由此,就可以知道看門狗的喂狗時間,該事件的計算方式:Tout = 40khz/(4×2^rlr)當然這個值是粗略的計算值,因為時鍾不准確,所以無法得到准確的喂狗時間;
2、向IWDG_KR寫入0xAAAA
通過這句,將使stm32重新加載IWDG_RLR的值到看門狗計數器里面,也是用該命令來喂狗。
3、向IWDG_KR寫入0XCCCC
通過這句,啟動看門狗;
通過上面3步,我們啟動了stm32的看門狗,使能了看門狗,在程序里面就必須間隔一定時間來喂狗,否則將導致程序復位。
配置實例:
1 void IWDG_Configuration(void) 2 { 3 //使能對寄存器IWDG_PR和IWDG_RLR的寫操作 4 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); 5 //設置IWDG預分頻值256: 6 //40K/256 = 156HZ(6.4ms) 5s/6.4ms=781; 7 IWDG_SetPrescaler(IWDG_Prescaler_256); 8 9 //設置IWDG重裝載值,要小於0xfff(因為寄存器是12位的) 10 IWDG_SetReload(781); 11 //按照IWDG重裝載寄存器的值 重新載入IWDG計數值; 12 IWDG_ReloadCounter(); 13 IWDG_Enable(); //使能IWDG 14 }
窗口看門狗:
windowWD由APB1時鍾分頻后得到的時鍾驅動,通過可配置的時間窗口來檢測應用程序非正常的過遲或過早的行為。WWDG最適合那些要求看門狗在精確計時窗口起作用的應用程序;
窗口看門狗通常被用來檢測由外部干擾或不可預見的邏輯條件造成的應用程序背離正的運行序列而產生的軟件故障;除非遞減計數器的值在T6位(第6位)變成0前被刷新,此看門狗電路在達到可編程的時間周期時,會產生一個MCU復位。在遞減計數器達到窗口寄存器之前,如果遞減計數器值的第7位(在控制寄存器中)被刷新,那么也將產生一個MCU復位。這表明遞減計數器需要一個有限的窗口中被刷新;
T6即窗口看門狗的自減計數器的第六位(最高位),該計數器的時鍾來源於PCLK/4096/預設分頻數。在該計數器的T6變為0后(小於0X40, 100 0000)就會引發復位。這個窗口的下限。而當計數器的值在大於窗口寄存器的窗口值之前就被修改的話,也會引發一場復位,這個窗口值的上限,窗口值是由用戶自己設定的,根據實際要求要設計窗口值,但一定要確保窗口值大於0X40,否則窗口就不存在了;
計算超時的公式如下:
Twwdg = Tpclk1×4096×2^WDTB×(T[5:0]+1); (ms)
其中:
Twwdg:WWDG超時時間 WDTB:寄存器配置的值,可取:0、1、2、3
Tpclk1:APB1以ms位單位的時鍾間隔;一般是確定的,為36Mhz;
控制寄存器:WWDG_CR 低8位有效,T[6:0]用來存儲看門狗的計數值,隨時間更新的;每個PCLK1周期減1.當該計數器的值從0X40變為0X3F的時候,將產生看門狗復位;(這個是喂狗太晚了,已經減到了下限)
WDGA位則是看門狗的激活位,該位由軟件置1,以啟動看門狗,並且一定注意該位一旦設置,就只能在硬件復位后才能清零了;
配置寄存器:WWDG_CFR:低10位有效,
低7位設置的是復位最早值W(這個是窗口上限);
第8,9位是:時基,可取00,01、10、11
第10位是提前喚醒中斷;
操作步驟:
1、使能WWDG時鍾
WWDG不同於IWDG,IWDG有自己獨立的40khz的時鍾,不存在使能問題。而WWDG使用的是PCLK1的時鍾,需要先使能時鍾;
2、設置WWDG_CFR和WWDG_CR寄存器
在時鍾使能完后,我們設置WWDG的CFR和CR兩個寄存器,對WWDG進行配置。包括使能窗口看門狗、開啟中斷、設置計數器初始值T、設置窗口值並設置分頻數WDGTB等;
3、開啟WWDG中斷並分組
在設置完WWDG后,需要配置該中斷的分組及使能;
4、編寫中斷服務函數
若沒有在規定時間段內喂狗,就引起軟件復位。在中斷服務函數里將狀態寄存器的EWIF位清空;
如果啟動了看門狗並且允許中斷,當遞減計數器等於0x40時產生早期喚醒中斷(EWI) ,它可以被用於重裝載計數器以避免WWDG復位。
1 void WWDG_Configuration(void) 2 { 3 //使能APB1外設WWDG時鍾 4 RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE); 5 6 //看門狗節拍=(36/4096)/8 = 1098hz 略等1ms 7 WWDG_SetPerscaler(WWDG_Prescaler_8); 8 //窗口上限值為0x45 9 WWDG_SetWindowValue(0x45); 10 //看門狗使能並初始化定時器為0x7f 11 //計數器一直隨時間遞減; 12 //減到0x45到0x40之間必須喂狗(重新載入初值) 13 //否則復位, 14 WWDG_Enable(0x7f); 15 //clear EWI flag 16 WWDG_ClearFlag(); 17 //Enable EWI interrupt 18 WWDG_Enable(); 19 20 }