赞
踩
目录
窗口看门狗通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在T6位变为0前被刷新,否则看门狗电路在达到预置的时间周期时,会产生一个MCU复位。如果在递减计数器达到窗口寄存器值之前刷新控制寄存器的7位递减计数器值,也会产生MCU复位。这意味着必须在限定的时间窗口内刷新计数器。
之所以称为窗口,是因为其喂狗时间是一个有上下限的范围内(窗口),可以通过设定相关寄存器,设定其上限时间(下限固定)。喂狗时间不能过早也不能过晚。
为什么需要窗口看门狗呢?独立看门狗是在0~重载值之间任何时间段都可以喂狗,如果在这个时间段程序死循环结束,或者说程序跑飞之后又跑回正常,这时候恰好又刷新了看门狗,这种情况下独立看门狗是检测不到复位芯片的;但是窗口看门狗不同,严格限时了喂狗的时间,即使程序跑飞又跑回正常,只要不在限定的时间窗口内,MCU都会产生复位。
独立看门狗和窗口看门狗同属于STM32的看门狗外设,具有安全性高、定时准确及使用灵活的优点。两个看门狗外设均可用于检测并解决由软件错误导致的故障。但是:
1. 独立看门狗IWDG由其专用的低速时钟LSI驱动,因此即便在主时钟发生故障时仍然可以保持工作状态。
窗口看门狗WWDG时钟由APB1时钟经预分频后提供,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。
2. IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。
WWDG最适合那些要求看门狗在精确计时窗口起作用的应用程序。
3. 也是两者最重要的区别:独立看门狗IWDG是在定时器减为0这个时间段之中喂狗,就不会产生复位;而窗口看门狗需要在定时器减到0x3F这个时间段内喂狗才不会产生复位,在其他时间均会产生复位。
1. 可编程的自由运行递减计数器 //给定一个时间段,由计数器来完成
2. 复位条件
当递减计数器值小于0x40时复位;(如果看门狗已激活) //在计数器的值到0x3F之间喂狗才不会复位,相比于独立看门狗更加严格
在窗口之外重载递减计数器时复位;(如果看门狗已激活) //还是在强调一点:只有在计数器的值递减到0x3F之间才不会复位,其余任何时间哪怕是无限喂狗也会复位,窗口之外指的就是在计数器的值递减到0X3F这个过程之外。也可以说喂狗时间大于了窗口的上限值。
3. 提前唤醒中断(EWI):当递减计数器等于0x40时触发(如果已使能且看门狗已激活) //特殊功能:计数器的值等于0x40时触发中断,该中断可以用来提醒喂狗,并且执行其他功能;但是需要注意:如果有其他优先级更高的中断执行,那么看门狗将执行复位。
使能看门狗:在系统复位后,看门狗总是处于关闭状态。可通过设置WWDG_CR寄存器中的WDGA位来使能看门狗,之后除非执行复位操作,否则不能再次关闭。使能看门狗也就是激活看门狗,将WWDG_CR寄存器的WDGA位置1;
控制递减计数器:递减计数器处于一个自由运行的状态,这个时候即使是禁止了看门狗,递减计数器仍然继续递减计数。当使能看门狗时,必须将T6位置1,以防止立即复位;
该意思就是:递减计数器和是否禁止看门狗无关。
必须将T6位置1,防止其立即复位; 是因为T6计数器是一个7位计数器,100 0000 -> 000 0000,通过上述框图已经解释了,当第6位从高电平1滚动到低电平时,就会发生复位;开启看门狗以后,立刻将第6位置1,防止一开启第6位就从1 变为 0;产生复位。
T[5:0]也就是计数器的前6位包含了看门狗复位之前的计时数目;这是因为第7位一旦从1变为0,就会产生复位信号。
配置寄存器WWDG_CFR包含窗口的上限:为防止发生复位,当递减计数器的值低于窗口寄存器且大于0x3F时必须重载。根据上述的框图,我们已经明白了当递减计数器大于窗口寄存器时,就会发生复位。所以说当还未产生复位,且大于0x3F这个极限值时,就必须进行重载,否则就会离开窗口期,产生复位(这个过程也称作窗口狗喂狗)。
因为T6位的特殊性,同样可以借助软件复位;(将WDGA位置1 激活看门狗,将T6位清0)
看门狗中断高级特性:计数器的值等于0X40时触发中断EWI,此中断是窗口看门狗独特的一种特性。与其说是窗口看门狗的高级特性,不妨通俗的说是一种自我提醒,更高级的自救方法。
之所以这么讲,是因为在计数器值为0x40时使用EWI中断,不仅仅可以用来管理软件系统检查/或系统恢复/功能退化,也可以使用相应的中断服务程序ISR来重载WWDG计数器以避免WWDG复位。通过设置WWDG_CFR配置寄存器中EWI位来使能EWI中断。当递减计数器的值为0x40时,将生成EWI中断。通过将0写入WWDG_SR状态寄存器中的EWIF位来清除EWI中断。
注意:当更高级的中断优先级的任务中有系统锁定而无法使用EWI中断时,最终会产生WWDG复位。
超时值的计算公式:
其中:
t WWDG:WWDG超时;
t PCLK1:APB1时钟周期,以ms为测量单位;
控制寄存器 WWDG_CR(Status register) 32位寄存器
位31:8 保留,必须保持复位值。
位7 WDGA 激活看门狗
此位由软件置1,只有复位后才由硬件清零。当WDGA=1时,看门狗可以产生复位。
0:禁止看门狗
1:使能看门狗
位6:0 T[6:0]:7位计数器
这些位可用来存储看门狗计数器的值。当它从0x40滚动到0x3F(T6清零)时会产生复位。(这里并不是说只有 0x40 到 0x3F 的这个过程)
配置寄存器 WWDG_CFR(Configuration register) 32位寄存器
位31:10 保留,必须保持复位值。
位9:EWI:提前唤醒中断
置1后,只要计数器值达到0x40就会产生中断。此中断只有在复位后才由硬件清零。提醒我们需要进行喂狗了。
位8:7 WDGTB[1:0]:定时器时基
00:CK计数器时钟分频器1
01:CK计数器时钟分频器2
10:CK计数器时钟分频器4
11:CK计数器时钟分频器8
位6:0 W[6:0]:7位窗口值
这些位包含用于与递减计数器进行比较的窗口值。
状态寄存器 WWDG_SR(Status register) 32位寄存器
位31:1 保留,必须保持复位值。
位0 EWIF:提前唤醒中断标志 用来标志中断是否开启的状态标志位
当计数器值达到0x40时此位由硬件置1。他必须由软件通过写入0来清零。写入1不起作用。如果不使能中断,此位也会被置1;
FlagStatus WWDG_GetFlagStatus(void); //获取状态位
void WWDG_ClearFlag(void); //提前清除唤醒中断标志位
注意:上窗口值 W[6:0]是由用户自己设定的,根据实际要求来设计窗口值,但是一定要确保窗口值大于0x40,否则窗口就不存在了。这应该很好理解。上限不大于下限,成负空间了。
1. 使能WWDG时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG时钟使能
WWDG不同于IWDG,IWDG有自己独立的32Khz时钟,不存在使能问题。WWDG使用的是PCLK1的时钟,需要先使能时钟。
2. 设置窗口值和分频数
void WWDG_SetWindowValue(uint8_t WindowValue); //设置上窗口值函数
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler); //设置分频数函数
3. 开启WWDG中断并分组
WWDG_EnableIT(); //开启窗口看门狗中断 (开启提前唤醒中断)
紧接着需要进行中断优先级配置,使用NVIC_Init();函数
4. 设置计数器初始值并使能看门狗
void WWDG_Enable(uint8_t Counter); //该函数既设置了计数器初始值,同时也使能了窗口看门狗
void WWDG_SetCounter(uint8_t Counter); //该函数只用来设置计数器的值(也就是喂狗操作)
5. 编写中断服务函数
void WWDG_IQRHandler(); //中断服务函数,通过该函数来喂狗,喂狗要快;
在中断服务函数中也要将状态寄存器的EWIF位清空。WWDG_ClearFlag(); //提前清除唤醒中断标志位
本实验程序将用来检测窗口看门狗:
LED0指示STM32F4是否被复位了,如果被复位LED就会点亮300ms。LED1用来指示中断喂狗,每次中断喂狗翻转一次。
- #include "stm32f4xx.h"
- #include "delay.h"
- #include "LED.h"
- #include "BEEP.h"
- #include "Key.h"
- #include "usart.h"
- #include "exti.h"
- #include "iwdg.h"
- #include "wwdg.h"
-
- int main()
- {
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置系统中断优先级分组为2
- LED_Init();//初始化LED
- delay_init(168); //初始化延迟函数
- LED0=0;//LED0点亮
- delay_ms(300); //延迟300ms,方便肉眼观看到灯亮灭
- WWDG_Init(0x7F,0x5F,WWDG_Prescaler_8); //初始化看门狗
- //计数器设置为0x7F,窗口值为0x5F,分频数为8
- //也就是从0x7F开始递减,0111 1111
- //0101 1111->0011 1111 为窗口的上下限
- while(1)
- {
- LED0=1; //一旦进入while循环中,表示窗口看门狗初始化完成,LED0熄灭作为初始化完成的标志
- }
- }
-
- #include "stm32f4xx.h"
- #include "wwdg.h"
- #include "LED.h"
-
- unsigned char WWDG_CNT=0x7F;//全局变量 保存最初设置的计数器的值
-
- void WWDG_Init(unsigned char tr,unsigned char wr,u32 fprer)
- //tr:计数器的值 wr:配置寄存器窗口值 fprer:分频系数 WDGTB 配置寄存器的7 8位控制
- {
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);//使能WWDG时钟
- WWDG_CNT=tr&WWDG_CNT;//初始化WWDG_CNT,之所以要拿tr&WWDG_CNT,是因为全局变量WWDG_CNT=0x7F是一个8位的,
- //而我们的定时器是7位,第七位还是一个激活/禁止的状态位,精确来说是拿出低7位,所以用tr&0x7F拿出低七位赋值给WWDG_CNT
- WWDG_SetWindowValue(wr);//设置窗口值
- WWDG_SetPrescaler(fprer);//设置预分频值
- WWDG_SetCounter(WWDG_CNT);//设置计数器的值
- WWDG_Enable(WWDG_CNT);//开启看门狗
-
- NVIC_InitTypeDef NVIC_InitStructure;//设置NVIC中断优先级结构体变量
- NVIC_InitStructure.NVIC_IRQChannel=WWDG_IRQn;//窗口看门狗中断
- NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能窗口看门狗
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0X02;//抢占优先级2
- NVIC_InitStructure.NVIC_IRQChannelSubPriority=0X03;//响应优先级3
- NVIC_Init(&NVIC_InitStructure);//初始化NVIC
-
- WWDG_ClearFlag();//清除提前唤醒中断标志位 开启中断之前清除中断标志位
- WWDG_EnableIT();//开启看门狗中断
- }
-
- void WWDG_IRQHandler(void)//看门狗中断服务函数,运行到中断就表示定时器已经到0x40了,必须喂狗
- {
- WWDG_SetCounter(WWDG_CNT);//设置看门狗计数器值 设置计数器值的过程就是喂狗,定时器到0x40就会进入中断服务函数,我们知道计数器从0x40到0x3F,MCU就会复位,所以在0x40这个极限值就必须要喂狗
- //将计数器的值重新设置为计数器最初的值,重新从最初的值开始递减;等同于喂狗;
- WWDG_ClearFlag();//清除提前唤醒中断标志位
- LED1=!LED1;//LED1闪烁
- }
-
- #ifndef _WWDG__H_
- #define _WWDG__H_
-
-
- void WWDG_Init(unsigned char tr,unsigned char wr,u32 fprer);
- void WWDG_IRQHandler(void);
- #endif
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。