WWDG---窗口看门狗

一、窗口看门狗简介

    独立看门狗(宠物狗);窗口看门狗(警犬)。

    工作原理:

WWDG---窗口看门狗_第1张图片

二、功能框图

WWDG---窗口看门狗_第2张图片

    (1)窗口看门狗时钟

            窗口看门狗时钟来自PCLK1,PCLK1最大是42MHz,由RCC时钟控制器开启。

    (2)计数器时钟

            1、CNT_CLK = CK_CLK / ( 2^WDGTB )

            2、CK_CLK = PCLK1 / 4096

    (3)计数器

            窗口看门狗的计数器是一个7位的递减计数器,当7个位全为1时是0x7F,这个是最大值。当从0x40变为0x3F时,会产生看门狗复位。这个值0x40是看门狗能够递减到的最小值,所以计数器的值只能是:0x40 ~ 0x7F之间。

    (4)窗口值

            窗口看门狗必须在计数器的值在一个范围内才可以喂狗,其中下窗口的值是固定的0x40,上窗口的值可以改变(必须大于0x40,小于0x7F)。窗口值具体要设置成过大,需要根据监控的程序的运行时间来决定。如果要监控的程序段A运行的时间为Ta,当执行完这段程序之后就要进行喂狗,如果在窗口时间内没有喂狗的话,那程序就肯定是出问题了。一般计数器的值TR设置成最大0x7F,窗口值为WR,计数器减一个数的时间为T,那么时间:(TR - WR)* T应该稍微大于Ta即可,这样就能做到当执行完程序段A之后喂狗,起到监控的作用,这样也就可以算出WR的值是多少。

三、计算窗口看门狗的超时时间

WWDG---窗口看门狗_第3张图片

四、常用固件库函数

    (1)设置预分频器的值

            void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);

            参数:

                    WWDG_Prescaler_1
                    WWDG_Prescaler_2
                    WWDG_Prescaler_4
                    WWDG_Prescaler_8               

    (2)设置上窗口的值

            void WWDG_SetWindowValue(uint8_t WindowValue);

            参数:

                    小于0x80

    (3)设置计数器的值,使能WWDG

            void WWDG_Enable(uint8_t Counter);

            参数:

                    0x40 ~ 0x7F 

    (4)清除提前唤醒中断标志位

            void WWDG_ClearFlag(void);

    (5)打开WWDG中断

            void WWDG_EnableIT(void);

    (6)刷新递减计数器的值,即喂狗

            void WWDG_SetCounter(uint8_t Counter);

            参数:

                     0x40 ~ 0x7F 

    (7)获取状态标志位

            FlagStatus WWDG_GetFlagStatus(void);

五、程序

bsp_wwdg.h文件

#ifndef __BSP_WWDG_H__
#define __BSP_WWDG_H__


#include "stm32f4xx_conf.h"

extern void WWDG_Feed(void);
extern void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv);

#endif
 

bsp_wwdg.c文件

#include "./wwdg/bsp_wwdg.h"
#include "./led/bsp_led.h"

//用于记录看门狗 递减计数器的值,方便喂狗函数直接使用
static uint8_t wwdg_cnt;

/* WWDG 配置函数
 * tr :递减计时器的值, 取值范围为:0x7f~0x40,超出范围会直接复位
 * wr :窗口值,取值范围为:0x7f~0x40
 * prv:预分频器值,取值可以是
     *      @arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1(42MHz)/4096)/1  约10253Hz 97us
     *      @arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1(42MHz)/4096)/2     约5126Hz    195us
     *      @arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1(42MHz)/4096)/4     约2563Hz    390us
     *      @arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1(42MHz)/4096)/8  约1281Hz    780us
     *      
     *            例:tr = 127(0x7f,tr的最大值)  wr = 80(0x50, 0x40为最小wr最小值)  prv =  WWDG_Prescaler_8
     *            ~780 * (127-80) = 36.6ms < 刷新窗口 < ~780 * 64(127-0x40+1) = 49.9ms
     *            也就是说调用WWDG_Config进行这样的配置,若在之后的36.6ms前喂狗,系统会复位,在49.9ms后没有喂狗,系统也会复位。
     *            需要在刷新窗口的时间内喂狗,系统才不会复位。    
 */
