WDG看门狗(独立看门狗和窗口看门狗)
WDG看门狗
文章目录
- WDG看门狗
- 1.WDG简介
- 2.IWDG独立看门狗
- 2.1IWDG框图
- 2.1.1实现步骤(配置流程)
- 2.1.2相关库函数
- 2.2IWDG键寄存器
- 2.3超时时间计算
- 3.WWDG窗口看门狗
- 3.1WWDG框图
- 3.1.1实现步骤
- 3.1.2相关库函数
- 3.2工作特性
- 3.3WWDG超时时间
- 3.4窗口看门狗的配置寄存器和控制寄存器的位用处
- 4.IWDG和WWDG对比(区别)
- 5.独立看门狗(实操)
- 5.1接线图
- 5.2代码部分
- 6.窗口看门狗
- 6.1接线图
- 6.2代码部分
1.WDG简介
- WDG(Watchdog)看门狗
- 看门狗可以监控程序的运行状态,当程序因为设计漏洞、硬件故障、电磁干扰等原因,出现卡死或跑飞现象时,看门狗能及时复位程序,避免程序陷入长时间的罢工状态,保证系统的可靠性和安全性
- 看门狗本质上是一个定时器,当指定时间范围内,程序没有执行喂狗(重置计数器)操作时,看门狗硬件电路就自动产生复位信号
- STM32内置两个看门狗
- 独立看门狗(IWDG):独立工作,对时间精度要求较低
- 窗口看门狗(WWDG):要求看门狗在精确计时窗口起作用
独立工作,就是独立看门狗的时钟是专用的LSI,内部低速时钟,即使主时钟出现问题了,看门狗也可以正常工作,独立看门狗有一个最短界限,只要喂狗间隔只要不超过这个最晚界限就行了
精确计时窗口:意思就是喂狗的时间有个最晚的界限,也有个最早的界限,必须在这个界限的窗口内喂狗,使用的是APB1的时钟,没有专用的时钟,所以不算独立
2.IWDG独立看门狗
2.1IWDG框图
独立看门狗
2.1.1实现步骤(配置流程)
- 开启LSI(开启独立看门狗,LSI就会被强制打开)
- 写入预分频器和重装寄存器(需要先解除写保护),根据超时时间公式写入预分频值和重装值
- 使用0xCCCC启动独立看门狗
- 在主程序中写入0xAAAA来进行喂狗操作
2.1.2相关库函数
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);//写使能操作,定义处0x5555(解除写保护)就是enbale使能,0x0000(启用写保护)就是disable失能
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);//写预分频器,就是写PR寄存器
void IWDG_SetReload(uint16_t Reload);//写重装值,RLR寄存器
void IWDG_ReloadCounter(void);//重新装载寄存器,就是喂狗
void IWDG_Enable(void);//键寄存器写入0xCCCC,启动看门狗
FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);//获取标志位状态
查看复位是看门狗导致的复位还是,系统或复位键导致的复位。
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG);//查看标志位的函数,根据参数查看对应的标志位,时钟或触发状态等
void RCC_ClearFlag(void);//清除标志位
2.2IWDG键寄存器
- 键寄存器本质上是控制寄存器,用于控制硬件电路的工作
- 在可能存在干扰的情况下,一般通过在整个键寄存器写入特定值来代替控制寄存器写入一位的功能,以降低硬件电路受到干扰的概率
如果只有一位,那么一位被误写的概率大,所以采用特定的值(16位),如下表:
写入键寄存器的值 | 作用 |
---|---|
0xCCCC | 启用独立看门狗 |
0xAAAA | IWDG_RLR中的值重新加载到计数器(喂狗) |
0x5555 | 解除IWDG_PR和IWDG_RLR的写保护 |
0x5555之外的其他值 | 启用IWDG_PR和IWDG_RLR的写保护 |
在键寄存器写入特定的值,进行设置,对其他寄存器进行保护和修改(PR,SR,RLR)
总之,键寄存器设置的用途就是防止误操作。
2.3超时时间计算
写入PR和RL寄存器来确定超时时间。
超时时间: T I W D G T_{IWDG} TIWDG = T L S I T_{LSI} TLSI × PR预分频系数 × (RL + 1)
其中: T L S I T_{LSI} TLSI = 1 F L S I \frac{1}{ F_{LSI}} FLSI1
在40kHz下,T周期为1/40KHz = 0.025ms,表格:如果PR等于选择0的话,预分频系数可选4,最短时间RL可选0x000(0+1),最长时间RL可选0xFFF(4095+1),0.025*4*1=0.1;0.025*4*4096 = 409.6
3.WWDG窗口看门狗
3.1WWDG框图
3.1.1实现步骤
- 开启窗口看门狗APB1的时钟(不会自动开启)
- 配置寄存器(预分频和窗口值),没有写保护
- 写入控制寄存器CR(包含看门狗使能位,计数器溢出标志位和计数器有效位)
- 不断向计数器写入想要的重装值就可以进行喂狗了
3.1.2相关库函数
void WWDG_DeInit(void);//恢复缺省配置
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);//写入预分频器
void WWDG_SetWindowValue(uint8_t WindowValue);//写入窗口值(初始化配置采用这两个函数)
void WWDG_EnableIT(void);//使能中断,只有一个中断所以不需要指定参数
void WWDG_SetCounter(uint8_t Counter);//写入计数器,喂狗使用这个函数
void WWDG_Enable(uint8_t Counter);//使能窗口看门狗,初始化后启动看门狗就用这个函数,参数是防止一使能就复位,所以指定喂狗
FlagStatus WWDG_GetFlagStatus(void);//获取标志位
void WWDG_ClearFlag(void);//和清除标志位的函数
3.2工作特性
- 递减计数器T[6:0]的值小于0x40时,WWDG产生复位
- 递减计数器T[6:0]在窗口W[6:0]外被重新装载时,WWDG产生复位
- 递减计数器T[6:0]等于0x40时可以产生早期唤醒中断(EWI),用于重装载计数器以避免WWDG复位
- 定期写入WWDG_CR寄存器(喂狗)以避免WWDG复位
等于0x40:就是在发送复位信号的前一刻,可以进行一些紧急操作,比如保存数据或这直接处理问题等,可以在早期唤醒中断中直接执行喂狗,阻止系统复位
3.3WWDG超时时间
超时时间:
T W W D G T_{WWDG} TWWDG = T P C L K 1 T_{PCLK1} TPCLK1 × 4096 × WDGTB预分频系数 × (T[5:0] + 1)
(上面的T[5:0]是计数器减到0的时间)
窗口时间:
T W I N T_{WIN} TWIN= T P C L K 1 T_{PCLK1} TPCLK1 × 4096 × WDGTB预分频系数 × (T[5:0] - W[5:0])
(上面的T[5:0] - W[5:0]为计数器减到窗口值得时间)
其中: T P C L K 1 T_{PCLK1} TPCLK1 = 1 F P C L K 1 \frac{1 }{F_{PCLK1}} FPCLK11
TPCLK1 = 1/36MHz
TWWDG = 1/36MHz*4096* 2 0 2^0 20*(0+1)=113us(6位计数器最小值)
TWWDG = 1/36MHz*4096* 2 0 2^0 20*( 2 6 2^6 26+1)=7.28ms(6位计数器最大值值)
3.4窗口看门狗的配置寄存器和控制寄存器的位用处
寄存器 | 作用 | 位域说明 |
---|---|---|
WWDG_CR | 控制看门狗的使能、当前计数器值 | - 位 7 (WDGA): 看门狗激活位(置 1 后锁定配置) - 位 6:0 (T[6:0]): 当前计数器值(7 位,范围 0x00~0x7F ) |
WWDG_CFR | 配置窗口值、预分频系数和中断 | - 位 6:0 (W[6:0]): 窗口值(7 位,必须大于 0x3F )- 位 9:8 (WDGTB[1:0]): 预分频系数 - 位 9 (EWI): 早期唤醒中断使能位 |
4.IWDG和WWDG对比(区别)
IWDG独立看门狗 | WWDG窗口看门狗 | |
---|---|---|
复位 | 计数器减到0后 | 计数器T[5:0]减到0后、过早重装计数器 |
中断 | 无 | 早期唤醒中断 |
时钟源 | LSI(40KHz) | PCLK1(36MHz) |
预分频系数 | 4、8、32、64、128、256 | 1、2、4、8 |
计数器 | 12位 | 6位(有效计数) |
超时时间 | 0.1ms~26214.4ms | 113us~58.25ms |
喂狗方式 | 写入键寄存器,重装固定值RLR | 直接写入计数器,写多少重装多少 |
防误操作 | 键寄存器和写保护 | 无 |
用途 | 独立工作,对时间精度要求较低 | 要求看门狗在精确计时窗口起作用 |
看门狗一旦启用,就无法关闭
5.独立看门狗(实操)
5.1接线图
5.2代码部分
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
//#include "OLED_Font.h"int main(void){OLED_Init();Key_Init();OLED_ShowString(1,1,"IWDG TEST");if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET){//看门狗标志位是否为1OLED_ShowString(2,1,"IWDGRST");Delay_ms(500);OLED_ShowString(2,1," ");Delay_ms(100);RCC_ClearFlag();}else{OLED_ShowString(3,1,"RST");Delay_ms(500);OLED_ShowString(3,1," ");Delay_ms(100);}IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//超时时间计算公式见笔记IWDG_SetPrescaler(IWDG_Prescaler_16);IWDG_SetReload(2499);IWDG_ReloadCounter();//喂一次狗IWDG_Enable();while(1){Key_getNum();//按下按钮,长时间没响应触发中断IWDG_ReloadCounter();OLED_ShowString(4,1,"FEED");Delay_ms(200);OLED_ShowString(4,1," ");Delay_ms(600);//共延迟800ms,没有超过1000ms,不会}
}
按键未按下时:
- 主循环正常执行,每 800ms 喂狗一次(<1 秒超时时间)
- 看门狗不会触发复位
- OLED 交替显示 “FEED” 和空白
按键按下时:
Key_getNum()
进入阻塞状态,等待按键释放- 如果按住时间超过 1 秒,看门狗计数器溢出,触发系统复位
- 重启后检测到
RCC_FLAG_IWDGRST
标志,显示 “IWDGRST”
6.窗口看门狗
6.1接线图
6.2代码部分
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
//#include "OLED_Font.h"int main(void){OLED_Init();Key_Init();OLED_ShowString(1,1,"WWDG TEST");if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET){//看门狗标志位是否为1OLED_ShowString(2,1,"WWDFRST");Delay_ms(500);OLED_ShowString(2,1," ");Delay_ms(100);RCC_ClearFlag();}else{OLED_ShowString(3,1,"RST");Delay_ms(500);OLED_ShowString(3,1," ");Delay_ms(100);}//窗口看门狗初始化RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);WWDG_SetPrescaler(WWDG_Prescaler_8);WWDG_SetWindowValue(0x40 + 21); //30msWWDG_Enable(0x40 + 54); //50ms//窗口看门狗需要在使能窗口看门狗的时候写入计数器时间while(1){Key_getNum();//按下按钮,长时间没响应触发中断OLED_ShowString(4,1,"FEED");Delay_ms(24);OLED_ShowString(4,1," ");Delay_ms(25);//共延迟800ms,没有超过1000ms,不会WWDG_SetCounter(0x40 + 54);//喂狗}
}
需要加上0x40是因为,公式计算的数值是T[5:0]的数值,而实际上6位,所以要加上最高位也就是0x40。
需要注意的是,看门狗的使能时写入计数器的值与进入主循环后再向计数器中写入重装值不能靠的太近,否则会出错。