目录
一、IWDG简介
IWDG(Independent watchdog),即独立看门狗
本质:能产生系统复位信号的计数器
特性:递减的计数器,时钟由独立的 RC 振荡器提供(可在待机和停止模式下运行),看门狗被激活后,当递减计数器计数到 0x000 时产生复位
喂狗:在计数器计数到 0 之前,重装载计数器的值,防止复位
异常 | 外界电磁干扰或者自身系统(硬件或软件)异常,造成程序跑飞,如:陷入某个不正常的死循环,打断正常的程序运行 |
作用 | 主要用于检测外界电磁干扰,或硬件异常导致的程序跑飞问题 |
应用 | 在一些需要高稳定性的产品中,并且对时间精度要求较低的场合 |
独立看门狗是异常处理的最后手段,不可依赖,应在设计时尽量避免异常的发生!
二、IWDG工作原理
原理图
CPU 必须及时喂狗,否则系统复位重启!
三、IWDG框图
启用 IWDG 后,LSI 时钟会自动开启
LSI 时钟频率并不精确,F1 用 40kHz,F4/F7/H7 用 32kHz 进行计算即可
四、IWDG寄存器
4.1、关键字寄存器(IWDG_KR)
用于喂狗,解除PR和RLR寄存器写访问保护,以及启动看门狗工作
4.2、预分频器寄存器(IWDG_PR)
4.3、重载寄存器(IWDG_RLR)
用于存放重装载值,低12位有效,即最大值为4096
4.4、状态寄存器(IWDG_SR)
4.5、寄存器配置操作步骤
1、通过在键寄存器 (IWDG_KR) 中写入 0xCCCC 来使能 IWDG
2、通过在键寄存器 (IWDG_KR) 中写入 0x5555 来使能寄存器访问
3、通过将预分频器寄存器 (IWDG_PR) 编程为 0~7 中的数值来配置预分频器
4、对重载寄存器 (IWDG_RLR) 进行写操作
5、等待寄存器更新 (IWDG_SR = 0x0000 0000)
6、刷新计数器值为 IWDG_RLR 的值 (IWDG_KR = 0xAAAA)
五、IWDG溢出时间计算
5.1、IWDG溢出时间计算公式(HAL库)
是看门狗溢出时间
是看门狗的时钟源频率
是看门狗预分频系数
是看门狗重装载值
5.2、寄存器设置分频系数的方法
是 IWDG_PR 的值
5.3、IWDG溢出时间计算公式(寄存器)
5.4、IWDG最短最长超时时间(F4/F7/H7)
六、IWDG配置步骤
6.1、使能并初始化IWDG
取消 PR/RLR 寄存器写保护,设置 IWDG 预分频系数和重装载值,启动 IWDG
HAL库驱动函数:HAL_IWDG_Init()
/**
* @brief Initialize the IWDG according to the specified parameters in the
* IWDG_InitTypeDef and start watchdog. Before exiting function,
* watchdog is refreshed in order to have correct time base.
* @param hiwdg pointer to a IWDG_HandleTypeDef structure that contains
* the configuration information for the specified IWDG module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg);
关键结构体
/**
* @brief IWDG Init structure definition
*/
typedef struct
{
uint32_t Prescaler; /*!< Select the prescaler of the IWDG.
This parameter can be a value of @ref IWDG_Prescaler */
uint32_t Reload; /*!< Specifies the IWDG down-counter reload value.
This parameter must be a number between Min_Data = 0 and Max_Data = 0x0FFF */
} IWDG_InitTypeDef;
6.2、及时喂狗
把重装载寄存器的值重载到计数器中,写入 0xAAAA 到 IWDG_KR,喂狗
HAL库驱动函数:HAL_IWDG_Refresh()
/**
* @brief Refresh the IWDG.
* @param hiwdg pointer to a IWDG_HandleTypeDef structure that contains
* the configuration information for the specified IWDG module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg);
七、编程实战:验证不及时喂狗,系统将复位重启
验证思路:按下 WKUP 时可喂狗,当超过 1s 没喂狗时系统将复位重启,LED0 反复初始化点亮,正常喂狗时 LED0 常亮
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的变化"可见" */
iwdg_init(IWDG_PRESCALER_64, 500); /* 预分频数为64,重载值为500,溢出时间约为1s */
LED0(0); /* 点亮LED0(红灯) */
while (1)
{
if (key_scan(1) == WKUP_PRES) /* 如果WK_UP按下,则喂狗,支持连按 */
{
iwdg_feed(); /* 喂狗 */
}
delay_ms(10);
}
}
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并使能 */
}
/* 喂独立看门狗 */
void iwdg_feed(void)
{
HAL_IWDG_Refresh(&iwdg_handler); /* 喂狗 */
}
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
八、WWDG简介
WWDG(Window watchdog),即窗口看门狗
本质:能产生系统复位信号和提前唤醒中断的计数器
特性:递减的计数器,当递减计数器值从 0x40 减到 0x3F 时复位(即 T6 位跳变到 0),计数器的值大于 W[6:0] 值时喂狗会复位,提前唤醒中断 (EWI):当递减计数器等于 0x40 时可产生
喂狗:在窗口期内重装载计数器的值,防止复位
作用 | 用于监测单片机程序运行时效是否精准,主要检测软件异常 |
应用 | 需要精准检测程序运行时间的场合 |
九、WWDG工作原理
注意:W[6:0] 必须大于窗口下限值 0x3F,否则无窗口期
十、WWDG框图
时钟源
PCLK1 | |
F103 | 36MHz |
F407 | 42MHz |
F429 | 45MHz |
F767 | 54MHz |
H743 | 100MHz |
十一、WWDG寄存器
11.1、控制寄存器(WWDG_CR)
用于使能窗口看门狗工作,以及重装载计数器值(即喂狗)
11.2、配置寄存器(WWDG_CFR)
用于使能窗口看门狗提前唤醒中断,设置预分频系数,设置窗口上限值
11.3、状态寄存器(WWDG_SR)
用于判断是否发生了 WWDG 提前唤醒中断
十二、WWDG超时时间计算
WWDG 超时时间计算公式
是 WWDG 超时时间(没喂狗)
是 WWDG 的时钟源频率
是 WWDG 固定的预分频系数
是 WWDG_CFR 寄存器设置的预分频系数值
是 WWDG 计数器低 6 位
WWDG 最短最长超时时间(F4/F7/H7)
十三、WWDG配置步骤
13.1、使能并初始化WWDG
使能WWDG,设置预分频系数和窗口值等
HAL库驱动函数:HAL_WWDG_Init()
/**
* @brief Initialize the WWDG according to the specified.
* parameters in the WWDG_InitTypeDef of associated handle.
* @param hwwdg pointer to a WWDG_HandleTypeDef structure that contains
* the configuration information for the specified WWDG module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg);
关键结构体
/**
* @brief WWDG Init structure definition
*/
typedef struct
{
uint32_t Prescaler; /*!< Specifies the prescaler value of the WWDG.
This parameter can be a value of @ref WWDG_Prescaler */
uint32_t Window; /*!< Specifies the WWDG window value to be compared to the downcounter.
This parameter must be a number Min_Data = 0x40 and Max_Data = 0x7F */
uint32_t Counter; /*!< Specifies the WWDG free-running downcounter value.
This parameter must be a number between Min_Data = 0x40 and Max_Data = 0x7F */
uint32_t EWIMode ; /*!< Specifies if WWDG Early Wakeup Interrupt is enable or not.
This parameter can be a value of @ref WWDG_EWI_Mode */
} WWDG_InitTypeDef;
13.2、窗口期喂狗
重装载计数器,即喂狗
HAL库驱动函数:HAL_WWDG_Refresh()
/**
* @brief Refresh the WWDG.
* @param hwwdg pointer to a WWDG_HandleTypeDef structure that contains
* the configuration information for the specified WWDG module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg);
十四、编程实战:验证窗口看门狗功能
验证思路:LED0 熄灭 LED1 闪烁说明正常喂狗,程序正常执行;LED1 熄灭 LED0 闪烁说明没有正常喂狗,程序反复执行复位
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 */
LED0(0); /* 点亮LED0(红灯) */
delay_ms(300); /* 延时100ms再初始化看门狗,LED0的变化"可见" */
wwdg_init(0X7F, 0X5F, WWDG_PRESCALER_8); /* 计数器值为7f,窗口寄存器为5f,分频数为8 */
while (1)
{
LED0(1); /* 关闭LED0(红灯) */
}
}
wdg.c
#include "./BSP/WDG/wdg.h"
WWDG_HandleTypeDef wwdg_handler; /* 窗口看门狗句柄 */
/**
* @brief 初始化窗口看门狗
* @param tr: T[6:0],计数器值
* @param tw: W[6:0],窗口值
* @note fprer:分频系数(WDGTB),范围:WWDG_PRESCALER_1~WWDG_PRESCALER_8,表示2^WDGTB分频
* Fwwdg=PCLK1/(4096*2^fprer). 一般PCLK1=42Mhz
* @retval 无
*/
void wwdg_init(uint8_t tr, uint8_t wr, uint32_t fprer)
{
wwdg_handler.Instance = WWDG;
wwdg_handler.Init.Prescaler = fprer; /* 设置分频系数 */
wwdg_handler.Init.Window = wr; /* 设置窗口值 */
wwdg_handler.Init.Counter = tr; /* 设置计数器值 */
wwdg_handler.Init.EWIMode = WWDG_EWI_ENABLE; /* 使能窗口看门狗提前唤醒中断 */
HAL_WWDG_Init(&wwdg_handler); /* 初始化WWDG */
}
/* WWDG底层驱动,时钟配置,中断配置 */
void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)
{
__HAL_RCC_WWDG_CLK_ENABLE(); /* 使能窗口看门狗时钟 */
HAL_NVIC_SetPriority(WWDG_IRQn, 2, 3); /* 抢占优先级2,子优先级为3 */
HAL_NVIC_EnableIRQ(WWDG_IRQn); /* 使能窗口看门狗中断 */
}
/* 窗口看门狗中断服务程序 */
void WWDG_IRQHandler(void)
{
HAL_WWDG_IRQHandler(&wwdg_handler); /* 调用WWDG共用中断处理函数 */
}
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
HAL_WWDG_Refresh(&wwdg_handler); /* 更新窗口看门狗值 */
LED1_TOGGLE(); /* 绿灯闪烁 */
}
wdg.h
#ifndef __WDG_H
#define __WDG_H
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
void wwdg_init(uint8_t tr, uint8_t wr, uint32_t fprer); /*窗口看门狗初始化*/
#endif