在嵌入式系统中,由于MCU的工作常常受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统陷入停滞状态,发送不可预料的后果,所以出于对单片机运行状态实时监测的考虑,便产生了一种专门用于检测程序运行状态的模块,俗称“看门狗(watchdog)”;
在系统运行以后就启动了看门狗的计数器,看门狗就开始自动计数,如果到了一定的时间还不去清看门狗,那么看门狗计数器就会溢出从而引起看门狗中断,造成系统复位。所以在使用看门狗的时候要注意清除看门狗;
看门狗是恢复系统的正常运行及有效的监视管理器(具有锁定光驱,锁定任何指定程序的作用,可用在家庭中防止小孩无节制地玩游戏,上网等)具有很好的应用价值;
独立看门狗:(使用的是独立时钟)
IWDG由专用的32KHZ的低速时钟来驱动;因此,即使主时钟发生故障它仍然有效。IWDG最适合应用于那些需要看门狗做为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合;
重要寄存器:
键值寄存器(IWDG_KR):与喂狗、允许访问IWDG_PRIWDG_RLR寄存器、启动看门狗相关
预分频寄存器(IWDG_PR):设置分频值
重装载寄存器(IWDG_RLR):
状态寄存器(IWDG_SR)
操作步骤:(将独立看门狗使能、开启)
1、向IWDG_KR写入0x5555.
通过这部,我们取消IWDG_PR和IWDG_RLR的写保护,使后面可以操作这两个寄存器。设置IWDG_PR和IWDG_RLR的值;
这两步设置看门狗的分频系数,和重装载的值。由此,就可以知道看门狗的喂狗时间,该事件的计算方式:Tout = 40khz/(4×2^rlr)当然这个值是粗略的计算值,因为时钟不准确,所以无法得到准确的喂狗时间;
2、向IWDG_KR写入0xAAAA
通过这句,将使stm32重新加载IWDG_RLR的值到看门狗计数器里面,也是用该命令来喂狗。
3、向IWDG_KR写入0XCCCC
通过这句,启动看门狗;
通过上面3步,我们启动了stm32的看门狗,使能了看门狗,在程序里面就必须间隔一定时间来喂狗,否则将导致程序复位。
配置实例:
1 void IWDG_Configuration(void) 2 { 3 //使能对寄存器IWDG_PR和IWDG_RLR的写操作 4 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); 5 //设置IWDG预分频值256: 6 //40K/256 = 156HZ(6.4ms) 5s/6.4ms=781; 7 IWDG_SetPrescaler(IWDG_Prescaler_256); 8 9 //设置IWDG重装载值,要小于0xfff(因为寄存器是12位的) 10 IWDG_SetReload(781); 11 //按照IWDG重装载寄存器的值 重新载入IWDG计数值; 12 IWDG_ReloadCounter(); 13 IWDG_Enable(); //使能IWDG 14 }
窗口看门狗:
windowWD由APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的行为。WWDG最适合那些要求看门狗在精确计时窗口起作用的应用程序;
窗口看门狗通常被用来检测由外部干扰或不可预见的逻辑条件造成的应用程序背离正的运行序列而产生的软件故障;除非递减计数器的值在T6位(第6位)变成0前被刷新,此看门狗电路在达到可编程的时间周期时,会产生一个MCU复位。在递减计数器达到窗口寄存器之前,如果递减计数器值的第7位(在控制寄存器中)被刷新,那么也将产生一个MCU复位。这表明递减计数器需要一个有限的窗口中被刷新;
T6即窗口看门狗的自减计数器的第六位(最高位),该计数器的时钟来源于PCLK/4096/预设分频数。在该计数器的T6变为0后(小于0X40, 100 0000)就会引发复位。这个窗口的下限。而当计数器的值在大于窗口寄存器的窗口值之前就被修改的话,也会引发一场复位,这个窗口值的上限,窗口值是由用户自己设定的,根据实际要求要设计窗口值,但一定要确保窗口值大于0X40,否则窗口就不存在了;
计算超时的公式如下:
Twwdg = Tpclk1×4096×2^WDTB×(T[5:0]+1); (ms)
其中:
Twwdg:WWDG超时时间 WDTB:寄存器配置的值,可取:0、1、2、3
Tpclk1:APB1以ms位单位的时钟间隔;一般是确定的,为36Mhz;
控制寄存器:WWDG_CR 低8位有效,T[6:0]用来存储看门狗的计数值,随时间更新的;每个PCLK1周期减1.当该计数器的值从0X40变为0X3F的时候,将产生看门狗复位;(这个是喂狗太晚了,已经减到了下限)
WDGA位则是看门狗的激活位,该位由软件置1,以启动看门狗,并且一定注意该位一旦设置,就只能在硬件复位后才能清零了;
配置寄存器:WWDG_CFR:低10位有效,
低7位设置的是复位最早值W(这个是窗口上限);
第8,9位是:时基,可取00,01、10、11
第10位是提前唤醒中断;
操作步骤:
1、使能WWDG时钟
WWDG不同于IWDG,IWDG有自己独立的40khz的时钟,不存在使能问题。而WWDG使用的是PCLK1的时钟,需要先使能时钟;
2、设置WWDG_CFR和WWDG_CR寄存器
在时钟使能完后,我们设置WWDG的CFR和CR两个寄存器,对WWDG进行配置。包括使能窗口看门狗、开启中断、设置计数器初始值T、设置窗口值并设置分频数WDGTB等;
3、开启WWDG中断并分组
在设置完WWDG后,需要配置该中断的分组及使能;
4、编写中断服务函数
若没有在规定时间段内喂狗,就引起软件复位。在中断服务函数里将状态寄存器的EWIF位清空;
如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI) ,它可以被用于重装载计数器以避免WWDG复位。
1 void WWDG_Configuration(void) 2 { 3 //使能APB1外设WWDG时钟 4 RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE); 5 6 //看门狗节拍=(36/4096)/8 = 1098hz 略等1ms 7 WWDG_SetPerscaler(WWDG_Prescaler_8); 8 //窗口上限值为0x45 9 WWDG_SetWindowValue(0x45); 10 //看门狗使能并初始化定时器为0x7f 11 //计数器一直随时间递减; 12 //减到0x45到0x40之间必须喂狗(重新载入初值) 13 //否则复位, 14 WWDG_Enable(0x7f); 15 //clear EWI flag 16 WWDG_ClearFlag(); 17 //Enable EWI interrupt 18 WWDG_Enable(); 19 20 }