文章目录
看门狗
在由单片机构成的微型计算机系统中单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环;或者因为用户配置代码出现BUG,导致芯片无法正常工作,出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog)
简单说:看门狗的本质就是定时计数器,计数器使能之后一直在累加 而喂狗就是重新写入计数器的值,时计数器重新累加,
如果在一定时间内没有接收到喂狗信号(表示MCU已经挂了),便实现处理器的自动复位重启(发送复位信号)
STM32的内置看门狗
STM32内置两个看门狗,提供了更高的安全性、时间的精确性和使用的灵活性。两个看门狗设备(独立看门狗、窗口看门狗)可以用来检测和解决由软件错误引起的故障。当计数器达到给定的超时值时,触发一个中断(仅适用窗口看门狗)或者产生系统复位。
- 独立看门狗(IWDG)由专用的低速时钟(LSI)驱动(40kHz),即使主时钟发生故障它仍有效。独立看门狗适合应用于需要看门狗作为一个在主程序之外 能够完全独立工作,并且对时间精度要求低的场合。
- 窗口看门狗由从APB1时钟(36MHz)分频后得到时钟驱动。通过可配置的时间窗口来检测应用程序非正常的过迟或过早操作。 窗口看门狗最适合那些要求看门狗在精确计时窗口起作用的程序。
WWDG-窗口看门狗
窗口看门狗跟独立看门狗一样,也是一个递减计数器不断的往下递减计数,当减到一个固定值 0x3F 时还不喂狗的话,产生复位,这个值叫窗口的下限,是固定的值,不能改变。
窗口看门狗之所以称为窗口,就是因为其喂狗时间是在一个有上下限的范围内(计数器减到某个值~计数器减到0x3F),在这个范围内才可以喂狗,可以通过设定相关寄存器,设定其上限时间(但是下限是固定的0x3F)
- 计数器的初始值
- 是我们设置的上窗口(W[6:0]值
- 是下窗口值(0x3F)
CubeMX操作步骤
1 选择窗口看门狗
2 选中Activated
3 设置分频值psc、窗口寄存器的值window value、递减计数器刷新值counter
4 还有最后的中断提前唤醒Enable
1)使能 WWDG时钟
WWDG不同于 IWDG IWDG有自己独立的 32Khz时钟,不存在使能问题。而 W WDG使用的是 PCLK1的时钟,需要先使能时钟 。方法是 : __HAL_RCC_WWDG_CLK_ENABLE(); //使能窗口看门狗时钟
2)设置窗口值 ,分频数 和计数器初始值
在HAL库中,这三个值都是通过函数 HAL_WWDG_Init来设置的。该函数声明如下:
HAL_StatusTypeDef HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg);
该函数只有一个入口参数,就是WWDG_HandleTypeDef结构体类型指针变量。这里我们来看看 WWDG_HandleTypeDef结构体定义:
typedef struct { WWDG_TypeDef *Instance; WWDG_InitTypeDef Init; HAL_LockTypeDef Lock; __IO HAL_WWDG_StateTypeDef State; }WWDG_HandleTypeDef;
该结构体和前面我们讲解的WWDG_HandleTypeDef类似,这里我们就主要讲解成员变量Init,它是 WWDG_InitTypeDef结构体类型,该结构体定义如下:
typedef struct { uint32_t Prescaler; //预分频系数
uint32_t Window; //窗口值
uint32_t Counter; //计数器值
}WWDG_InitTypeDef;
该结构体有3三个成员变量,分别用来设置 WWDG的预分频系数,窗口之以及计数器值。
函数 HAL_WWDG_Init的使用范例如下:
WWDG_HandleTypeDef WWDG_Handler; //窗口 看门狗句柄
WWDG_Handler.Instance=WWDG; //窗口看门狗
WWDG_Handler.Init.Prescaler=WWDG_PRESCALER_8; //设置分频系数为 8
WWDG_Handler.Init.Window=0X5F; //设置窗口值 0X5F
WWDG_Handler.Init.Counter=0x7F; //设置计数器值 0x7F
HAL_WWDG_Init(&WWDG_Handler); //初始化 WWDG
3)开启 WWDG
HAL库中开启 WWDG的函数有两个:
HAL_StatusTypeDef HAL_WWDG_Start(WWDG_HandleTypeDef *hwwdg); HAL_StatusTypeDef
HAL_WWDG_Start_IT(WWDG_HandleTypeDef *hwwdg);
函数 HAL_WWDG_Start仅仅只是用来开启 WWDG,而函数 HAL_WWDG_Start_IT除了
启动 WWDG,还同时启动 WWDG中断。
4)使能中断通道并配置优先级(如果开启了 WWDG中断)
这一步相信大家已经非常熟悉了,我们这里仅仅列出两行实现代码,如下:
HAL_NVIC_SetPriority(WWDG_IRQn,2,3); //抢占优先级 2,子优先级为 3
HAL_NVIC_EnableIRQ(WWDG_IRQn); //使能窗口看门狗中断
这里大家要注意,跟串口一样, HAL库同样为看门狗提供了 MSP回调函数HAL_WWDG_MspInit,一般情况下,步骤 1和步骤 4的步骤,是与 MCU相关的,我们均放在该回调函数中。 关于 MSP回调函数的使用方法,前面多次讲解,这里我们就不累赘了。
5) 编写中断服务函数
在最后,还是要编写窗口看门狗的中断服务函数,通过该函数来喂狗,喂狗要快,否则当窗口看门狗计数器值减到 0X3F的时候,就会引起软复位了。在中断服务函数里面也要将状态寄存器的 EWIF位清空。窗口看门狗中断服务函数为:
void WWDG_IRQHandler(void);
在HAL库中,喂狗函数为:
HAL_StatusTypeDef HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg, uint32_t cnt);
WWDG的喂狗操作实际就是往 CR寄存器重写计数器值,这里的第二个入口函数就是重写的计数器的值。
6) 重写窗口看门狗唤醒中断处理回调函数 HAL_WWDG_WakeupCallback
跟串口和外部中断 一样, 首先, HAL库定义了一个中断处理共用函数HAL_WWDG_IRQHandler,我们在 WWDG中断服务函数中会调用该函数。同时该函数内部,会经过一系列判断,最后调用回调函数 HAL_WWDG_WakeupCallback,所以提前唤醒中断逻辑我们一般些在回调函数 HAL_WWDG_WakeupCallback中。 回调函数声明为:
void HAL_WWDG_WakeupCallback(WWDG_HandleTypeDef* hwwdg);
完成了以上6个步骤之后,我们就可以使用 STM32F4的窗口看门狗了。
结果