IWDG和WWDG分析

关于本博文的介绍:

  1. 基于STM32F103ZET芯片和3.5V标准库
  2. 分开介绍两种模式:独立看门狗IWDG和窗口看门狗WWDG
  3. 从寄存器,介绍到对应的库函数;

一 什么是看门狗?
单片机系统在正常执行程序时,当收到外界各种物理干扰或其他原因出现程序跑飞或者陷入死循环的现象,而使得正常的程序无法正常运行,导致MCU挂掉,看门狗就是为了解决这么个问题而出现的;

二 工作原理
在一定时间内(时间由看门狗定时计数器决定)没有接收到喂狗信号(表示MCU挂了),便实现处理器自动复位重启(发出复位信号);
** IWDG和WWDG的时钟源 **
IWDG和WWDG分析_第1张图片
从图中可以看出:
1.独立看门狗IWDG有自己独立的时钟源——LSI
2. 窗口看门狗WWDG的时钟源——PCLK1
由此图可以看出:在编程时,IWDG不需要使能时钟源,而WWDG需要;所以IWDG的操作会比较简单一些;

独立看门狗定时器IWDG

一 相关寄存器以及功能
(1)键值寄存器IWDG_KR
IWDG和WWDG分析_第2张图片
功能和使用方法:

  1. 当[15:0]位被写入0xCCCC时,使能,此时寄存器从其0xFFF开始递减计数,当递减到0x0000时,会产生一个复位信号(IWDG_RESET)
  2. 当[15 : 0]位被写入0xAAAA时,IWDG_RLR寄存器中的值将会被重新加载到计数器中(这就是喂狗的过程),就是通过这个功能,从而避免产生MCU复位;
  3. 当寄存器被写入0x5555时,可以访问IWDG_PR和IWDG_RLR寄存器;(这里要注意了,这个重要,因为如果IWDG_PR和IWDG_RLR不能被写入数据,也就是相当于无法给IWDG预分频和重载值)

(2)预分频寄存器IWDG_PR
IWDG和WWDG分析_第3张图片
功能和使用:
对照着对[2:0]位的介绍选择分频因子;

(3)重载寄存器IWDG_RLR
IWDG和WWDG分析_第4张图片
功能和使用方法:看方框中吧;

(4)状态寄存器IWDG_SR
IWDG和WWDG分析_第5张图片
功能和使用方法:看方框中吧;

二 编程步骤

  1. 取消寄存器写保护(也即是先IWDG_KR中写入0x5555)
    目的:取消PR和RLR寄存器写保护,从而可以操作这两个寄存器
    库函数:
    void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);

  2. 设置预分频系数和重装载值
    库函数:
    void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);
    void IWDG_SetReload(uint16_t Reload);
    这里要明白一个重要的概念:
    Tout(ms) = ((4*2^prer) * rlr)/40;

    Tout:要设置的溢出时间,也就是多久初始化一次MCU,单位是ms
    prer :分频系数
    rlr :重载值;
    比如:prer = 4,rlr = 625时,Tout = 1000ms

  3. 重载计数值喂狗(向IWDG_KR写入0xAAAA)
    库函数:
    void IWDG_ReloadCounter(void);

  4. 启动看门狗(向IWDG_KR 写入0xCCCC)
    库函数:
    void IWDG_Enable(void);

自此,整个程序就完成了;比较简单;

窗口看门狗WWDG

“窗口”的原因:
因为喂狗的时间有一个时间上的限制,必须在一定时间范围内(窗口);这个时间范围(窗口)上限是相关寄存器配置;下限时间是0x40;在这段时间内要完成喂狗,否则将会发生MCU复位;

一 WWDG发出复位信号的条件

  1. 计数器的数值从0x40减到0x3F时候;
  2. 喂狗的时候,计数器的值大于WWDG_CFG寄存器设置的数值;

注意: 上面第二点需要特别注意,在后面进行编程的时候,我们会发现有两个喂狗函数:
1.看门狗设置计数器(喂狗)函数WWDG_SetCounter(0xXX),这是一个经常放在WWDG中断函数中的一个专门又来喂狗的函数,0XX被送往CR寄存器;
2.看门狗启动函数**WWDG_Enable(0xXX)**的这个括号里有一个0xXX值,也同样被送到CR函数执行了一次喂狗操作;
所以一定要注意一个原则:这两个函数的实参都不能是大于窗口值,否则就直接发生复位了;

**二 WWDG的特点 **
当MCU受到外界干扰或者内部干扰时候,导致程序出现跑飞或者死循环现象的时候,有一种情况是:程序在死循环的时候同时执行了喂狗程序,这就尴尬了,看门狗就无法起到了作用;
如果使用窗口看门狗,程序员可以根据程序执行的时间设置刷新看门狗的一个时间窗口,保证不会提前刷新看门狗或滞后刷新看门狗,这样可以检测出程序有没有正常的执行程序;

