STM32-笔记26-WWDG窗口看门狗

一、简介

        窗口看门狗用于监测单片机程序运行时效是否精准,主要检测软件异常,一般用于需要精准检测程序运行时间的场合。        

        窗口看门狗的本质是一个能产生系统复位信号提前唤醒中断的6位计数器(有的地方说7位。其实都无所谓,本质是一样的)。

        产生复位条件:

  • 当递减计数器值从 0x40 减到 0x3F 时复位(即T6位跳变到0)
  • 计数器的值大于 W[6:0] 值时喂狗会复位。
  •         产生中断条件:

  • 当递减计数器等于 0x40 时可产生提前唤醒中断 (EWI)。
  • 在窗口期内重装载计数器的值,防止复位,也就是所谓的喂狗。

    二、WWDG工作原理及框图

     三、WWDG寄存器及函数介绍

            窗口看门狗内有一个7位的递减计数器,并可以设置成自由运行。它可以被当成看门狗用于在发生问题时复位整个系统。它由主时钟驱动,具有早期预警中断功能;在调试模式下,计数器可以被冻结。

    3.1 控制寄存器

    3.2 配置寄存器

    3.3 状态寄存器

    3.4 寄存器映像

    3.5 函数

     等……

    配置步骤

    四、WWDG溢出时间计算

    在上面的超时公式中:周期(时间 = Tpclk1) = 频率的倒数 = PCLK1(频率)

    4096 * 2^WDGTB / PCLK1  = 数一个数的时间单位是ms

    PCLK1 = 36MHZ( 常等于)

    (T[5:0]+1) = 个数

    五、看门狗实验

    5.1 实验目的

            开启窗口看门狗,计数器值设置为 0X7F ,窗口值设置为 0X5F ,预分频系数为 8 。在 while 循环里喂狗,同时翻转 LED1 状态;在提前唤醒中断服务函数进行喂狗,同时翻转 LED2 状态。

    这里设置的窗口上限值为:

    从开始计数,到记完数要复位的地方,也就是0X7F – 0X3F这段记58.25ms

    复制项目文件夹19-串口打印功能,重命名位28-WWDG窗口看门狗

    新建文件夹wwdg

    打开项目

    加载文件

    加入wwdg驱动文件

    代码:

    main.c

    #include "sys.h"
    #include "delay.h"
    #include "led.h"
    #include "uart1.h"
    #include "wwdg.h"
    
    int main(void)
    {
        HAL_Init();                         /* 初始化HAL库 */
        stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
        led_init();//初始化led灯
        uart1_init(115200);
        wwdg_init(0x7f,0x5f,WWDG_PRESCALER_8);
        printf("hello word!\r\n");
        
        if(__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET)
        {
            printf("窗口看门狗复位!\r\n");
            __HAL_RCC_CLEAR_RESET_FLAGS();
        }
        else
            printf("外部复位!\r\n");
    
        while(1)
        { 
    //        delay_ms(50);
    //        wwdg_feed();
    //        led1_Toggle();
        }
    }
    

    wwdg.c

    #include "wwdg.h"
    #include "led.h"
    
    WWDG_HandleTypeDef wwdg_handle = {0};
    
    //初始化窗口看门狗函数
    void wwdg_init(uint8_t tr,uint8_t wr,uint32_t psc)
    {
        wwdg_handle.Instance = WWDG;
        wwdg_handle.Init.Counter = tr;//计数器的值
        wwdg_handle.Init.Prescaler = psc;//预分频系数
        wwdg_handle.Init.Window = wr;//窗口上限值
        wwdg_handle.Init.EWIMode = WWDG_EWI_ENABLE;//窗口看门狗早期唤醒启用
        HAL_WWDG_Init(&wwdg_handle);
    }
    
    //msp函数初始化
    void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)
    {
        __HAL_RCC_WWDG_CLK_ENABLE();
        HAL_NVIC_SetPriority(WWDG_IRQn,2,2);//抢占优先级和响应优先级
        HAL_NVIC_EnableIRQ(WWDG_IRQn);
    }
    
    //中断服务函数
    void WWDG_IRQHandler(void)
    {
        HAL_WWDG_IRQHandler(&wwdg_handle);
    }
    
    //提前唤醒回调函数
    void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
    {
        //wwdg_feed();
        led2_Toggle();
    }
    
    //喂狗函数
    void wwdg_feed(void)
    {
        HAL_WWDG_Refresh(&wwdg_handle);
    }
    
    

    wwdg.h

    #ifndef __WWDG_H__
    #define __WWDG_H__
    
    #include "sys.h"
    
    void wwdg_init(uint8_t tr,uint8_t wr,uint32_t psc);
    void wwdg_feed(void);
    
    #endif
    
    

    5.2 出现的结果

    5.2.1 检验出现的结果1

    当主函数为下面这段代码时,出现的结果是:

    #include "sys.h"
    #include "delay.h"
    #include "led.h"
    #include "uart1.h"
    #include "wwdg.h"
    
    int main(void)
    {
        HAL_Init();                         /* 初始化HAL库 */
        stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
        led_init();//初始化led灯
        uart1_init(115200);
        wwdg_init(0x7f,0x5f,WWDG_PRESCALER_8);
        printf("hello word!\r\n");
        
        while(1)
        { 
    
        }
    }
    

    此时wwdg.c文件中,有喂狗操作。

    串口窗口显示结果为

    并且开发板LED2疯狂闪烁,表示在唤醒回调函数中成功喂狗

    5.2.2 检验出现的结果2

    当主函数为下面代码时:

    此时wwdg.c文件中,有喂狗操作。

    串口窗口显示结果为

    并且开发板LED2疯狂闪烁,表示由外部复位,并且在此时成功喂狗

    5.2.3 检验出现的结果3

    主函数代码不变,wwdg.c文件如下图所示:

    串口窗口显示结果为

    并且开发板LED2疯狂闪烁,表示此时没有喂狗,看数数溢出由,窗口看门狗是否复位

    5.2.4 检验出现的结果4

    主函数代码如下图所示:

    wwdg.c文件代码如下:

    串口窗口显示结果为

    LED1疯狂闪烁,这个时候延迟10ms喂狗的,此时喂狗在窗口期前,这个时候数数溢出由看门狗会复位

    5.2.5 检验出现的结果5

    主函数代码如下:

    串口窗口显示如下:

    LED1疯狂闪烁,在while函数中喂狗成功

    5.3 关于疑问

    在wwdg.c文件中,psc预分频器的定义,这里使用的是uint16_t,没有报错

    我的理解是:4096 * 8 = 32768 = 1000 0000 0000 0000,十六位够用

    这里如果定义的是uint8,则会报错,如下图所示:

    翻译如下:

    作者:1101 1101

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32-笔记26-WWDG窗口看门狗

    发表回复