一、原理介绍
1.独立看门狗
IWDG(Independent watchdog)独立看门狗
本质:能产生系统复位信号的计数器
特性:
- 递减的计数器;
- 时钟由独立的RC振荡器提供(可在待机和停止模式下运行);
- 看门狗被激活后,当计数器计数到0x000时产生复位。
喂狗:在计数器计数到0之前,重装载计数器的值,防止复位。
IWDG有什么用?
- 异常:外界电磁干扰或者自身系统(硬件或软件)异常,造成程序跑飞。如:陷入某个不正常的死循环,打断正常的程序执行。
- 作用:主要用于检测外界电磁干扰,或硬件异常导致的程序跑飞。
- 应用:在一些需要高稳定性的产品中,并且对时间精度要求较低的场合。
IWDG工作原理图
CPU必须及时喂狗,否则系统复位重启!!
IWDG框图
启用IWDG后,LSI时钟会自动开启。
LSI时钟并不精确,F1用40KHz,F4/F7/H7用32KHz进行计算。
IWDG溢出时间计算:
2.窗口看门狗
WWDG(Window watchdog)串口看门狗
本质:能产生系统复位信号和提前唤醒中断的计数器。
特性:
- 递减的计数器;
- 当计数器值从0x40减到0x3F时(即T6位跳变为0时),会产生复位;
- 计数器的值大于W[6:0]值时喂狗,会产生复位;
- 提前唤醒中断(EWI):当递减计数器等于0x40时可产生。
喂狗:在窗口期内重装载计数器的值,防止复位。
WWDG有什么用?
- 作用:用于监测单片机程序运行时效是否精准,主要检测软件异常。
- 应用:需要精准监测程序运行时间的场合。
WWDG工作原理:
W[6:0]必须大于0x3F,否则窗口期不存在。
WWDG框图:
WWDG超时时间计算公式:
其中:
——WWDG超时时间(没喂狗)
——WWDG的时钟源频率
4096——WWDG固定的预分频系数
2^{WDGTB}——WWDG_CFR寄存器设置的预分频系数值
T[5:0]——WWDG计数器低6位
3.IWDG和WWDG的主要区别
对比点 | IWDG | WWDG |
---|---|---|
时钟源 | LSI(40KHz或32KHz) | PCLK1或PCLK3 |
复位条件 | 递减计数到0 | 计数值大于W[6:0]或递减计数到0x3F |
中断 | 无中断 | 计数值递减到0x40时可产生中断 |
递减计数器位数 | 12位(最大计数范围4095~0) | 7位(最大计数范围:127~63) |
应用场合 | 防止程序跑飞、死循环、死机 | 监测程序时效,防止软件异常 |
二、环境
硬件:STM32F407ZGT6开发板
软件:STM32CubeMx、Keil5 MDK、串口调试助手
三、使用STM32CubeMx初始化配置
本实验会用到串口,所以配置是在串口实验的基础上进行配置的。
1.IWDG配置
激活IWDG,并配置分频系数为64,重装载值为500。由于F4的时钟源频率是32KHz,所以溢出时间为1s。
2.WWDG配置
激活WWDG,并配置分频系数为8,窗口上限值为96,重装载值为127。则超时时间为49.93.ms。
然后使能提前唤醒中断和串口看门狗中断。
四、看门狗实验
1.IWDG实验
本实验使用串口每900ms发送一次字符串“Normal_state”,如果在1s内不喂狗,则复位MCU,打印"SYS_INIT_OK"。
首先打开main.c文件,在主函数中使用HAL_IWDG_Init()函数启动独立看门狗。
然后在while循环中,每900ms喂一次狗。
printf("SYS_INIT_OK\r\n"); //系统启动时打印字符串
HAL_IWDG_Init(&hiwdg); //启动独立看门狗
HAL_IWDG_Refresh(&hiwdg); //1s内必须喂一次狗,否则单片机复位
HAL_Delay(900); //小于1s,否则看门狗会产生复位信号
printf ("Normal state\r\n"); //若未复位,则打印字符串
编译下载到开发板后,打开串口调试助手,程序运行无异常。
若将延时时间改为1000ms,则系统会不断地复位。
经测试,当延时时间只要大于986ms,那么系统就会不断地被复位,因为独立看门狗的RC时钟源频率并不是很精准,且发送字符串等操作也要占用一部分时间。
2.WWDG实验
本实验将使用串口每1ms发送一次“1”,并在每次喂狗后发送一次字符串“OK!”。
由于使能了早期唤醒中断,那么喂狗函数在中断回调函数中执行,在main.c文件中对串口看门狗早期唤醒中断进行定义。
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg) //窗口看门狗早期唤醒中断回调函数
{
HAL_WWDG_Refresh(hwwdg); //喂狗
printf("ok!\r\n"); //打印喂狗成功标志
}
在主函数中首先打印一个字符串“SYS_INIT_OK”,然后在while循环中,每1ms打印一次“1”。
这样,不喂狗的话,串口调试助手中会频繁打印“SYS_INIT_OK”,标志着系统复位了;如果喂狗的话,就频繁地打印“1”,并且周期性地插入“OK!”字符串。
编译下载到开发板上,可以看到符合基本预设。