三 相关寄存器功能
先总结一下:
控制寄存器——WWDG_CR——使能WWDG,WWDG倒计数计时器;
配置寄存器——WWDG_CFG——设置唤醒中断标志位,设置分频因子,设置上窗口的值;
状态寄存器——WWDG_SR——唤醒中断位中断标志;

  1. 控制寄存器WWDG_CR
    IWDG和WWDG分析_第6张图片
    功能和使用:
    [7]:WWDG功能的开关位;
    [6:0] : 1. 这7位的值为要递减的值;
    2. 喂狗就是要对这7位赋值(赋值的时候绝对不能大于窗口值);
    3. 这几个位所能承受的最大值0x7F,最小值是0x40;

2.配置寄存器WWDG_CFG
IWDG和WWDG分析_第7张图片
[9] : EWI提前唤醒中断,说白了此位置1会开启WWDG中断,调用相应中断相应函数;
[8:7]:设置分频因子;经过此处分频后,即可得到CR寄存器中的递减周期;
[6:0]:窗口值,是可以喂狗和不可以喂狗的临界点,当此处的值大于计数器的值时方可喂狗,否则不可喂狗;

3.状态寄存器WWDG_SR
IWDG和WWDG分析_第8张图片
当EWIF位被置1,说明程序正在执行中断函数或并没有开启WWDG中断

四 窗口看门狗WWDG关于周期的计算:
《STM32f103使用手册》中给出了下面这个超时公式,但是我觉得实在是有些无厘头的计算,为什么要给一个T[5:0]的计算,并且我也没搞懂所谓的超时公式这个“超时”到底超的是谁;所以我觉得要正确的配置窗口值和喂狗的值只要对计数器T[6:0]的递减周期足够理解就好了;
在这里插入图片描述
所以我总结如下:
一,计数器T[6:0]的递减周期:T1 = (4096*2^WDGTB)/PCLK1;
PCLK1:APB1上的时钟频率,在库函数提供的默认配置下,PCLK1默认为36MHz;
WDGTB:分频系数(1,2,4,8);
二,在配置窗口值,喂狗值时要遵循的规则:

0x7F >= 窗口值 >= 喂狗值 >=0x41; 超时时间范围:(图片下方用我总结的计数器递减周期公式计算一下怎么得到的下边的这个表格) ![这里写图片描述](https://img-blog.csdn.net/20170526101137239?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3V5dXp1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 例如:当配置将使WDGTB=2^3时,PCLK1=36MHz时,可得递减周期约为910us,然而我们又知道T[6:0]的最大值为0x7f,最小值为0x40,则(0x7f - 0x3f)=0x40=64(十进制),即 64*910=58240us=58.240≈58.25ms;当窗口值和喂狗值同时设置为0x41时,中断周期就是910us,为0x7f时,中断周期就是58.25ms;所以当WDGTB=8时,中断周期就可以认为的在910us~58.25ms中间设定;事实就是这样;

编程思路
IWDG和WWDG分析_第9张图片

五 编程步骤

一定要切记这个步骤,不然因为对EWIF位的不理解导致错误

(1) 开启WWDG时钟

 RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);

(2)设置窗口值和分频系数值(配置WWDG_CFG)

void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);//设置分频因子
   void WWDG_SetWindowValue(uint8_t WindowValue);//设置窗口值

(3)使能WWDG,并加载初值

void WWDG_Enable(uint8_t Counter);

这里需要特别注意:如果说Counter的值为0x7F(MAX),会使得WWDG_SR寄存器中的EWIF位(提醒中断标志位)。
(4)配置WWDG的中断NVIC
(5)开启WWDG中断并清除提醒中断标志位EWIF;

 void WWDG_EnableIT(void);    /
 void WWDG_ClearFlag(void);    //WWDG_SR的EWIF清零,如果不清零会使得程序无法进入到WWDG中断函数;

(6)中断函数

void WWDG_IRQHandler(void)
{
	if(WWDG_GetFlagStatus())
	{
			WWDG_SetCounter(喂狗值); 
		//逻辑代码;
	}
	WWDG_ClearFlag();
}

IWDG和WWDG的区别;

  1. 从编程的角度来说,IWDG没有相应的中断函数,而WWDG有相应的中断函数,所以如果想完成喂狗操作,IWDG只能是通过main函数里的循环执行达到喂狗的操作,而WWDG可以通过在中断函数内执行喂狗程序;也因此,在使用WWDG是要配置相应的NVIC,而IWDG不用;

你可能感兴趣的:(stm32)