STM32窗口看门狗共三个寄存器,如下图:
看似简单,但设置及应用起来有不少玄机。
控制寄存器(WWDG_CR)中的值必须在0xFF与0xC0之间, 因为它的第0至第6位为递减计数器CNT,在它的第6位变为0时将产生复位,所以在初始化时需要为1,第7位WDGA是用来设置启动或禁止窗口看门狗的,当为1进才会启动窗口看门狗,所以第6和第7位都需为1,即WWDG_CR 的值需要大于等于0xC0 。
配置寄存器(WWDG_CFR) 第0至第6位 是设置窗口边界值用的,只有当递减计数器CNT的值小于边界值时才可以喂狗,过早不行,狗还不饿,撑死了。并且7位递减计数器CNT减少到0x3F时即T6位变为0,此时MCU也会复位,过晚了,狗饿死了。所以必须在指定的时间范围喂狗,过早或过晚都将产生复位,而这样设计可以减少软件跑飞了却仍能够歪打正着地喂狗的发生概率。
状态寄存器(WWDG_CFR) 只用到了第0位,EWIF(Early wakeup interrupt flag )是提前唤醒中断标识,当递减计数器CNT的值到达0X40(若再减少一次则T6位变为0,产生复位)时此位由硬件置1,且需用软件清0,注意无论中断是否使能此位都会被硬件置1。而提前唤醒中断使能设置是在配置寄存器(WWDG_CFR)第9位EWI(Early wakeup interrupt),此位需由软件置1,则会在当递减计数器CNT的值到达0X40时产生中断,并且与EWIF不同,此位是由硬件清0。
另外控制寄存器(WWDG_CR)中第7位WDGA(Activation bit)激活位,需用软件来置1,以启动窗口看门狗,并且一旦启动后,只能在复位或重启后由硬件来清0。配置寄存器(WWDG_CFR)的第8位和第7位WDGTB[1:0]用来设置时基(Timer base)预分频数。
以上描述可参考下图以更清晰的理解:
窗口看门狗应用时还要注意算准最小与最大喂狗时间,以便正确地喂狗,如下:
在PCLK1频率为36MHz 时,则
上窗口时间:T_min = 4096 * (2^WDGTB)*(WWDG_CR[6:0] - WWDG_CFR[6:0])/36 (us)
下窗口时间: T_max = 4096 * (2^WDGTB)*(WWDG_CR[6:0] - 0x40)/36 (us) 。
喂狗动作需在这段时间之间进行,而喂狗动作为向控制寄存器(WWDG_CR)中写值,值的范围上文已经说过。
窗口看门狗中断函数void WWDG_IRQHandler(void);是用来做什么的呢。窗口看门狗中断函数是在递减计数器减少到0x40是被调用,因为它本身计数就比较慢,所以离数到0x3F复位还有一段时间,我认为这样设计是为MCU复位之前留下一点时间,能够使工程设计人员根据需要在中断函数保存一些重要的数据,这样在复位后MCU可知道系统因异常复位的某此状态,以使系统有更高稳定性。
并且我觉得在窗口看门狗中断函数中喂狗没有什么意义,程序本来已经不按正常运行了,还在中断函数中喂狗防止复位只会错上加错,不好好利用它干点正事, 更是浪费资源。
这点上我个人认为不要被点原子示例代码误导哦,但其还是有部分借鉴意义的,以下为初始化相关代码:
//窗口看门狗中断服务设置程序
void WWDG_NVIC_Init() { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //WWDG 中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占2 子优先级3 组2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //抢占2,子优先级3,组2 NVIC_Init(&NVIC_InitStructure); //NVIC 初始化 }
//保存WWDG 计数器的设置值,默认为最大.
u8 WWDG_CNT=0x7f;
//初始化窗口看门狗 //tr :T[6:0],计数器值 //wr :W[6:0],窗口值 //fprer:分频系数(WDGTB ),仅最低2 位有效 //Fwwdg=PCLK1/(4096*2^fprer). void WWDG_Init(u8 tr,u8 wr,u32 fprer) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG 时钟使能 WWDG_CNT=tr&WWDG_CNT; //初始化WWDG_CNT. WWDG_SetPrescaler(fprer); //设置IWDG 预分频值 WWDG_SetWindowValue(wr); //设置窗口值 WWDG_Enable(WWDG_CNT); //使能看门狗,设置counter WWDG_ClearFlag(); //清除提前唤醒中断标志位 (注:若没有此句则会在初始化后先进入中断一次) WWDG_NVIC_Init(); //初始化窗口看门狗NVIC WWDG_EnableIT(); //开启窗口看门狗中断 }
以上代码朋友们也可以跳到库函数代码中自己研究下,另外要说明下的是WWDG_EnableIT(); 函数相关代码
#define CFR_EWI_BB (PERIPH_BB_BASE + (CFR_OFFSET * 32) + (EWI_BitNumber * 4))
用到位带操作,具体理解可参照《Cortex-M3权威指南》第五章的位带操作相关介绍(具体89页)。