一、看门狗概念
1.1 为啥需要看门狗
-
应对软件错误:在复杂的软件系统中,由于程序错误或异常情况导致系统死锁、无限循环等问题时,可能会导致系统停止响应。看门狗可以监视系统运行状态,一旦系统停止响应,看门狗就会重启系统,使其恢复到正常运行状态。
-
应对硬件故障:在嵌入式系统中,由于硬件故障(如电源问题、外部干扰等),系统可能会出现异常情况。看门狗可以检测到系统异常并触发重启操作,以应对硬件故障造成的系统停止响应问题。
-
提高系统稳定性:通过定期喂狗(重置看门狗计时器),可以确保系统在正常运行时能够持续地运行。这有助于提高系统的稳定性和可用性。
-
应对环境变化:在一些特殊环境下(如高温、高湿度、电磁干扰等),系统可能会遇到意外情况导致运行异常。看门狗可以监视系统状态,及时应对这些突发情况。
-
远程系统管理:对于远程或分布式系统,看门狗可以通过远程监控和重启功能,实现对系统的远程管理和维护。
引入看门狗能够提高系统的可靠性和稳定性,保证系统在各种异常情况下能够及时恢复到正常运行状态,从而确保系统的持续稳定运行。因此,看门狗在嵌入式系统、实时系统和其他对系统稳定性要求较高的场景中得到了广泛应用。
1.2 什么是看门狗
看门狗就像是一个守护者,专门监视电子设备的运行状态。它的工作方式类似于定时器,会周期性地计时。如果设备一直正常运行,就会定时“喂狗”,保持看门狗沉默;但如果设备出现了故障或者停顿,没有及时“喂狗”,看门狗就会发出狗叫产生警报,甚至执行重启操作,让设备重新启动,从而恢复正常工作。看门狗就像是设备的“保护神”,确保设备在任何情况下都能保持稳定运行。
STM32 有两个看门狗,一个是独立看门狗另外一个是窗口看门狗 。独立看门狗用通俗一 点的话来解释就是一个12 位的递减计数器,当计数器的值从某个值一直减到0 的时候,系统就 会产生一个复位信号,即IWDG_RESET。如果在计数没减到0 之前,刷新了计数器的值的话,那 么就不会产生复位信号,这个动作就是我们经常说的喂狗。
计时器:看门狗通常包含一个定时器,它在系统启动后开始计时。计时器的计数值会不断递增。
喂狗(Feed the Dog):系统正常运行时,会定期“喂狗”,即重置看门狗的计时器,防止其超时。这通常是通过特定的指令或操作完成的,比如写入特定的寄存器或执行特定的指令。
超时重启:如果系统出现故障、死锁或停止响应,导致无法及时“喂狗”,则看门狗的计时器会超时。一旦超时发生,看门狗会触发系统重启操作,使系统恢复到初始状态。
在嵌入式系统中,看门狗通常是通过硬件实现的,但也可以通过软件模拟。它可以帮助系统应对各种异常情况,如死锁、程序错误、电源故障等,从而提高系统的可靠性和稳定性。看门狗的超时时间通常根据系统的需求进行配置,以在适当的时机触发重启操作。
二、独立看门狗
独立看门狗(Independent Watchdog,IWDG)是一种硬件看门狗,它是嵌入式系统中的一个独立的硬件模块,用于监视系统的运行状态。独立看门狗与处理器核心相分离,通常由专用的硬件电路实现,能够在系统出现异常或停止响应时自主触发重启操作。
独立看门狗 (IWDG) 由其专用低速时钟 (LSI) 驱动,因此即便在主时钟发生故障时仍然保持工作状态。窗口看门狗 (WWDG) 时钟由 APB1 时钟经预分频后提供,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。
IWDG 最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。WWDG 最适合那些要求看门狗在精确计时窗口起作用的应用程序。
IWDG主要特性
● 自由运行递减计数器● 时钟由独立 RC 振荡器提供(可在待机和停止模式下运行)● 当递减计数器值达到 0x000 时产生复位(如果看门狗已激活)
2.1 独立看门狗时钟
独立看门狗的时钟由独立的RC 振荡器LSI 提供,即使主时钟发生故障它仍然有效,非常独立。 LSI 的频率一般在30~60KHZ 之间,根据温度和工作场合会有一定的漂移, 所以独立看门狗的定时时间并不一定非常精确,只适用于对时间精度要求比较低的场合。
(需要注意独立看门狗的时钟并不是准确的 32Khz, 而是在 15~47Khz之间的一个可变化的时钟 )
2.2 计数器时钟(IWDG_PR)
递减计数器的时钟由LSI 经过一个8 位的预分频器得到,我们可以操作预分频器寄存器 IWDG_PR 来设置分频因子,分频因子可以是:[4,8,16,32,64,128,256]
计数器时钟CK_CNT= 40/ 4*2^PRV,一个计数时钟到来,计数器就减一。
2.3 计数器
独立看门狗的计数器是一个12 位的递减计数器,最大值为0XFFF,当计数器减到0 时,会产生 一个复位信号:IWDG_RESET,让程序重新启动运行,如果在计数器减到0 之前刷新了计数器的 值的话,就不会产生复位信号,重新刷新计数器值的这个动作我们俗称喂狗。
2.4 重装载计数器(IWDG_RLR)
重装载寄存器是一个12 位的寄存器,里面装着要刷新到计数器的值,这个值的大小决定着独立 看门狗的溢出时间。超时时间Tout = (4*2^prv) / 40 * rlv (s) ,prv 是预分频器寄存器的值,rlv 是 重装载寄存器的值。
2.5 键寄存器(IWDG_KR)
键寄存器IWDG_KR 可以说是独立看门狗的一个控制寄存器,主要有三种控制方式,往这个寄存 器写入下面三个不同的值有不同的效果。
IWDG_ReloadCounter(); #define KR_KEY_RELOAD ((uint16_t)0xAAAA)
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); #define IWDG_WriteAccess_Enable ((uint16_t)0x5555)
IWDG_Enable(); #define KR_KEY_ENABLE ((uint16_t)0xCCCC)
2.6 编程
IWDG 属于单片机内部资源,不需要外部电路,需要一个外部的按键和LED,通过按键来喂狗, 喂狗成功LED 灭,喂狗失败,程序重启,LED 亮一次。
iwdg.c
#include "public.h"
void IWDG_Init_Config(void)
{
//取消写保护
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
//设置分频系统
IWDG_SetPrescaler(IWDG_Prescaler_32);
//32分频 32khz/32=1khz 倒数一个数:1/1khz = 1/1000hz =0.001s = 1ms
//设置重装载值
IWDG_SetReload(2000); //数2000个数,用时2s
IWDG_ReloadCounter();
//启动
IWDG_Enable();
}
main.c
int main(void)
{
//2号分组:2bit给抢占 2bit给响应 0-3 0-3
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//SysTick_Init();
KEY_Init();
LED_Init();
IWDG_Init_Config();
GPIO_ResetBits(GPIOF,GPIO_Pin_9); //如果复位,则灯亮
while(1)
{
if(GetStaKey()==true)
{
GPIO_SetBits(GPIOF,GPIO_Pin_9);
IWDG_ReloadCounter(); //喂狗
}
}
}
三、窗口看门狗
窗口看门狗跟独立看门狗一样,也是一个递减 计数器不断的往下递减计数,当减到一个固定值0X40 时还不喂狗的话,产生复位,这个值叫窗 口的下限,是固定的值,不能改变。
这是跟独立看门狗类似的地方,不同的地方是窗口看门狗 的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值由用户 独立设置。窗口看门狗计数器的值必须在上窗口和下窗口之间才可以喂狗,这就是窗口看门狗中 窗口两个字的含义。
主要特性● 可编程的自由运行递减计数器● 复位条件— 当递减计数器值小于 0x40 时复位(如果看门狗已激活)— 在窗口之外重载递减计数器时复位(如果看门狗已激活)● 提前唤醒中断 (EWI) :当递减计数器等于 0x40 时触发(如果已使能且看门狗已激活)
T[6:0]就是 WWDG_CR的低七位, W[6:0]即是 WWDG-->CFR的低七位。 T[6:0]就是窗口看门狗的计数器,而 W[6:0]则是窗口看门狗的上窗口,下窗口值是固定的( 0X40)。
当窗口看门狗的计数器在上窗口值之外被刷新,或者低于下窗口值都会产生复位。 上 窗口值 W[6: 0] 是由用户自己设定的,根据实际要求来设计窗口值,但是一定要确保 窗口值大于 0X40,否则窗口就不存在了。其喂狗范围就是刷新范围。
3.1 窗口看门狗时钟
WWDG在工作时需要依赖于系统的时钟源。它通常与系统时钟源同步,并根据时钟源的节拍来进行计数和计时。
窗口看门狗时钟来自PCLK1,PCLK1 最大是42M,由RCC 时钟控制器开启。
3.2 计数器时钟
计数器时钟由CK 计时器时钟经过预分频器分频得到,分频系数由配置寄存器CFR 的WDGTB[1:0] 配置。
其中CK 计时器时钟=PCLK1/4096,除以4096 是手 册规定的,手册没有解释为什么(个人猜测还是为了降频)。所以计数器的时钟CNT_CK=PCLK1/4096/(2^WDGTB),这就可以算出 计数器减一个数的时间T= 1/CNT_CK = 4096 * (2^WDGTB) / PCLK1。
3.3 窗口值
我们知道窗口看门狗必须在计数器的值在一个范围内才可以喂狗,其中下窗口的值是固定的 0X40,上窗口的值可以改变,具体的由配置寄存器CFR 的位6:0 W[6:0] 设置。其值必须大于 0X40,如果小于或者等于0X40 就是失去了窗口的价值,而且也不能大于计数器的值,所以必须 得小于0X7F。
那窗口值具体要设置成多大?这个得根据我们需要监控的程序的运行时间来决定。 如果我们要监控的程序段A 运行的时间为Ta,当执行完这段程序之后就要进行喂狗,如果在窗 口时间内没有喂狗的话,那程序就肯定是出问题了。一般计数器的值TR 设置成最大0X7F,窗 口值为WR,计数器减一个数的时间为T,那么时间:(TR-WR)*T 应该稍微小于Ta 即可,这样 就能做到刚执行完程序段A 之后喂狗,起到监控的作用,这样也就可以算出WR 的值是多少。
最大值怎么算出来的?
例如WDGTB=0时,当计数值为0x40时,递减计数器再减一次,就产生复位 了,那这减1的时间就等于计数器的周期=1/CNT_CK = 4096 * (2^WDGTB)/PCLK1 = 1/30 * 4096 *2^0 =136.53us,这个就是最短的超时时间。
如果T[5:0] 全部装满为1,即63,当他减到0X40 变 成0X3F 时,所需的时间就是最大的超时时间=136.53*2^5=136.53*64=8.74ms。同理,当WDGTB 等于1/2/3 时,代入公式即可
3.4 使用时机
WWDG 一般被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序 列而产生的软件故障。比如一个程序段正常运行的时间是50ms,在运行完这个段程序之后紧接 着进行喂狗,如果在规定的时间窗口内还没有喂狗,那就说明我们监控的程序出故障了,跑飞了, 那么就会产生系统复位,让程序重新运行。
3.5 编程
让其自动进行喂狗,成功喂狗让LED亮
wwdg.c
#include "public.h"
void WWDG_Init_Config(void)
{
/* Enable WWDG clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
/* WWDG clock counter = (PCLK1 (42MHz)/4096)/8 = 1281 Hz (~780 us) */
WWDG_SetPrescaler(WWDG_Prescaler_8);
WWDG_SetWindowValue(80); // 上窗口值
WWDG_Enable(127); // 下窗口值最大值0x7F~0x40
NVIC_InitTypeDef NVIC_InitStructure;
//d.NVIC配置
NVIC_InitStructure.NVIC_IRQChannel=WWDG_IRQn; //设置中断通道
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x01; //设置响应优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x03;//设置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
WWDG_ClearFlag(); // 清除中断标志
WWDG_EnableIT(); // 开启中断
}
main.c
#include "public.h"
int main(void)
{
//2号分组:2bit给抢占 2bit给响应 0-3 0-3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SysTick_Init();
KEY_Init();
LED_Init();
WWDG_Init_Config();
GPIO_SetBits(GPIOF,GPIO_Pin_9); // 低电平 灭
while (1)
{
// 分频值 8 设置的上窗口值(80) 2*6
// ~780 * (127-80) = 36.6ms < refresh window < ~780 * 64 = 49.9ms
Delay_ms(30); // 喂狗时间
WWDG_SetCounter(127); // 喂狗
GPIO_ResetBits(GPIOF,GPIO_Pin_9); // 高电平 亮 喂狗成功,亮
}
}
中断服务函数
void WWDG_IRQHandler(void)
{
WWDG_Enable(127);
WWDG_ClearFlag();
GPIO_ResetBits(GPIOF,GPIO_Pin_9);
}
四、总结
4.1 独立看门狗
适用于需要在预定时间间隔内检测系统运行状态的场景。它独立于系统其他组件工作,定期检查系统的活动状态。如果系统在设定的时间内未喂狗,独立看门狗将触发重启操作。
用于检测系统死锁、无限循环等严重故障,并执行相应的恢复措施,确保系统稳定性和可靠性。
4.2 窗口看门狗
适用于需要在严格的时间窗口内监测系统运行状态的场景。它要求系统在指定的时间窗口内喂狗,而不仅仅是在预定时间间隔内。只有在窗口内喂狗,才能防止看门狗触发重启操作。
用于实时系统或对时间敏感的应用,确保系统在严格的时间要求内正常运行,避免因执行时间超出预期而触发看门狗重启。
综合来说,当系统对时间要求较为严格,需要确保在严格的时间窗口内完成特定任务时,通常会选择窗口看门狗。而当需要独立于系统其他组件工作、定期检查系统状态,并在发生严重故障时执行恢复操作时,通常会选择独立看门狗。