Rane

引言

在单片机运行的过程中,我们可能会遇到程序陷入死循环的情况。很显然我们需要对这种情况进行提前的预防。看门狗就是用来进行该工作的。看门狗分为独立看门狗和窗口看门狗,这一节介绍的是独立看门狗。




看门狗介绍

STM32的独立看门狗由内部专门的40KHz低速时钟驱动,与系统主时钟分开工作,也就是说,主时钟损坏时,看门狗仍然可以正常使用。这个低速时钟是一个RC时钟,并不是很精确,频率在30~60KHz之间。

看门狗的作用就是在一定时间内(通过定时计数器实现) 没有接收喂狗信号(表示 MCU 已经挂了),便实现处理器的自动复位重启(发送复位信号)。

设置看门狗的步骤如下:

  • 取消寄存器写保护
  • 设置独立看门狗的预分频系数和重装载值
  • 喂狗(重载计数值)
  • 启动看门狗

设预分频系数为prer,重装载值为rlr,则喂狗的时间计算公式为(T的单位为ms):

\[T=\frac{4 \times 2^{p r e r} \times r l r}{40} \]

$\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();		//重载计数器喂狗函数
}




至此,我们就完成了独立看门狗的学习。为了手中单片机的性命,还是尽量让看门狗发挥一点作用吧。

分类:

技术点:

相关文章: