基于STM32F407ZGT6——看门狗
独立看门狗
独立看门狗的时钟由独立的RC 振荡器LSI 提供,即使主时钟发生故障它仍然有效,非常独立。 LSI 的频率一般在30~60KHZ 之间,根据温度和工作场合会有一定的漂移, 所以独立看门狗的定时时间并不一定非常精确,只适用于对时间精度要求比较低的场合。(需要注意独立看门狗的时钟并不是准确的 32Khz, 而是在 15~47Khz之间的一个可变化的时钟 )
1.计数器时钟
递减计数器的时钟由LSI 经过一个8 位的预分频器得到,我们可以操作预分频器寄存器 IWDG_PR 来设置分频因子,分频因子可以是:[4,8,16,32,64,128,256]
计数器时钟CK_CNT= 40/ 4*2^PRV,一个计数时钟到来,计数器就减一。
(置位110和111都是256分频)
2.重装载计数器
重装载寄存器是一个12 位的寄存器,里面装着要刷新到计数器的值,这个值的大小决定着独立 看门狗的溢出时间。超时时间Tout = (4*2^prv) / 40 * rlv (s) ,prv 是预分频器寄存器的值,rlv 是 重装载寄存器的值。
3.键寄存器IWDG_KR
键寄存器IWDG_KR 可以说是独立看门狗的一个控制寄存器,主要有三种控制方式,往这个寄存 器写入下面三个不同的值有不同的效果。
4.独立看门狗代码
#include "iwdg.h"
/*
1.取消写保护 IWDG_WriteAccessCmd 0x5555
2.对LSI时钟分频,32分频 32khz/32=1khz 计一个数:1/1khz = 1ms
IWDG_SetPrescaler
3.设置看门狗溢出时间:重装载寄存器值
IWDG_SetReload
4.填充自动重装载值
IWDG_ReloadCounter
5.使能看门狗
IWDG_Enable
6.在程序中定时喂狗
按键喂狗:判断按键按下后调用IWDG_ReloadCounter
*/
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-1); //数2000个数,用时2s
IWDG_ReloadCounter();
//启动
IWDG_Enable();
}
#include "stm32f4xx.h"
#include "uart.h"
#include "led.h"
#include "stdio.h"
#include "timer.h"
#include "pwm.h"
#include "delay.h"
#include "iwdg.h"
int main(void)
{
//2号分组:2bit给抢占 2bit给响应 0-3 0-3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
key_init();
LED0_init();
GPIO_ResetBits(GPIOF,GPIO_Pin_9); //如果复位,则灯亮
SysTick_Init(); //系统延时
//f = 84Mhz/ (83+1) / (999+1) = 1Khz
//pwm频率 = 时钟频率/(分频值+1)/(自动重装载值+1)
tim13_pwm_led0(84, 3816);
IWDG_Init_Config();
delay_ms(30);
WWDG_SetCounter(0x7f);//窗口看门狗的上限最大值是0x7F,也就是最大值是127,我们自己设置上限,取值在64-127之间,64是0x40,是寄存器内部设置的
//改变灯的状态
GPIO_ToggleBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);
}
窗口看门狗
窗口看门狗跟独立看门狗一样,也是一个递减 计数器不断的往下递减计数,当减到一个固定值0X40 时还不喂狗的话,产生复位,这个值叫窗 口的下限,是固定的值,不能改变。
这是跟独立看门狗类似的地方,不同的地方是窗口看门狗 的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值由用户 独立设置。窗口看门狗计数器的值必须在上窗口和下窗口之间才可以喂狗,这就是窗口看门狗中 窗口两个字的含义。
T[6:0]就是 WWDG_CR的低七位, W[6:0]即是 WWDG-->CFR的低七位。 T[6:0]就是窗口看门狗的计数器,而 W[6:0]则是窗口看门狗的上窗口,下窗口值是固定的( 0X40)。
当窗口看门狗的计数器在上窗口值之外被刷新,或者低于下窗口值都会产生复位。 上 窗口值 W[6: 0] 是由用户自己设定的,根据实际要求来设计窗口值,但是一定要确保 窗口值大于 0X40,否则窗口就不存在了
窗口看门狗时钟来自PCLK1,PCLK1 最大是42M,由RCC 时钟控制器开启。
计数器时钟由CK 计时器时钟经过预分频器分频得到,分频系数由配置寄存器CFR 的WDGTB[1:0] 配置。其中CK 计时器时钟=PCLK1/4096,除以4096 是手 册规定的,手册没有解释为什么(个人猜测还是为了降频)。所以计数器的时钟CNT_CK=PCLK1/4096/(2^WDGTB),这就可以算出 计数器减一个数的时间T= 1/CNT_CK = 4096 * (2^WDGTB) / PCLK1。
窗口看门狗的计数器是一个递减计数器,共有7 位,其值存在控制寄存器CR 的位6:0,即T[6:0], 当7 个位全部为1 时是0X7F,这个是最大值,当递减到T6 位变成0 时,即从0X40 变为0X3F 时候,会产生看门狗复位。这个值0X40 是看门狗能够递减到的最小值,所以计数器的值只能是: 0X40~0X7F 之间。(64~127)
当递减计数器递减到0X40 的时候,还不会马上 产生复位(再减一次就复位),如果使能了提前唤醒中断:CFR 位9 EWI 置1,则产生提前唤醒中断,如果真进入了 这个中断的话,就说明程序肯定是出问题了,那么在中断服务程序里面我们就需要做最重要的工 作,比如保存重要数据,或者报警等,这个中断我们也叫它死前中断。
窗口看门狗必须在计数器的值在一个范围内才可以喂狗,其中下窗口的值是固定的 0X40,上窗口的值可以改变,具体的由配置寄存器CFR 的位6:0 W[6:0] 设置。其值必须大于 0X40,如果小于或者等于0X40 就是失去了窗口的价值,而且也不能大于计数器的值,所以必须 得小于0X7F。
那窗口值具体要设置成多大?这个得根据我们需要监控的程序的运行时间来决定。 如果我们要监控的程序段A 运行的时间为Ta,当执行完这段程序之后就要进行喂狗,如果在窗 口时间内没有喂狗的话,那程序就肯定是出问题了。一般计数器的值TR 设置成最大0X7F,窗 口值为WR,计数器减一个数的时间为T,那么时间:(TR-WR)*T 应该稍微小于Ta 即可,这样 就能做到刚执行完程序段A 之后喂狗,起到监控的作用,这样也就可以算出WR 的值是多少。
-
计数器初始值: WWDG在启动时,计数器的初始值被设定为窗口上限值。
-
计数值递减: 计数器的数值递减,不断减小。
-
窗口上限值: 窗口上限值是一个阈值,当计数器的值大于窗口上限值时,WWDG可以产生中断。
-
可产生中断: 在窗口期内,当计数器的值大于窗口上限值时,WWDG可以产生中断。这时,系统可以执行一些预定义的中断服务程序。
-
窗口下限值,产生复位: 当计数器的值小于等于窗口下限值时,WWDG将触发复位。窗口下限值是一个临界值,如果计数器的值在窗口期内没有被重载,则会导致复位。
-
窗口期,可以喂狗: 在窗口期内,如果计数器的值大于窗口下限值(0x3F),可以通过喂狗的方式重载计数器的值,防止触发复位。
-
非窗口期,喂狗则会复位: 如果计数器的值小于等于窗口下限值,表示已经超过了窗口期,此时喂狗将无效,WWDG将触发复位。
WWDG(窗口看门狗)的框图如下:
-
时钟源: PCLK(Peripheral Clock)是来自RCC(Reset and Clock Control)时钟控制器的时钟源。不同型号的STM32芯片,其PCLK的频率可能不同,例如,F103系列是36MHz,F407系列是42MHz,F429系列是45MHz,F767系列是54MHz,H743系列是100MHz,等等。
-
分频: 时钟源通过一个固定的分频系数(4096)进入WDG预分频器(WDGTB)。
-
递减计数器(CNT): WDGTB输出的时钟进入看门狗控制寄存器(WWDG_CR),其中T0到T5是一个6位的递减计数器,T6用于判断是否处于窗口期。
-
看门狗配置寄存器(WWDG_CFR): 该寄存器用于配置WWDG的一些参数,包括窗口上限值W[6:0]和比较器(COM)。
-
看门狗控制寄存器(WWDG_CR): 包含递减计数器的当前值T0-T5,判断位T6,激活位WDGA等。
-
比较器: 当T0到T5的值大于窗口上限值W[6:0]时,比较器输出为1。
-
喂狗操作: 通过写WWDG_CR寄存器,喂狗操作即将递减计数器的当前值重新加载到W[6:0],这样可以避免复位。在窗口期内有效,可以通过该操作刷新看门狗计数。
-
判断是否复位: 复位的判断条件包括T6为0和WDGA激活位为1,同时还要判断是否在窗口期内进行了喂狗操作。如果不在窗口期内进行喂狗或者T6为0,则WWDG将触发复位。
总的来说,WWDG的工作框图涉及到时钟源的分频、递减计数器、窗口配置、比较器、喂狗操作,以及复位的判断条件。这些都是为了保证WWDG的正常工作和对程序运行的监测。 WWDG超时时间计算
最大值怎么算出来的?(了解即可)
例如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.532^6=136.5364=8.74ms。同理,当WDGTB 等于1/2/3 时,代入公式即可。
代码
#include "wwdg.h"
#include "stm32f4xx.h"
/*
1.APB1时钟使能
2.时钟分频 42MHZ
WWDG_SetPrescaler
3.设置窗口值
WWDG_SetWindowValue
4.窗口计数器使能
WWDG_Enable
5.需要定时喂狗
*/
// 上窗口前时间(127-100)*780us = 21.06ms
// 喂狗时间 (100-64)*780us = 28.08ms
void WWDG_Init_Config(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
WWDG_SetPrescaler(WWDG_Prescaler_8); //4分频, 42Mhz/ 4096 / 8 = 1281hz 计数计一个数时间为780us
//0x7f - 0x40 127-64
WWDG_SetWindowValue(100);
WWDG_Enable(0x7f);
}
#include "public.h"
int main(void)
{
//2号分组:2bit给抢占 2bit给响应 0-3 0-3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SysTick_Init();
KEY_Init();
LED_Init();
GPIO_ResetBits(GPIOF,GPIO_Pin_9); //如果复位,则灯亮
WWDG_Init_Config();
while(1)
{
Delay_ms(30);
WWDG_SetCounter(0x7f);
//改变灯的状态
GPIO_ToggleBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);
}
}
总结
独立看门狗与窗口看门狗区别如下:
(1)独立看门狗没有中断,窗口看门狗有中断。
(2)独立看门狗有硬件、软件之分,窗口看门狗只能软件控制。
(3)独立看门狗只有下限,窗口看门狗又下限和上限。
(4)独立看门狗是12位递减的。窗口看门狗是7位递减的。
(5)独立看门狗是用的内部的大约40kHz RC振荡器,窗口看门狗是用的系统时钟APB1ENR。
(6)独立看门狗Iwdg——独立于系统之外,因为有独立时钟,所以不受系统影响的系统故障探测器。
窗口看门狗wwdg——系统内部的故障探测器,时钟与系统相同。如果系统时钟不走了,这个狗也就失去作用了。主要用于监视软件错误。
(7)独立看门狗没有中断功能,窗口看门狗有中断。
独立看门狗(Independent Watchdog):适用于需要在预定时间间隔内检测系统运行状态的场景。它独立于系统其他组件工作,定期检查系统的活动状态。如果系统在设定的时间内未喂狗,独立看门狗将触发重启操作。用于检测系统死锁、无限循环等严重故障,并执行相应的恢复措施,确保系统稳定性和可靠性。
窗口看门狗(Windowed Watchdog):适用于需要在严格的时间窗口内监测系统运行状态的场景。它要求系统在指定的时间窗口内喂狗,而不仅仅是在预定时间间隔内。只有在窗口内喂狗,才能防止看门狗触发重启操作。用于实时系统或对时间敏感的应用,确保系统在严格的时间要求内正常运行,避免因执行时间超出预期而触发看门狗重启。
综合来说,当系统对时间要求较为严格,需要确保在严格的时间窗口内完成特定任务时,通常会选择窗口看门狗。而当需要独立于系统其他组件工作、定期检查系统状态,并在发生严重故障时执行恢复操作时,通常会选择独立看门狗。