IWDG---独立看门狗

时间:2024-06-01 18:38:57

一、独立看门狗简介

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

    独立看门狗:就是一个12位的递减计数器(最大值为0xFFF),当计数器的值从某个值一直减到0的时候,系统就会产生一个复位信号,即IWDG_RESET。如果在计数没减到0之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作称为喂狗。看门狗功能由VDD电压域供电,在停止模式和待机模式下仍能工作。

    独立看门狗工作原理:

IWDG---独立看门狗

二、功能框图

IWDG---独立看门狗

    (1)独立看门狗时钟

            独立看门狗的时钟由LSI提供,即使主时钟发生故障它仍然有效,非常独立。LSI的频率一般在30 ~ 60KHz之间,根据温度和工作场合会有一定的漂移,我们一般取40KHz,所以独立看门狗的定时时间并不一定非常精确,只适用于对时间精度要求比较低的场合。

    (2)计数器时钟

            递减计数器的时钟由LSI经过一个8位的预分频器分频得到,可以操作预分频器寄存器IWDG_PR来设置分频因子,分频因子可以是:4,8,16,32,64,128,256。计数器时钟 = LSI / 分频因子(CK_CNT= 40/ 4*2^PRV。)。

    (3)计数器

            独立看门狗的计数器是一个12位的递减计数器,最大值为0xFFF,当计数器减到0时,会产生一个复位信号IWDG_RESET,让程序重新运行。如果在计数器减到0之前刷新了计数器的值的话,就不会产生复位信号,重新刷新计数器值的动作我们俗称喂狗。

    (4)重装载寄存器

            重装载寄存器是一个 12 位的寄存器,里面装着要刷新到计数器的值,这个值的大小决定着独立看门狗的溢出时间。超时时间Tout = (4*2^prv) / 40 * rlv (s) , prv 是预分频器寄存器的值, rlv 是重装载寄存器的值

    (5)键值寄存器(控制寄存器)

            IWDG---独立看门狗

    (6)状态寄存器

            IWDG---独立看门狗

三、如何使用IWDG

    1、一般用来检测和解决由程序引起的故障。

    2、比如一个程序正常运行的时间是50ms,在运行完这个段程序之后紧接着进行喂狗,我们设置独立看门狗的定时溢出时间为60ms,比我们需要监控的程序 50ms 多一点,如果超过 60ms 还没有喂狗,那就说明我们监控的程序出故障了,跑飞了,那么就会产生系统复位,让程序重新运行。

    3、伪代码

IWDG---独立看门狗

四、常用固件库函数

    (1)使能预分频寄存器和重装载寄存器可写

            void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);

            参数:

                    IWDG_WriteAccess_Enable 
                    IWDG_WriteAccess_Disable

    (2)设置预分频器的值

            void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);

            参数:

                    IWDG_Prescaler_4  
                    IWDG_Prescaler_8  
                    IWDG_Prescaler_16 
                    IWDG_Prescaler_32 
                    IWDG_Prescaler_64 
                    IWDG_Prescaler_128
                    IWDG_Prescaler_256

    (3)设置重装载寄存器的值

            void IWDG_SetReload(uint16_t Reload);

            参数:

                    0 ~ 0x0FFF

    (4)把重装载寄存器的值放到计数器中(喂狗)

            void IWDG_ReloadCounter(void);

    (5)使能IWDG

            void IWDG_Enable(void);

    (6)获取状态寄存器的值

            FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);

            参数:

                    IWDG_FLAG_PVU 
                    IWDG_FLAG_RVU 

五、程序

bsp_iwdg.h文件

#ifndef __BSP_IWDG_H__
#define __BSP_IWDG_H__

#include "stm32f4xx_conf.h"

void IWDG_Config(uint8_t prv,uint8_t rlv);
extern void IWDG_Feed(void);


#endif

bsp_iwdg.c文件

#include "./iwdg/bsp_iwdg.h"


/*************************************
    功能:独立看门狗配置
    参数:
        prv--预分频寄存器的值 
        rlv--重装载寄存器的值,范围:0-0XFFF
    返回值:无
**************************************/
void IWDG_Config(uint8_t prv,uint8_t rlv)
{
    /*1、使能预分频寄存器和重装载寄存器可写*/
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
    
    /*2、设置预分频器的值*/
    IWDG_SetPrescaler(prv);
    
    /*3、设置重装载寄存器的值*/
    IWDG_SetReload(rlv);
    
    /*4、把重装载寄存器的值放到计数器中*/
    IWDG_ReloadCounter();
    
    /*5、使能IWDG*/
    IWDG_Enable();
}

/************************
    功能:喂狗
    参数:无
    返回值:无
*************************/
void IWDG_Feed(void)
{
    //把重装载寄存器的值放到计数器中,喂狗,防止IWDG复位
    //当计数器的值减到0的时候会产生系统复位
    IWDG_ReloadCounter();
}

main.c文件

#include "./usart/bsp_usart.h"
#include "./led/bsp_led.h"
#include "./iwdg/bsp_iwdg.h"
#include "./key/button.h"
#include "stdio.h"

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

int main(void)
{
    LED_Config();
    Delay(0X8FFFFF);    
    
    /* 检查是否为独立看门狗复位 */
  if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)  //独立看门狗复位
  {
    /*  亮LED1 */
    LED_ON(1);

    /* 清除标志 */
    RCC_ClearFlag();
        
        /*如果一直不喂狗,会一直复位,加上前面的延时,会看到红灯闪烁
        在1s 时间内喂狗的话,则会持续亮绿灯*/
  }
  else
  {
    /*不是独立看门狗复位(可能为上电复位或者手动按键复位之类的) */
    /* 亮LED3 */
    LED_ON(3);
  }        
  
  /*初始化按键*/
  button_init();    
    
    // IWDG 1s 超时溢出
    IWDG_Config(IWDG_Prescaler_64 ,625); 

 
    //while部分是我们在项目中具体需要写的代码,这部分的程序可以用独立看门狗来监控
  //如果我们知道这部分代码的执行时间,比如是500ms,那么我们可以设置独立看门狗的
    //溢出时间是600ms,比500ms多一点,如果要被监控的程序没有跑飞正常执行的话,那么
    //执行完毕之后就会执行喂狗的程序,如果程序跑飞了那程序就会超时,到达不了喂狗的
    //程序,此时就会产生系统复位。但是也不排除程序跑飞了又跑回来了,刚好喂狗了,
    //歪打正着。所以要想更精确的监控程序,可以使用窗口看门狗,窗口看门狗规定必须
    //在规定的窗口时间内喂狗。
    while(1)                            
    {       
        if( button_state(1) == 0  )
        {
            // 喂狗,如果不喂狗,系统则会复位,复位后亮LED1,如果在1s时间内准时喂狗的话,则会亮LED2
            IWDG_Feed();        
            //喂狗后亮LED2
            LED_ON(2);
        }
    }
}