1、介紹:編程
STM32看門狗分爲獨立看門狗和窗口看門狗兩種,其二者使用調條件以下所示,函數
IWDG和WWDG二者特色以下圖所示:spa
獨立看門狗的手冊資料:3d
窗口看門狗的手冊資料:code
應當注意:在窗口看門狗中,當遞減計數器在窗口外被從新裝載,(若看門狗被啓動)則產生復位blog
【注】圖中的WDGTB爲3表示2^3=8,表示8分頻,最小時間910us也等於每次計數器減一所須要通過的時間:T(LSB),每隔910us減1。最大值也等於,設置重載(喂狗)值127時(最大),一個復位週期的時間就是最大值58.25ms,也就是所能維持進入復位的最大時間。ip
因爲窗口看門狗使用的APB1的PCLK1,時鐘最高36MHZ,和RCC_APB2Periph_GPIOx不一樣,APB1最大就是36MHZ,APB2最大就是72MHZ。it
因此串口看門狗須要配置APB1時鐘使能,以下語句。io
能夠從圖1-3 窗口看門狗編程說明紅看到T(WWDG)=T(PCLK1) x 4096 x 2^WDGTB x (T[5:0]+1) ; (ms)class
WDGTB[1:0]: 時基 (Timer base),也就是設置WDGTB 的值是1/2/4仍是8,這在配置寄存器(WWDG_CFR)寄存器的位8:7 中設置,
其預分頻器的時基能夠設置以下:
00: CK計時器時鐘(PCLK1除以4096)除以1
01: CK計時器時鐘(PCLK1除以4096)除以2
10: CK計時器時鐘(PCLK1除以4096)除以4
11: CK計時器時鐘(PCLK1除以4096)除以8
也能夠直接用這個函數
1 WWDG_SetPrescaler(WWDG_Prescaler_8); //8預分頻,則WWDG時鐘頻率=(PCK1(36M)/4096)/8=1099Hz(910us)
也能夠直接用這個函數
其次是設置窗口值,用來與遞減計數器進行比較用的窗口值。經過以下函數便可
1 WWDG_SetWindowValue(80);//設置窗口值爲80則WWDG的計數值必須在64~80之間才能喂狗(64是0x40,當再次減1就會T6清零,從而致使復位了,即刷新窗口設置成了80-64,127-80也是不能更新值得不然也會復位)
應當注意:在窗口看門狗中,當遞減計數器在窗口外被從新裝載,(若看門狗被啓動)則產生復位,也便是說在90-64外面使用這個重載函數,會有問題發生
最後咱們設置 (T[5:0]+1)的值,這裏咱們設置最大127,代碼以下,之後每次喂狗也能夠用這個函數進行重載計數值(喂狗)。
1 WWDG_Enable(127)
由於這是會致使產生復位,因此重載的窗口必定要設置好。
總結就是咱們使用串口看門狗應該先配置寄存器(WWDG_CFR),即配置窗口值是多少到最小的0x40*T(LSB)(假定T(LSB)爲每減一計數所須要的時間),這個配置會告訴單片機何時來與遞減計數器進行值比較,若是計數值值小於0x40就產生復位。
固然,本例中若是你在減減計數值還在0x7E~0x50(127~80)之間就重載計數值(喂狗)一樣會致使芯片復位。因此窗口的概念必定要理解好,在窗內才能夠重載計數值(喂狗),這樣纔不會莫名被複位。
2、代碼實現
最終的初始化窗口看門狗的配置函數(WWDG)以下:
/************************************************************* Function : WWDGReste_Init Description: 窗口看門狗定時器 Input : none return : none *************************************************************/ void WWDGReste_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);//WWDG鏈接在PCLK1(36M)的時鐘線上 WWDG_SetPrescaler(WWDG_Prescaler_8); //8預分頻,則WWDG時鐘頻率=(PCK1(36M)/4096)/8=1099Hz(910us) WWDG_SetWindowValue(80);//設置窗口值爲80則WWDG的計數值必須在64~80之間才能喂狗(64是0x40,當再次減1就會T6清零,從而致使復位了) //設置WWDG計數值爲127,超時時間=910us*64=58.25ms,因此 WWDG_Enable(127);//(0x7F爲設置的最小值,0x40爲最大的復位值,取值應該在0x40~0x7F之間)刷新窗口爲:910us*(127-80)=42.77ms < 刷新窗口 < 910us*64=58.25ms }
主函數以下:
void mian(void) { //初始化 while(1) { delay_ms(400) WWDG_Enable(127); //無需判斷直接等待窗口看門狗中斷觸發 } }
或者這樣的留參帶使能中斷形式:
#include "wdg.h" #include "stm32f10x_wwdg.h" static u8 WWDG_CNT=0x7f; /*保存WWDG計數器的設置值,默認爲最大127. */ //======================================================================================== /** * 初始化窗口看門狗 * tr :T[6:0],計數器值 * wr :W[6:0],窗口值 * fprer:分頻係數(WDGTB),僅最低2位有效 * Fwwdg=PCLK1/(4096*2^fprer). // 計數器值爲7f,窗口寄存器爲5f,分頻數爲8 WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8); */ void WWDG_Init(u8 tr,u8 wr,u32 fprer) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); /*WWDG時鐘使能*/ WWDG_SetPrescaler(fprer); /*設置IWDG預分頻值*/ WWDG_SetWindowValue(wr); /*設置窗口值*/ WWDG_CNT=tr&WWDG_CNT; /* 初始化WWDG_CNT. */ WWDG_Enable(WWDG_CNT); /*使能看門狗 , 設置 counter . */ WWDG_ClearFlag(); /*清除提早喚醒中斷標誌位*/ WWDG_NVIC_Init();/* 初始化窗口看門狗 NVIC */ WWDG_EnableIT(); /* 開啓窗口看門狗中斷 */ } /** * 窗口看門狗中斷服務程序 */ void WWDG_NVIC_Init(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; /*WWDG中斷*/ /* 搶佔2,子優先級3 */ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中斷使能, NVIC_Init(
&NVIC_InitStructure);/* NVIC初始化*/ } /** * 重設置WWDG計數器的值,喂狗 */ void WWDG_Set_Counter(u8 cnt) { WWDG_Enable(cnt); /*使能看門狗 , 設置 counter . */ } /** * 看門狗中斷服務程序 */ void WWDG_IRQHandler(void) { WWDG_Set_Counter(WWDG_CNT); WWDG_ClearFlag(); /*清除提早喚醒中斷標誌位*/ LED1 = ~LED1; /*LED狀態翻轉 */ } void mian(void) { //初始化 while(1) { } }
3、中斷說明:
關於void WWDG_IRQHandler(void)裏的中斷進入是在減計數到0x40時,處罰中斷進入這個中斷函數,若是在中斷函數中進行減計數的操做,能夠避免復位的厄運,可是若是你不作喂狗操做,那減計數值將接着減,數值將爲0x3F,此時bit7被置零,此時將會直接致使復位。總之,進入中斷函數並不是就復位了,只是此時的減計數值到了0x40,而下一次減計數器減一後值爲0x3F將致使芯片復位了。
附錄:
獨立看門狗(IWDG)的代碼:
/** * 初始化獨立看門狗 * prer:分頻數:0~7(只有低 3 位有效!) * 分頻因子=4*2^prer.但最大值只能是 256! * rlr:重裝載寄存器值:低 11 位有效. * 時間計算(大概):Tout=((4*2^prer)*rlr)/40 (ms). *IWDG_Init(4,625);//初始化獨立看門狗,分頻數爲64,重裝載值爲625,溢出時間計算爲:64*625/40=1000ms=1s */ void IWDG_Init(u8 prer,u16 rlr) { IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); /* 使能對寄存器IWDG_PR和IWDG_RLR的寫操做*/ IWDG_SetPrescaler(prer); /*設置IWDG預分頻值:設置IWDG預分頻值*/ IWDG_SetReload(rlr); /*設置IWDG重裝載值*/ IWDG_ReloadCounter(); /*按照IWDG重裝載寄存器的值重裝載IWDG計數器*/ IWDG_Enable(); /*使能IWDG*/ } /** * 喂獨立看門狗 */ void IWDG_Feed(void) { IWDG_ReloadCounter(); /*reload*/ } /** *main函數 */ void main(void) { NVIC_Configuration();//優先級配置 IWDG_Init(4,625);//初始化獨立看門狗,分頻數爲64,重裝載值爲625,溢出時間計算爲:64*625/40=1000ms=1s while(1) { delay_ms(500);//0.5秒喂一次狗 IWDG_Feed();//喂狗 } }