void WWDG_Config(uint8_t tr,uint8_t wr,uint32_t prv)
{
    NVIC_InitTypeDef nvicInitValue;
    
    wwdg_cnt = tr; //保存CNT配置,用在喂狗
    
    /*1、打开WWDG时钟*/
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);
    
    /*2、设置预分频器的值*/
    WWDG_SetPrescaler(prv);
    
    /*3、设置上窗口值*/
    WWDG_SetWindowValue(wr);
    
    /*4、设置计数器的值,使能WWDG*/
    WWDG_Enable(tr);
    
    /*5、清除提前唤醒中断标志位*/
    WWDG_ClearFlag();
    
    /*6、配置NVIC*/
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    nvicInitValue.NVIC_IRQChannel = WWDG_IRQn;
    nvicInitValue.NVIC_IRQChannelCmd = ENABLE;
    nvicInitValue.NVIC_IRQChannelPreemptionPriority = 1;
    nvicInitValue.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&nvicInitValue);
    
    /*7、打开WWDG中断*/
    WWDG_EnableIT();
    
}

// 喂狗
void WWDG_Feed(void)
{
    // 喂狗,刷新递减计数器的值,设置成最大WDG_CNT=0X7F
    WWDG_SetCounter( wwdg_cnt );
}


// WWDG 中断复服务程序,如果发生了此中断,表示程序已经出现了故障,
// 这是一个死前中断。在此中断服务程序中应该干最重要的事,
// 比如保存重要的数据等,这个时间具体有多长,要
// 由 WDGTB 的值决定:
// WDGTB:0 97us   (PCLK1(42MHz)/4096)/1 约10253Hz 97us
// WDGTB:1 195us  (PCLK1(42MHz)/4096)/2 约5126Hz    195us
// WDGTB:2 390us  (PCLK1(42MHz)/4096)/4 约2563Hz    390us
// WDGTB:3 780us  (PCLK1(42MHz)/4096)/8 约1281Hz    780us
void WWDG_IRQHandler(void)
{
    // 清除中断标志位
    WWDG_ClearFlag();

    //LED2 亮,点亮 LED 只是示意性的操作,
    //真正使用的时候,这里应该是做最重要的事情
    LED_ON(2);
}

main.c文件

#include "./usart/bsp_usart.h"
#include "./led/bsp_led.h"
#include "./wwdg/bsp_wwdg.h"
#include "stdio.h"

static void Delay(__IO uint32_t nCount)     //简单的延时函数
{
    for(; nCount != 0; nCount--);
}


int main(void)
{
    uint8_t wwdg_tr, wwdg_wr;
    
    /* LED 端口初始化 */
    LED_Config();
  
    // LED3亮
    LED_ON(3);
    Delay(0XFFFFFF);    
    
/* WWDG 配置函数
 * tr :递减计时器的值, 取值范围为:0x7f~0x40,超出范围会直接复位
 * wr :窗口值,取值范围为:0x7f~0x40
 * prv:预分频器值,取值可以是
     *      @arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1(42MHz)/4096)/1  
     *      约10253Hz 97us
     *      @arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1(42MHz)/4096)/2     
     *      约5126Hz    195us
     *      @arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1(42MHz)/4096)/4     
     *      约2563Hz    390us
     *      @arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1(42MHz)/4096)/8  
     *      约1281Hz    780us
     *      
     *            例:tr = 127(0x7f,tr的最大值)  
     *          wr = 80(0x50, 0x40为最小wr最小值)  
     *          prv =  WWDG_Prescaler_8    ,这时计数器计一次的时间为780us             
                则有:780 * (127-80) = 36.6ms < 刷新窗口 < ~780 * 64(127-0x40+1) = 49.9ms
     *            也就是说调用WWDG_Config进行这样的配置,若在启动wwdg之后的36.6ms前喂狗,系统会复位,
     *      在49.9ms后没有喂狗,系统也会复位。
     *            需要在刷新窗口的时间内喂狗,系统才不会复位。    
*/    
    // 初始化WWDG:配置计数器初始值,配置上窗口值,启动WWDG,使能提前唤醒中断
    WWDG_Config(127,80,WWDG_Prescaler_8);    
    
    // 窗口值我们在初始化的时候设置成0X50,这个值不会改变
    wwdg_wr = WWDG->CFR & 0X7F;
    
    while(1)
    {    
        // LED3灭
        LED_OFF(3);
        //-----------------------------------------------------
        // 这部分应该写需要被WWDG监控的程序,这段程序运行的时间
        // 决定了窗口值应该设置成多大。
        //-----------------------------------------------------
        
        // 计时器值,初始化成最大0X7F,当开启WWDG时候,这个值会不断减小
        // 当计数器的值大于窗口值时喂狗的话,会复位,当计数器减少到0X40
        // 还没有喂狗的话就非常非常危险了,计数器再减一次到了0X3F时就复位
        // 所以要当计数器的值在窗口值和0X40之间的时候喂狗,其中0X40是固定的。
        wwdg_tr = WWDG->CR & 0X7F;
        
        if( wwdg_tr < wwdg_wr )
        {
            // 喂狗,重新设置计数器的值为最大0X7F
            WWDG_Feed();
        }
    }
}

你可能感兴趣的:(STM32)