首页 > 技术文章 > stm32-WWDG小实验

lzd626 2018-07-02 16:19 原文

WWDG的定义:

窗口看门狗是一个递减计数器不断的往下递减计数,当减到一个固定值0X40 时还不喂狗的话,产生复位,这个值叫窗口的下限,是固定的值,不能改变。这个是跟独立看门狗类似的地方,不同的地方是窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值由用户独立设置。窗口看门狗计数器的值必须在上窗口和下窗口之间才可以喂狗,这就是窗口看门狗中窗口两个字的含义。

 

IWDGWWDG的区别;

 

 

WWDG框图:

 

1. 窗口看门狗时钟

    窗口看门狗时钟来自PCLK1PCLK1 最大是36M,由RCC 时钟控制器开启。

2. 计数器时钟

    计数器时钟由CK 计时器时钟经过预分频器分频得到,分频系数由配置寄存器CFR 的 位8:7  WDGTB[1:0]配置,可以是[0,1,2,3],其中CK 计时器时钟=PCLK1/4096,除以4096是手册规定的,没有为什么。所以计数器的时钟CNT_CK=PCLK1/4096/(2^WDGTB),这就可以算出计数器减一个数的时间T= 1/CNT_CK = Tpclk1 * 4096 * (2^WDGTB)

3. 计数器

    窗口看门狗的计数器是一个递减计数器,共有7 位,其值存在控制寄存器CR 的位6:0

T[6:0],当7 个位全部为1 时是0X7F,这个是最大值,当递减到T6 位变成0 时,即从

0X40 变为0X3F 时候,会产生看门狗复位。这个值0X40 是看门狗能够递减到的最小值,所以计数器的值只能是:0X40~0X7F  之间,实际上真正用来计数的是T[5:0]。当递减计数

器递减到0X40 的时候,还不会马上产生复位,如果使能了提前唤醒中断:CFR 9 EWI

1,则产生提前唤醒中断,如果真进入了这个中断的话,就说明程序肯定是出问题了。那么在中断服务程序里面我们就需要做最重要的工作,比如保存重要数据,或者报警等,

这个中断我们也叫它死前中断。

4. 窗口值

    我们知道窗口看门狗必须在计数器的值在一个范围内才可以喂狗,其中下窗口的值是

固定的0X40,上窗口的值可以改变,具体的由配置寄存器CFR 的位6:0 W[6:0]设置。其值

必须大于0X40,如果小于或者等于0X40 就是失去了窗口的价值,而且也不能大于计数器

的值,所以必须得小于0X7F。那窗口值具体要设置成多大?这个得根据我们需要监控的程

序的运行时间来决定。如果我们要监控的程序段A 运行的时间为Ta,当执行完这段程序之

后就要进行喂狗,如果在窗口时间内没有喂狗的话,那程序就肯定是出问题了。一般计数器的值TR 设置成最大0X7F,窗口值为WR,计数器减一个数的时间为T,那么时间:(TR- WR)*T 应该稍微大于Ta  即可,这样就能做到刚执行完程序段A 之后喂狗,起到监控的作 用,这样也就可以算出WR 的值是多少。

5.计算看门狗超时时间

递减计数器有7T[6:0]  ,当位6 变为0 的时候就会产生复位,实际上有效的计数位是T[5:0],而且T6 必须先设置为1。如果T[5:0]=0时,递减计数器再减一次,就产生复位了,那这减一的时间就等于计数器的周期=1/CNT_CK = Tpclk1 * 4096 * (2^WDGTB) = 1/36 * 4096 *2^0 = 113.7us,这个就是最短的超时时间。如果T[5:0]全部装满为1,即63,当他减到0X40 变成0X3F 时,所需的时间就是最大的超时时间=113.7*2^5=113.7*64=7.2768ms。同理,当WDGTB 等于1/2/3 时,代入公式即可。

 

WWDG怎么用:

WWDG 一般被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。比如一个程序段正常运行的时间是50ms,在运行完这个段程序之后紧接着进行喂狗,如果在规定的时间窗口内还没有喂狗,那就说明我们监控的程序出故障了,跑飞了,那么就会产生系统复位,让程序重新运行。

 bsp_wwdg.h文件如下:

#ifndef __WWDG_H
#define __WWDG_H
#include "stm32f10x.h"
#define WWDG_CNT    0X7F
void WWDG_Feed(void);
void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv);
#endif

bsp_wwdg.c文件如下:

#include "bsp_wwdg.h"   

static void WWDG_NVIC_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure; 
  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 
  NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv)
{    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
    WWDG_SetCounter( tr );
    WWDG_SetPrescaler( prv );
    WWDG_SetWindowValue( wr );
    WWDG_Enable(WWDG_CNT);    
    WWDG_ClearFlag();    
    WWDG_NVIC_Config();    
    WWDG_EnableIT();
}

void WWDG_Feed(void)
{
    WWDG_SetCounter( WWDG_CNT );
}

中断处理函数:

void WWDG_IRQHandler(void)
{
    WWDG_ClearFlag();
    green(ON); 
}

main.c文件如下:

#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_key.h" 
#include "bsp_wwdg.h" 
void SOFT_Delay(__IO u32 nCount);
int main(void)
{    
    uint8_t wwdg_tr, wwdg_wr; 
    LED_GPIO_Config();
    red(ON) ;
    SOFT_Delay(0X00FFFFFF);    
    WWDG_Config(0X7F, 0X5F, WWDG_Prescaler_8);
    wwdg_wr = WWDG->CFR & 0X7F;//被下面的判断使用 
    while(1)
    {    
        red(OFF);
        wwdg_tr = WWDG->CR & 0X7F;
        
        if( wwdg_tr < wwdg_wr )
        {
            WWDG_Feed();
        }
    }
}
void SOFT_Delay(__IO u32 nCount)
{
    for(; nCount != 0; nCount--);
} 

 

推荐阅读