一,窗口看門狗介紹
獨立看門狗的喂狗範圍 0-X(X由預分頻器和重裝載值決定,最大值爲0xFFF)
獨立看門狗相關介紹:傳送門:獨立看門狗
相比於獨立看門狗,窗口看門狗限定了喂狗時間段(由喂狗上限和喂狗下限值限定的喂狗範圍)
所以形象的稱作窗口看門狗
二,爲什麼需要窗口看門狗
獨立看門狗:在0-重載值之間任意時間都可以喂狗
如果程序跑飛後又跑回正常
或者跑亂的程序正好執行了刷新看門狗
這樣獨立看門狗是不能檢查到並復位芯片的
窗口看門狗:限制了喂狗時間
如果程序跑飛並且在限制的時間段喂狗是很困難的
從而保證了程序的正常運行
三,獨立看門狗和窗口看門狗比較
獨立看門狗:
驅動:由LSI驅動,即使主時鐘發生故障它仍有效
適用場景:
作爲主程序之外能夠完全獨立工作
對時間精度要求較低
窗口看門狗:
驅動:由APB1時鐘分頻後得到時鐘驅動
適用場景:
在精確計時窗口起作用的程序
四,獨立看門狗工作原理
參數: CNT:遞減計數器 窗口上限:寄存器設置 窗口下限:0x3F 隨時間推移,計數器值遞減,經過上窗口W和下窗口 重載值->上窗口:這段時間不允許喂狗,如果喂狗會使芯片復位 上窗口->下窗口:這段時間允許喂狗,下窗口位固定值(0x3F) 下窗口:進入下窗口會產生復位 T6位: 0x3F=00111111 在計數器到達0x3F之前第六位爲1
所以當計數器到達窗口下限前T6位爲1,到達窗口下限後T6位爲低電平
復位: 當計數器到達窗口下限(喂狗失敗),會產生MCU復位信號,使芯片復位
五,窗口看門狗復位分析
遞減計數器時鐘:
時鐘來源PCLK1
由於PCLK1時鐘頻率過高/4096
再經過預分頻器WDGTB
預分頻後作爲遞減計數器時鐘
WWDG_CR寄存器:
T7:WDGA啓動位-使能窗口看門狗
T0-6 :6位遞減計數器寄存器
WWDG_CFR寄存器:
W0-6:設置窗口看門狗上窗口值
比較器:
比較遞減計數器CNT和上窗口寄存器大小關係
遞減計數器值>上窗口值 比較結果爲1
分析一: 計數器值>上窗口值時,喂狗,會產生復位
當計數器值>上窗口值時,比較器比較結果輸出爲1
此時喂狗,與門1下端輸入爲1
所以,或門1上端輸入爲1,導致與門2右端輸入爲1
此時看門狗處於使能狀態,與門2左端輸入爲1
所以芯片產生復位
分析二: 計數器值到達0x3F,會產生復位
當計數器值到達0x3F時,T6位從1跳變到0
或門1下端輸入通過取反置1,所以或門1輸出值爲1,與門右側輸入值爲1
此時看門狗處於使能狀態,與門2左端輸入爲1
所以芯片產生復位
總結:窗口看門狗有兩種情況會產生復位
1,喂狗時間大於窗口上限值 2,計數器值從0x40減到0x3F
如果啓動看門狗並且允許中斷,當遞減計數器等於0x40時,會產生喚醒中斷EWI,它可以用於喂狗避免WWDG復位
窗口看門狗使用注意
上窗口值W[6:0]必須大於下窗口值0x40(0x40產生喚醒中斷),否則窗口看門狗就沒有窗口了
六,窗口看門狗的超時時間
時鐘來源:
Fpclk1除以4096再經過WDGTB預分頻器
f = Fpclk1 / (4096 * 2^WDGTB)
超時時間:
窗口看門狗時鐘週期(時鐘頻率f分之1)
t = 1/f * 看門狗計數器重載值
七,窗口看門狗相關寄存器
直接寫WWDG_CR[6:0]實現喂狗
獨立看門狗喂狗:向鍵值寄存器IWDG_KR寫0xAAAA喂狗.將IWDG_RLR寄存器值重新裝載到計數器
位0-6設置上窗口值
位7-8設置時基-窗口看門狗的時鐘頻率
位9提前喚醒中斷使能位(1:使能)當計數器到達0x40產生中斷
WWDG_SR只用到位0:提前喚醒中斷標誌
當計數器達到0x40時,由硬件置1,需軟件清零
八,窗口看門狗相關庫函數
stm32f10x_wwdg.h中找到相關函數頭文件
/** @defgroup WWDG_Exported_Functions
* @{
*/
void WWDG_DeInit(void); // 窗口看門狗復位
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler); // 設置預分頻係數-WWDG_CFR[8:7]
void WWDG_SetWindowValue(uint8_t WindowValue); // 設置上窗口值-WWDG_CFR[6:0]
void WWDG_EnableIT(void); // 使能窗口看門狗中斷-提前喚醒中斷WWDG_CFR[9]
void WWDG_SetCounter(uint8_t Counter); // 喂狗-重新寫WWDG_CR[6:0]
void WWDG_Enable(uint8_t Counter); // 使能窗口看門狗並設置初值-WWDG_CR[7]+WWDG_CR[6:0]
FlagStatus WWDG_GetFlagStatus(void); // 獲取WWDG_SR寄存器標誌位
void WWDG_ClearFlag(void); // 清除WWDG_SR寄存器標誌位
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
九,窗口看門狗相關配置步驟
// 1,使能看門狗時鐘:
RCC_APB1PeriphClockCmd(); // 窗口看門狗時鐘來自APB1時鐘
// 2,設置分頻係數:
WWDG_SetPrescaler(); // 確定窗口看門狗時鐘
// 3,設置上窗口值:
WWDG_SetWindowValue(); // 設置上窗口值(下窗口值爲0x3F)
// 4,開啓提前喚醒中斷並設置中斷優先級:
WWDG_EnableIT(); // 開啓提前喚醒中斷,當到達0x40時產生中斷,在中斷喂狗
NVIC_Init(); // 使用中斷要NVIC初始化(先進行中斷優先級分組)
// 5,使能看門狗:
WWDG_Enable();
// 6,喂狗:
WWDG_SetCounter();
// 7,編寫中斷服務函數
WWDG_IRQHandler(); // 在中斷中喂狗
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
十,窗口看門狗代碼:
HARDWARE/WDG目錄新建wgd.h
#ifndef __WDG_H
#define __WDG_H
#include "sys.h" // 用到了u8 u32
void WWDG_Init(u8 tr,u8 wr,u32 fprer);// 初始化WWDG
void WWDG_Set_Counter(u8 cnt); // 設置WWDG的計數器 - 喂狗
void WWDG_NVIC_Init(void); // 初始化窗口看門狗中斷優先級配置
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
HARDWARE/WDG目錄新建wgd.c
#include "wdg.h"
#include "led.h"
//WWDG計數器值,默認爲最大0x7F
u8 WWDG_CNT=0x7f;
//初始化窗口看門狗
// tr : T[6:0],計數器值
// wr : W[6:0],窗口值
// fprer: 分頻係數(WDGTB),僅最低2位有效
// Fwwdg = PCLK1 / (4096 * 2^fprer).
void WWDG_Init(u8 tr, u8 wr, u32 fprer)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG時鐘使能
WWDG_CNT=tr&WWDG_CNT; // 初始化WWDG_CNT (只取低7位,防止溢出)
WWDG_SetPrescaler(fprer); // 設置IWDG預分頻值
WWDG_SetWindowValue(wr); // 設置窗口值
WWDG_Enable(WWDG_CNT); // 設置看門狗使能位,並第一次喂狗
WWDG_ClearFlag(); // 清除提前喚醒中斷標誌位
WWDG_NVIC_Init(); // 窗口看門狗中斷優先級設置
WWDG_EnableIT(); // 開啓窗口看門狗中斷
}
// 喂狗-重置WWDG計數器值
void WWDG_Set_Counter(u8 cnt)
{
WWDG_Enable(cnt); // 使能窗口看門狗並設置初值(首次喂狗)
}
// 窗口看門狗中斷服務程序
void WWDG_NVIC_Init()
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; // WWDG中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 搶佔2,子優先級3,組2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 搶佔2,子優先級3,組2
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; // 使能
NVIC_Init(&NVIC_InitStructure); // NVIC初始化
}
//計數器到達0x40時進入
void WWDG_IRQHandler(void)
{
WWDG_SetCounter(WWDG_CNT); // 註釋此句,窗口看門狗將產生復位
WWDG_ClearFlag(); // 清除提前喚醒中斷標誌位
LED1=!LED1; // LED1狀態翻轉 - 指示喂狗成功
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
USER/main.c主函數編寫
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "wdg.h"
int main(void)
{
delay_init(); // 延時函數初始化
// 設置中斷優先級分組爲組2:2位搶佔優先級,2位響應優先級
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200); // 串口初始化爲115200
LED_Init(); // LED端口初始化
KEY_Init(); // 按鍵初始化
LED0=0; // LED0點亮
delay_ms(300); // 延時300ms
// 計數器值爲7f,窗口寄存器爲5f,分頻數爲8
WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);
while(1)
{
LED0=1; // LED0熄滅
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
以上程序實現:
程序初始化LED點亮延時300ms熄滅 窗口看門狗從0x7F開始遞減計數,上窗口爲0x5F,下窗口爲0x3F 計數器到達0x40進入提前喚醒中斷, 在中斷函數中進行喂狗操作,計數器翻轉(從0x7F重新計數),LED1翻轉 以此循環...
翻轉頻率爲從0x7F計數到0x40,翻轉時間可以根據公式計算
正常喂狗: LED0亮300ms之後熄滅,LED1不斷閃爍 喂狗失敗(註釋掉喂狗函數): 程序不斷復位,LED0閃爍