窗口看門狗
之所以稱為窗口就是因為其喂狗時間是一個有上下限的范圍內(窗口),你可以通過設定相關寄存器,設定其上限時間(下限固定)。喂狗的時間不能過早也不能過晚。
而獨立看門狗限制喂狗時間在0-x內,x由相關寄存器決定。喂狗的時間不能過晚。
計數器從初值計數到上窗口的值,不能喂狗,必須在上窗口值到0x3f值這個過程中喂狗。0x3f=0011 1111,所以0x3f上面一個數是0100 0000,也就是說t6位由1跳變為0.如果說t6位由1跳變為0,並且仍然沒有喂狗,那么就復位。
STM32F的窗口看門狗中有一個7位的遞減計數器T[6:0],它會在出現下述2種情況之一時產生看門狗復位:
當喂狗的時候如果計數器的值大於某一設定數值W[6:0]時,此設定數值在WWDG_CFR寄存器定義。
當計數器的數值從0x40減到0x3F時【T6位跳變到0】。
如果啟動了看門狗並且允許中斷,當遞減計數器等於0x40時產生早期喚醒中斷(EWI),它可以用於喂狗以避免WWDG復位。中斷時間不宜過長。
對於一般的看門狗,程序可以在它產生復位前的任意時刻刷新看門狗,但這有一個隱患,有可能程序跑亂了又跑回到正常的地方,或跑亂的程序正好執行了刷新看門狗操作,這樣的情況下一般的看門狗就檢測不出來了;
如果使用窗口看門狗,程序員可以根據程序正常執行的時間設置刷新看門狗的一個時間窗口,保證不會提前刷新看門狗也不會滯后刷新看門狗,這樣可以檢測出程序沒有按照正常的路徑運行、非正常地跳過了某些程序段的情況。
上窗口值W[6:0]必須大於下窗口值0x40。否則就無窗口了。
窗口看門狗時鍾來源PCLK1(APB1總線時鍾)分頻后。
可以通過查這個標志位來判斷是否到達0x40.
HAL_WWDG_Start是啟動看門狗,HAL_WWDG_Start_IT還開啟了提前喚醒中斷
HAL_StatusTypeDef HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg); void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg); HAL_StatusTypeDef HAL_WWDG_Start(WWDG_HandleTypeDef *hwwdg); HAL_StatusTypeDef HAL_WWDG_Start_IT(WWDG_HandleTypeDef *hwwdg); HAL_StatusTypeDef HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg); void HAL_WWDG_IRQHandler(WWDG_HandleTypeDef *hwwdg); void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef* hwwdg);
1.使能窗口看門狗時鍾:
HAL_WWDG_MspInit中
2.初始化窗口看門狗:設置分頻系數,窗口值,計數值等。
HAL_WWDG_Init();
該函數還可以使能窗口看門狗提前喚醒中斷 。
3.設置提前喚醒中斷優先級:
HAL_WWDG_MspInit
4.編寫提前喚醒中斷處理函數,喂狗:
HAL_WWDG_EarlyWakeupCallback();
HAL_WWDG_Refresh();
#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "key.h" #include "exti.h" void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg) { __HAL_RCC_WWDG_CLK_ENABLE();//使能時鍾 HAL_NVIC_EnableIRQ(WWDG_IRQn); //使WWDG_IRQn斷通道 HAL_NVIC_SetPriority(WWDG_IRQn,3,3); //搶占優先級3,子優先級3 } WWDG_HandleTypeDef wwdg_handler; void WWDG_IRQHandler(void) { HAL_WWDG_IRQHandler(&wwdg_handler); } void HAL_WWDG_WakeupCallback(WWDG_HandleTypeDef* hwwdg) { HAL_WWDG_Refresh(&wwdg_handler,0x7f); LED1=!LED1; } int main(void) { HAL_Init(); //初始化HAL庫 Stm32_Clock_Init(360,25,2,8); //設置時鍾,180Mhz delay_init(180); //初始化延時函數 uart_init(115200); //初始化USART LED_Init(); //初始化LED EXTI_Init(); LED0 = 0; delay_ms(300); wwdg_handler.Instance=WWDG; wwdg_handler.Init.Counter=0x7f;//初始值 wwdg_handler.Init.Prescaler=WWDG_PRESCALER_8; wwdg_handler.Init.Window=0x5f;//上窗口值 HAL_WWDG_Init(&wwdg_handler); HAL_WWDG_Start_IT(&wwdg_handler); while(1) { LED0=1; } }
PCLK1=180/4=45MHZ
45MHZ/4096/8=1373hz
0x7f-0x40+1個時鍾=64個時鍾
64/1373=0.0466s=22hz
經過0.0466s后執行中斷服務函數。
在之前肯定會進入while循環把LED0燈滅掉。
執行中斷服務函數之后,LED1燈會進行反轉,並對計數值刷新 重新從0x7f計數。
每隔0.0466s,LED1進行一次翻轉。開啟后LED0只進行一次閃爍。
如果把回調函數中的喂狗操作刪掉,那么進行到0x3f后會進行復位,led0會一直進行閃爍。
進行到0x40時,LED1翻轉,然后又進行到0x3f,程序又進行復位。最終led0和led1都會閃爍,而且他們的頻率相近。