一、简介
IWDG:全称是Independent watchdog,即独立看门狗。本质上是一个能产生系统复位信号的计数器。
特性:
是一个递减计数器。
时钟信号由独立的RC振荡器提供,可在待机和停止模式下运行。
看门狗被激活后,当递减计数器计数到0x000时产生系统复位信号。
喂狗操作:在计数器计数到0x000之前,重新装载计数器的值,使得计数器从新装载的值重新开始计数,以防止系统复位,这一过程就叫做喂狗。
作用:
由于外界电磁干扰或者自身系统(硬件或软件)异常,会造成程序跑飞,如:陷入某个不正常的死循环,打断正常的程序运行。
IWDG解决的问题就是:由于外界电磁干扰或硬件异常导致的程序跑飞问题。
应用:
IWDG主要应用于一些需要高稳定性的产品中,并且对时间精度要求较低的场合。
二、工作原理
时钟源(Src CLK)经过预分频器后得到看门狗时钟(IWDG CLK),看门狗时钟为递减计数器提供时钟信号。
重装载寄存器为递减计数器提供开始计数的值,喂狗操作就是在递减计数器的值减到0之前,将重装载寄存器的值重新加载给递减计数器。
看门狗被激活后,每发生一个IWDG CLK,递减计数器的值就会减1,直到减到0时,将会产生复位信号。
三、功能框图
1. 时钟信号
时钟源:
LSI是时钟源。
LSI时钟频率并不精确,例如:F1用40kHz,F4/F7/H7用32kHz。
启用IWDG后,LSI时钟会自动开启。
IWDG时钟:
由时钟源LSI经过预分频器分频后得到的时钟频率,就是IWDG的时钟。
IWDG时钟为递减计数器提供时钟信号,每发生一个IWDG时钟,递减计数器的值就会减1。
2. 重装载值&递减计数器
重装载寄存器低12位有效,因此重装载值的最大值为:2^12 = 4096。
重装载值为递减计数器提供初始值,递减计数器从初始值开始,每发生一次IWDG时钟信号,数值就会减1。若无喂狗操作时,当递减计数器值减到0时,就会产生复位信号;如有喂狗操作(将重装载值重新加载给递减计数器)时,递减计数器在喂狗操作后就会从新的初始值(拿到的新的重装载值)重新开始计数。
3. 寄存器
3.1 密钥寄存器
0xAAAA:进行喂狗。
0x5555:解除PR和RLR寄存器写访问保护。
0xCCCC:启动看门狗开始工作。
3.2 重装载寄存器
用于存放重装载值,低12位有效,即最大值为4096。
只有在KR寄存器中解除对RLR寄存器的写访问保护后,才能对该寄存器写入重装载值。
3.3 状态寄存器
用于判断预分频值和重装载值是否已经被更新。
3.4 预分频寄存器
四、溢出时间计算
1. 公式
2. 最短最长溢出时间计算
五、开发流程
1. 开发步骤
2. 函数详解
2.1 HAL_IWDG_Init()函数
功能:
设置预分频系数和重装载值,并使能IWDG。
函数原型:
HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg);
参数:
hiwdg:IWDG句柄。
typedef struct
{
IWDG_TypeDef *Instance; /* IWDG寄存器基地址 */
IWDG_InitTypeDef Init; /* IWDG初始化 */
} IWDG_HandleTypeDef;
typedef struct
{
uint32_t Prescaler; /* 预分频系数 */
uint32_t Reload; /* 重装载值 */
} IWDG_InitTypeDef;
返回值:
typedef enum
{
HAL_OK = 0x00U, /* 成功 */
HAL_ERROR = 0x01U, /* 失败 */
HAL_BUSY = 0x02U, /* 忙碌 */
HAL_TIMEOUT = 0x03U /* 超时 */
} HAL_StatusTypeDef;
相关寄存器:
IWDG_PR、
IWDG_RLR、
IWDG_KR。
2.2 HAL_IWDG_Refresh()函数
功能:
把重装载寄存器的值加载到递减计数器中,进行喂狗操作。
函数原型:
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg);
参数:
hiwdg:IWDG句柄。
返回值:
typedef enum
{
HAL_OK = 0x00U, /* 成功 */
HAL_ERROR = 0x01U, /* 失败 */
HAL_BUSY = 0x02U, /* 忙碌 */
HAL_TIMEOUT = 0x03U /* 超时 */
} HAL_StatusTypeDef;
相关寄存器:
IWDG_KR。
六、编程实战
1. 思路
2. 代码
iwdg.c文件
#include "./BSP/WDG/wdg.h"IWDG_HandleTypeDef g_iwdg_handle;/* IWDG初始化函数 */
void iwdg_init(uint8_t prer, uint16_t rlr)
{g_iwdg_handle.Instance = IWDG;g_iwdg_handle.Init.Prescaler = prer;g_iwdg_handle.Init.Reload = rlr;HAL_IWDG_Init(&g_iwdg_handle);
}/* 喂狗函数 */
void iwdg_feed(void)
{HAL_IWDG_Refresh(&g_iwdg_handle);
}
main.c文件
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/WDG/wdg.h"int main(void)
{HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟为72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */printf("您还没喂狗,请及时喂狗!!!\r\n");iwdg_init(IWDG_PRESCALER_32, 1250); /* 预分频系数为32,重装载值为1250,溢出时间约为1s */while (1){delay_ms(1000);iwdg_feed();printf("已经喂狗\r\n");}
}