一、独立看门狗简介
独立看门狗(宠物狗);窗口看门狗(警犬)。
独立看门狗:就是一个12位的递减计数器(最大值为0xFFF),当计数器的值从某个值一直减到0的时候,系统就会产生一个复位信号,即IWDG_RESET。如果在计数没减到0之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作称为喂狗。看门狗功能由VDD电压域供电,在停止模式和待机模式下仍能工作。
独立看门狗工作原理:
二、功能框图
(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)键值寄存器(控制寄存器)
(6)状态寄存器
三、如何使用IWDG
1、一般用来检测和解决由程序引起的故障。
2、比如一个程序正常运行的时间是50ms,在运行完这个段程序之后紧接着进行喂狗,我们设置独立看门狗的定时溢出时间为60ms,比我们需要监控的程序 50ms 多一点,如果超过 60ms 还没有喂狗,那就说明我们监控的程序出故障了,跑飞了,那么就会产生系统复位,让程序重新运行。
3、伪代码
四、常用固件库函数
(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);
}
}
}