引言
在单片机运行的过程中,我们可能会遇到程序陷入死循环的情况。很显然我们需要对这种情况进行提前的预防。看门狗就是用来进行该工作的。看门狗分为独立看门狗和窗口看门狗,这一节介绍的是独立看门狗。
看门狗介绍
STM32的独立看门狗由内部专门的40KHz低速时钟驱动,与系统主时钟分开工作,也就是说,主时钟损坏时,看门狗仍然可以正常使用。这个低速时钟是一个RC时钟,并不是很精确,频率在30~60KHz之间。
看门狗的作用就是在一定时间内(通过定时计数器实现) 没有接收喂狗信号(表示 MCU 已经挂了),便实现处理器的自动复位重启(发送复位信号)。
设置看门狗的步骤如下:
- 取消寄存器写保护
- 设置独立看门狗的预分频系数和重装载值
- 喂狗(重载计数值)
- 启动看门狗
设预分频系数为prer,重装载值为rlr,则喂狗的时间计算公式为(T的单位为ms):
$\frac{1}{40} $ 即 $\frac{1}{f} $ 是一个周期的长度,也就是计数器加一所需要的时间。\(4\times 2^{prer}\)是预分频系数的值。预分频系数乘以周期得到的是分频后计数器加一所用的时间。而这个时间再乘以重装载值rlr得到的是一次喂狗的时间。
可能有人会问,\(2^{prer}\)不是预分频系数了吗?为什么还要乘以4?这里可以看一下库函数中对分频系数的一系列预定义。
#define IWDG_Prescaler_4 ((uint8_t)0x00) #define IWDG_Prescaler_8 ((uint8_t)0x01) #define IWDG_Prescaler_16 ((uint8_t)0x02) #define IWDG_Prescaler_32 ((uint8_t)0x03) #define IWDG_Prescaler_64 ((uint8_t)0x04) #define IWDG_Prescaler_128 ((uint8_t)0x05) #define IWDG_Prescaler_256 ((uint8_t)0x06)
可以看到,当设置prer参数为0时,预分频系数为4,也就是说,我们设置参数为0时,预分频系数都不是0,而是4。因此,这里需要把这个4乘进去。
编码
main.c
int main(void){
delay_init();
//下列几个初始化函数在之前的博客中可以找到
LED_Init();
KEY_Init();
IWDG_Init(4, 625); //预分频系数为4,重装载数为625,喂狗时间约为1s。
delay_ms(500); //进行延迟,使led的灭掉可以看到。
LED0 = 0;
while(1){
if(KEY_Scan() == 1){ //如果WK_UP按键按下,就进行喂狗。
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_WriteAccessCmd(IWDG_WriteAccess_Enable); //取消写保护
IWDG_SetPrescaler(prer); //设置预分频系数
IWDG_SetReload(rlr); //设置重装载值
IWDG_ReloadCounter(); //重载计数器喂狗
IWDG_Enable(); //使能看门狗
}
void IWDG_Feed(void){
IWDG_ReloadCounter(); //重载计数器喂狗函数
}
至此,我们就完成了独立看门狗的学习。为了手中单片机的性命,还是尽量让看门狗发挥一点作用吧。