【stm32f407】視窗看門狗 wwdog
一.視窗看門狗
視窗看門狗(WWDG)通常被用來監測由外部干擾或不可預見的邏輯條件造成的應用程式背離正常的執行序列而產生的軟體故障。除非遞減計數器的值在T6位(WWDG->CR的第六位)變成0前被重新整理,看門狗電路在達到預置的時間週期時,會產生一個MCU復位。在遞減計數器達到視窗配置暫存器(WWDG->CFR)數值之前,如果7位的遞減計數器數值(在控制暫存器中)被重新整理, 那麼也將產生一個MCU復位。這表明遞減計數器需要在一個有限的時間視窗中被重新整理。如圖:
T[6:0]就是WWDG_CR的低七位,W[6:0]即是WWDG->CFR的低七位。T[6:0]
就是視窗看門狗的計數器,而
視窗看門狗的超時公式如下:
Twwdg=(4096×2^WDGTB×(T[5:0]+1))/Fpclk1;
其中:
Twwdg:WWDG超時時間(單位為ms)
Fpclk1:APB1的時鐘頻率(單位為Khz)
WDGTB:WWDG的預分頻係數
T[5:0]:視窗看門狗的計數器低6位
根據上面的公式,假設Fpclk1=42Mhz,那麼可以得到最小-最大超時時間表如圖所示:
接下來,我們介紹視窗看門狗的3個暫存器。首先介紹控制暫存器(WWDG_CR),該 暫存器的各位描述如圖
可以看出,這裡我們的WWDG_CR只有低八位有效,T[6:0]用來儲存看門狗的計數器值,隨時更新的,每個視窗看門狗計數週期(4096×2^WDGTB)減1。當該計數器的值從0X40變為0X3F的時候,將產生看門狗復位。WDGA位則是看門狗的啟用位,該位由軟體置1,以啟動看門狗,並且一定要注意的是該位一旦設定,就只能在硬體復位後才能清零了。
視窗看門狗的第二個暫存器是配置暫存器(WWDG_CFR),該暫存器的各位及其描述如圖
該位中的EWI是提前喚醒中斷,也就是在快要產生復位的前一段時間(T[6:0]=0X40
最後我們要介紹的是狀態暫存器(WWDG_SR),該暫存器用來記錄當前是否有提前喚醒的標誌。該暫存器僅有位0有效,其他都是保留位。當計數器值達到40h時,此位由硬體置1。它必須通過軟體寫0來清除。對此位寫1無效。即使中斷未被使能,在計數器的值達到0X40的時候,此位也會被置1,視窗看門狗庫函式相關原始碼和定義分佈在檔案stm32f4xx_wwdg.c檔案和標頭檔案stm32f4xx_wwdg.h中
二.視窗看門狗應用
1)使能WWDG時鐘
WWDG不同於IWDG,IWDG 有自己獨立的32Khz時鐘,不存在使能問題。而WWDG使用的是PCLK1的時鐘,需要先使能時鐘。方法是:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //WWDG時鐘使能
2)設定視窗值和分頻數
設定視窗值的函式是:
voidWWDG_SetWindowValue(uint8_t WindowValue);
這個函式就一個入口引數為視窗值,很容易理解。設定分頻數的函式是:
voidWWDG_SetPrescaler(uint32_t WWDG_Prescaler);
這個函式同樣只有一個入口引數就是分頻值。
3)開啟WWDG中斷並分組
開啟WWDG中斷的函式為:
WWDG_EnableIT();//開啟視窗看門狗中斷
接下來是進行中斷優先順序配置,這裡就不重複了,使用NVIC_Init()函式即可。
4)設定計數器初始值並使能看門狗
這一步在庫函式裡面是通過一個函式實現的:
voidWWDG_Enable(uint8_t Counter);
該函式既設定了計數器初始值,同時使能了視窗看門狗。
這裡還需要說明一下,庫函式還提供了一個獨立的設定計數器值的函式為:
voidWWDG_SetCounter(uint8_t Counter);
5)編寫中斷服務函式
在最後,還是要編寫視窗看門狗的中斷服務函式,通過該函式來喂狗,喂狗要快,否則當視窗看門狗計數器值減到0X3F的時候,就會引起軟復位了。在中斷服務函式裡面也要將狀態暫存器的EWIF位清空。
三.視窗看門狗原始碼
Wwdog.h
#ifndef_WWDOG_H_H_H
#define_WWDOG_H_H_H
#include"stm32f4xx_wwdg.h"
voidWWDG_Init(u8 tr,u8 wr,u32 fprer);
voidWWDG_IRQHandler(void);
#endif
Wwdog.c
#include"wwdog.h"
#include"led.h"
//儲存WWDG計數器的設定值,預設為最大.
u8WWDG_CNT=0X7F;
voidWWDG_Init(u8 tr,u8 wr,u32 fprer)
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE); //使能視窗看門狗時鐘
WWDG_CNT=tr&WWDG_CNT; //初始化WWDG_CNT.
WWDG_SetPrescaler(fprer); //設定分頻值
WWDG_SetWindowValue(wr); //設定視窗值
//WWDG_SetCounter(WWDG_CNT);//設定計數值
WWDG_Enable(WWDG_CNT); //開啟看門狗
NVIC_InitStructure.NVIC_IRQChannel=WWDG_IRQn; //視窗看門狗中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02; //搶佔優先順序為2
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //子優先順序為3
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能視窗看門狗
NVIC_Init(&NVIC_InitStructure);
WWDG_ClearFlag();//清除提前喚醒中斷標誌位
WWDG_EnableIT();//開啟提前喚醒中斷
}
//視窗看門狗中斷服務程式
voidWWDG_IRQHandler(void)
{
static int count = 0;
WWDG_SetCounter(WWDG_CNT); //重設視窗看門狗值
WWDG_ClearFlag();//清除提前喚醒中斷標誌位
if(count++ % 2 == 0)
{
LED_Operate(LED_RED,LED_ON);
}
else
{
LED_Operate(LED_RED,LED_OFF);
}
}
Main.c
#include"led.h"
#include"key.h"
#include"delay.h"
#include"uart.h"
#include"exit.h"
#include"iwdog.h"
voidUser_Delay(__IO uint32_t nCount)
{
while(nCount--)
{
}
}
staticint count = 0;
intmain(void)
{
#if 1
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設定系統中斷優先順序分組2
delay_init(168); //初始化延時函式
LED_Init(); //初始化LED埠
KEY_Init(); //初始化按鍵
LED_Operate(LED_BLUE,LED_ON); //點亮LED0
delay_ms(300);
WWDG_Init(0x7F,0X5F,WWDG_Prescaler_8); //計數器值為7f,視窗暫存器為5f,分頻數為8
while(1)
{
LED_Operate(LED_BLUE,LED_OFF);
}
#endif
}