独立看门狗(IWDG)实验
独立看门狗简介
单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环, 看门狗电路就是为了避免这种情况的发生 。IWDG(Independent watchdog)独立看门狗,可以用来检测并解决由于软件错误导致的故障,当计数器到达给定的超时值时,会触发一个中断或产生系统复位。独立看门狗用通俗一点的话来解释就是一个 12 位的递减计数器,当计数器的值从某个值一直减到 0 的时候,系统就会产生一个复位信号,即 IWDG_RESET。如果在计数没减到 0 之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们经常说的喂狗。
看门狗的作用就是在一定时间内(通过定时计数器实现) 没有接收喂狗信号(表示 MCU 已经挂了),便实现处理器的自动复位重启 (发送复位信号) 。
IWDG_KR寄存器
在键值寄存器 (IWDG_ KR)中写入 0xCCCC ,开始启用独立看门狗;此时计数器开始从其复位值 0xFFF 递减计数。当计数器计数到末尾 0x000 时,会产生一个复位信号 (IWDG_RESET) 。无论何时,只要键寄存器 IWDG_KR 中被写入0xAAAA ,IWDG_RLR 中的值就会被重新加载到计数器中从而避免产生看门狗复位。
IWDG_PR和 IWDG_RLR 寄存器具有写保护功能。要修改这两个寄存器的值,必须先向IWDG_KR 寄存器中写入 0x5555 。 将其他值写入这个寄存器将会打乱操作顺序,寄存器将重新被保护。重装载操作(即写入 0xAAAA) 也会启动写保护功能。
还有两个寄存器,一个预分频寄存器( IWDG_PR ),该寄存器用来设置看门狗时钟的分频系数 。 另一个重装载寄存器。该寄存器用来保存重装载到计数器中的值。该寄存器也是一个 32位寄存器,但是只有低 12 位是有效的 。
取消寄存器写保护向IWDG_KR写0X5555:
IWDG_WriteAccessCmd(IW DG_WriteAccess_Enable);
设置独立看门狗的预分频系数和重装载值:
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler) //设置 IWDG 预分频值
void IWDG_SetReload(uint16_t Reload) //设置 IWDG 重装载值
看门狗溢出时间:
Tout=((4 × 2^prer) × rlr)/40
重载计数值喂狗(向 IWDG_KR 写入 0XAAAA):
IWDG_ReloadCounter(); // 按照 IWDG 重装载寄存器的值重装载 IWDG 计数器
启动看门狗(向 IWDG_KR 写入0XCCCC):
IWDG_ Enable(); // 使能 IWDG
实现目标
用两个IO口,一个用来输入喂狗信号,另外一个用来指示程序是否重启。喂狗我们采用板上的 WK_UP 键来操作,而程序重启,则是通过 DS0 来指示的。
dog.h
#ifndef __WDG_H
#define __WDG_H
#include "stm32f10x_iwdg.h"
void IWDG_Init(u8 prer,u16 rlr);
void IWDG_Feed(void);
#endif
dog.c
#include"dog.h"
void IWDG_Init(u8 prer,u16 rlr)
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //① 使能对寄存器I写操作
IWDG_SetPrescaler(prer); //② 设置IWDG预分频值设置IWDG预分频值
IWDG_SetReload(rlr); //② 设置IWDG重装载值
IWDG_ReloadCounter(); // ③ 按照IWDG重装载寄存器的值重装载IWDG计数器
IWDG_Enable(); //④ 使能IWDG
}
//喂独立看门狗
void IWDG_Feed(void)
{
IWDG_ReloadCounter();//reload
}
main
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "dog.h"
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
LED_Init(); //初始化与LED连接的硬件接口
KEY_Init(); //按键初始化
delay_ms(500); //让人看得到灭
IWDG_Init(4,625); //与分频数为64,重载值为625,溢出时间为1s
LED0=0; //点亮LED0
while(1)
{
if(KEY_Scan(0)==WKUP_PRES)
{
IWDG_Feed();//如果WK_UP按下,则喂狗
}
delay_ms(10);
};
}