看门狗的基础知识
什么是看门狗
在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,导致单片机控制的系统无法继续工作,造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于检测单片机程序运行状态的外设或者芯片,俗称“看门狗”。
看门狗的作用
在微控制器进入错误状态后的一定时间内复位程序,重新运行。当看门狗使能时,如果用户程序没有在溢出周期内喂狗(给看门狗定时器重装定时值),看门狗会产生一个系统复位,这样在程序运行时开启看门狗,对程序进行监视,可防止程序跑飞而死机。
IWDG(独立看门狗)简介
IWDG_KR 键寄存器
IWDG_PR 预分频寄存器
IWDG_RLR 重载寄存器
STM32的独立看门狗由内部专门的40Khz低速时钟驱动,即使主时钟发生故障,它也仍然有效。这里需要注意独立看门狗的时钟是一个内部RC时钟,所以并不是准确的40Khz,而是在30~60Khz之间的一个可变化的时钟,只是我们在估算的时候,以40Khz的频率来计算,看门狗对时间的要求不是很精确,所以,时钟有些偏差,都是可以接受的。
在键值寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值0xfff递减计数。当计数器计数到末尾0x000时,会产生一个复位信
号(IWDG_RESET)。
无论何时,只要键寄存器IWDG——KR中被写入0xAAAA,IWDG_RLR中的值就会被重新加载到计数器中从而避免产生看门狗复位。
IWDG_PR和IWDG_RLR寄存器具有写保护功能。要修改这两个寄存器的值,必须先向IWDG_KR寄存器中写入0x5555,将其他值写入这个寄存器将会打乱操作顺序,寄存器将重新被保护。重装载操作(即写入0xAAAA)也会启动写保护功能。
注意IWDG在一旦启用,就不能再被关闭!想要关闭,只能重启,并且重启之后不能打开IWDG,否则还是不能关闭。
IWDG的寄存器版介绍
test.c
//实验现象很简单,如果不喂狗,那么LED闪烁,因为超过了时间,系统进行了复位,按下KEY1键进行喂狗,那么就不会复位那么LED将一直亮。
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "wdg.h"
int main(void)
{
Stm32_Clock_Init(9);
uart_init(72,115200);
delay_init(72);
LED_Init();
KEY_Init();
delay_ms(500);
IWDG_Init(4,625);
//4二进位制 100,对应分频64
//重载值625,如何计算在wdg.c
LED1 = 0;
while(1)
{
if(KEY_Scan(0) == KEY1_PRES)
{
IWDG_Feed();
}
delay_ms(10);
}
}
wdg.h
#ifndef __WDG_H
#define __WDG_H
#include "sys.h"
void IWDG_Init(u8 prer,u16 rlr);
void IWDG_Feed(void);
#endif
wdg.c
//我感觉这章看代码还是很容易理解的
#include "wdg.h"
void IWDG_Init(u8 prer,u16 rlr)
{
IWDG->KR = 0x5555;
//对独立看门狗的键值寄存器输入0x5555,
//使能IWDG->PR(预分频寄存器)和IWDG
//->RLR(重装载寄存器)
IWDG->PR = prer;
//设置分频系数
IWDG->RLR = rlr;
//重装载寄存器值
//Tout=((4×2^prer) ×rlr) /40
// 假设prer 值为 4,rlr 值为 625,那么就
//可以得到 Tout=64×625/40=1000ms
IWDG->KR = 0xAAAA;
//喂狗,
IWDG->KR = 0xCCCC;
//使能启动看门狗
}
void IWDG_Feed(void)
{
IWDG->KR = 0xAAAA;
//喂狗
}
IWDG的HAL库介绍
头文件:stm32f1xx_hal_iwdg.h
源文件:stm32f1xx_hal_iwdg.c
重要函数
IWDG初始化函数
HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg)
IWDG启动函数
HAL_StatusTyPeDef HAL_IWDG_Start(IWDG_HandleTypeDef *hiwdg)
IWDG喂狗函数
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg)
代码
main.c
#include "MyIncludes.h"
u16 sys_cnt = 0;
//systick滴答定时器计时器
void systick_isr(void)
{
if(sys_cnt <100)
{
sys_cnt++;
}
else
{
sys_cnt = 0;
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_4|GPIO_PIN_5);
//反转PC4 PC5 LED
}
}
int main(void)
{
System_Init();
LED_Init();
Key_Init();
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_4|GPIO_PIN_5,GPIO_PIN_RESET);
//打开PC4 PC5 LED
delay_ms(2000);
SysTick_Init(systick_isr);
Iwdg_Init(500);
//独立看门狗初始化
while(1)
{
Key_Read();
if(Key_Info.Num != 0)
{
switch( Key_Info.Num )
{
case KEY_ONE:
Iwdg_Feed();
//喂狗
break;
default:break;
}
}
}
}
/*可能刚看到这个程序有点懵,其实这个实验就是如果
没有按key1键,也就是没有喂狗,那么实验现象就是D5
D6 长亮一下,然后闪烁,然后一直重复此现象,因为没
有喂狗系统就会系统复位。但是如果长按key1,就会喂狗
,那么系统就不会复位,然后将一直进行systick滴答定
时器里面的内容,也就是会D5 D6一直闪烁*/
iwdg.h
#ifndef __IWDG_H_
#define __IWDG_H_
#include "stm32f1xx.h"
#include "stm32_types.h"
#include "stm32f1xx_hal.h"
void Iwdg_Init(u16 ms);
//独立看门狗初始化函数
void Iwdg_Feed(void);
//喂狗函数
#endif
iwdg.c
#include "iwdg.h"
IWDG_HandleTypeDef IwdgHandle;
void Iwdg_Init(u16 ms)
{
u16 timeout;
if(ms >= 2048)
//独立看门狗重装载寄存器低12位有效 也就是 0 - 11,一共12个端口
//不要钻牛角尖 一定要是 2的12次方也就是4096,也可以是1024 512等
timeout = 2048;
else
timeout = ms;
if(__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != RESET )
//检查系统是否已从IWDG复位恢复
{
__HAL_RCC_CLEAR_RESET_FLAGS();
//清除重置标志
}
IwdgHandle.Instance = IWDG;//寄存器基址为 IWDG
IwdgHandle.Init.Prescaler = IWDG_PRESCALER_32;//预分频32khz
IwdgHandle.Init.Reload = timeout;//计数
HAL_IWDG_Init(&IwdgHandle);
HAL_IWDG_Start(&IwdgHandle); //启动看门狗
}
void Iwdg_Feed(void)
//喂狗
{
HAL_IWDG_Refresh(&IwdgHandle);
}