文章目录
- 基础知识
- 简介
- 作用
- 工作原理
- 寄存器
- 寄存器简介
- 寄存器操作步骤
- IWDG溢出时间计算
- IWDG 配置步骤
- HAL库相关函数介绍
- 步骤
- 实验
基础知识
简介
- IWDG : Independent watchdog, 独立看门狗
- IWDG本质是能产生系统复位信号的计数器
- 特性:
- 递减计数器
- 时钟由独立的RC振荡器提供(可在待机和停止模式下运行)
- 激活后,当递减计数器计数到0x00时产生复位
- 喂狗 :在计数器计数到0之前,重装载计数器的值,防止复位。
作用
- 单片机异常:外界电磁干扰或者自身系统异常造成程序跑飞
- 作用:WDG可以用于检测外侧电磁干扰或者硬件异常导致的程序跑飞
- 应用:在一些需要高稳定性的产品中,并且对时间精度要求较低
是异常处理的最后手段,不可依赖
工作原理
- 系统框图
IWDG 有一个输入(时钟 LSI),经过一个 8 位的可编程预分频器提供时钟给一个 12 位递减计数器,满足条件就会输出一个复位信号(iwdg1_out_rst)
STM32F407 的独立看门狗由内部专门的 32Khz 低速时钟(lsi_ck)驱动,即使主时钟发生故障,它也仍然有效。这里需要注意独立看门狗的时钟是一个内部 RC 时钟,所以并不是准确的 32Khz,而是在 17~47Khz 之间的一个可变化的时钟,只是我们在估算的时候,以 32Khz 的频率来计算,看门狗对时间的要求不是很精确,所以,时钟有些偏差。
寄存器
寄存器简介
- 关键字寄存器 IWDG_KR
- 预分频寄存器 IWDG_PR
- 该寄存器用来设置看门狗时钟(LSI)的分频系数,最低为 4,最高为 256,该寄存器是一个 32 位的寄存器,但是我们只用了最低 3 位,其他都是保留位。
- 重装载寄存器 IWDG_RLR
- 该寄存器用来保存重装载到计数器中的值。该寄存器也是一个 32 位寄存器,只有低 12 位是有效的。
- 状态寄存器 IWDG_SR
寄存器操作步骤
- 通过在键寄存器 (IWDG_KR) 中写入 0xCCCC 来使能 IWDG。
- 通过在键寄存器 (IWDG_KR) 中写入 0x5555 来使能寄存器访问。
- 通过将预分频器寄存器 (IWDG_PR) 编程为 0~7 中的数值来配置预分频器。
- 对重载寄存器 (IWDG_RLR) 进行写操作。
- 等待寄存器更新 (IWDG_SR = 0x0000 0000)。
- 刷新计数器值为 IWDG_RLR 的值 (IWDG_KR = 0xAAAA)。
IWDG溢出时间计算
- 计算公式
——"Tout"是看门狗溢出时间
——f𝐼𝑊𝐷𝐺是看门狗的时钟源频率
——psc是看门狗预分频系数
——rlr是看门狗重装载值
——prer是IWDG_PR 的值 - IWDG 最短最长的超时时间
IWDG 配置步骤
HAL库相关函数介绍
- 初始化函数
HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg);
/* 关键结构体 */
typedef struct
{
IWDG_TypeDef *Instance; /* IWDG 寄存器基地址 */
IWDG_InitTypeDef Init; /* IWDG 初始化参数 */
}IWDG_HandleTypeDef;
typedef struct
{
uint32_t Prescaler; /* 预分频系数 */
uint32_t Reload; /* 重装载值 */
} IWDG_InitTypeDef;
- 喂狗函数
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg);
步骤
- 取消寄存器写保护,设置看门狗预分频系数和重装载值
取消写保护和设置预分频系数以及重装载值在 HAL 库中是通过函数 HAL_IWDG_Init 实现的。
看门狗的时钟不是准确的32Khz,所以在喂狗的时候,最好不要太晚了,否则,有可能发生看门狗复位。 - 重载计数值喂狗(向 IWDG_KR 写入 0xAAAA)
在 HAL 中重载计数值的函数是 HAL_IWDG_Refresh - 启动看门狗(向 IWDG_KR 写入 0xCCCC)
HAL 库函数里面启动独立看门狗是通过宏定义标识符来实现
#define __HAL_IWDG_START(__HANDLE__)
WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_ENABLE);
实验
- wdg.h
#ifndef __WDG_H
#define __WDG_H
#include "./SYSTEM/sys/sys.h"
void iwdg_init(uint32_t prer, uint16_t rlr); /* 初始化IWDG,并使能IWDG */
void iwdg_feed(void); /* 喂狗 */
#endif
- wdg.c
#include "./BSP/WDG/wdg.h"
IWDG_HandleTypeDef iwdg_handler; /*独立看门狗句柄 */
/**
* @brief 初始化独立看门狗
* @param prer: IWDG_PRESCALER_4~IWDG_PRESCALER_256,对应4~256分频
* @arg 分频因子 = 4 * 2^prer. 但最大值只能是256!
* @param rlr: 自动重装载值,0~0XFFF.
* @note 时间计算(大概):Tout=((4 * 2^prer) * rlr) / 32 (ms).
* @retval 无
*/
void iwdg_init(uint32_t prer, uint16_t rlr)
{
iwdg_handler.Instance = IWDG;
iwdg_handler.Init.Prescaler = prer; /* 设置IWDG分频系数 */
iwdg_handler.Init.Reload = rlr; /* 从加载寄存器 IWDG->RLR 重装载值 */
HAL_IWDG_Init(&iwdg_handler); /* 初始化IWDG并使能 */
}
/**
* @brief 喂独立看门狗
* @param 无
* @retval 无
*/
void iwdg_feed(void)
{
HAL_IWDG_Refresh(&iwdg_handler); /* 喂狗 */
}
- main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/KEY.h"
#include "./BSP/WDG/wdg.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
key_init(); /* 初始化按键 */
delay_ms(100); /* 延时100ms再初始化看门狗,LED0的变化"可见" */
printf("您还没喂狗,请及时喂狗!\r\n");
iwdg_init(IWDG_PRESCALER_64, 500); /* 预分频数为64,重载值为500,溢出时间约为1s */
LED0(0); /* 点亮LED0(红灯) */
while(1)
{
if (key_scan(1) == WKUP_PRES) /* 如果WK_UP按下,则喂狗,支持连按 */
{
iwdg_feed(); /* 喂狗 */
printf("您已喂狗!\r\n");
}
delay_ms(10);
}
}