研二小白硬件学习Day8——IWDG实验(资源:正点原子STM32F407探索者开发板)
全称:Independent watchdog,即独立看门狗,其本质为能产生系统复位信号的计数器。特性:12位的递减计数器,时钟由独立的RC振荡器提供(可在待机和停止模式下运行)。当看门狗被激活后,当递减计数器计数到0x000时产生复位。如果在计数没减到0之前,重置计数器的值的话,那么就不会产生复位信号,这个动作我们称为喂狗。
一、基本介绍
全称:Independent watchdog,即独立看门狗,其本质为能产生系统复位信号的计数器。
特性:12位的递减计数器,时钟由独立的RC振荡器提供(可在待机和停止模式下运行)。当看门狗被激活后,当递减计数器计数到0x000时产生复位。
如果在计数没减到0之前,重置计数器的值的话,那么就不会产生复位信号,这个动作我们称为喂狗。
二、IWDG框图

从IWDG框图整体认知就是,IWDG有一个输入(时钟LSI),经过一个8位的可编程预分频器提供时钟给一个12位递减计数器,满足条件就会输出一个复位信号(iwdg1_out_rst)。
STM32F407 的独立看门狗由内部专门的32Khz低速时钟(lsi_ck)驱动,即使主时钟发生故障,它也仍然有效。这里需要注意独立看门狗的时钟是一个内部RC时钟,所以并不是准确的32Khz,而是在17~47Khz 之间的一个可变化的时钟,只是我们在估算的时候,以32Khz的频率来计算,看门狗对时间的要求不是很精确,所以,时钟有些偏差,都是可以接受的。
三、IWDG寄存器
1.关键字寄存器(IWDG_KR)——控制中心

-
作用:写入特定的值来触发不同操作。
-
特点:只写寄存器,读取无效。
| 写入值 | 操作 | 说明 |
|---|---|---|
0xCCCC |
启动看门狗 | 使能 IWDG,计数器开始从复位值 0xFFF 递减。 |
0x5555 |
解除写保护 | 允许修改 PR(预分频)和 RLR(重载)寄存器。 |
0xAAAA |
喂狗(重载计数器) | 将 RLR 的值重新加载到计数器,防止复位。同时会重新使能写保护。 |
注意:一旦写入
0xCCCC启动看门狗,就无法再关闭,除非复位芯片。
2.预分频寄存器(IWDG_PR)—— 时钟分频器

-
作用:设置看门狗时钟(LSI,通常 40kHz)的分频系数,从而决定计数器的计数速度。
-
位宽:32 位,但只有最低 3 位有效(
PR[2:0]),其他位保留。 -
写保护:默认受保护,必须先向 KR 写
0x5555才能修改。
3.重载寄存器(IWDG_RLR)—— 超时时间设定

-
作用:存放喂狗时加载到计数器的值。
-
位宽:32 位,但只有最低 12 位有效(
RL[11:0]),取值范围 0 ~ 0xFFF。 -
写保护:默认受保护,必须先向 KR 写
0x5555才能修改。 -
默认值:
0xFFF(最大计数值,最长时间)。
四、IWDG溢出时间计算


五、IWDG配置步骤

1. HAL_IWDG_Init 函数——独立看门狗初始化
函数原型HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg);
功能描述
初始化独立看门狗(IWDG),配置预分频系数和重装载值,并使能看门狗。调用该函数后,计数器开始递减,必须在超时前喂狗,否则系统复位。
形参说明
-
hiwdg:IWDG 句柄指针,类型为IWDG_HandleTypeDef,包含以下成员:
| 成员 | 类型 | 说明 |
|---|---|---|
Instance |
IWDG_TypeDef* |
IWDG 寄存器基地址(通常直接使用 IWDG)。 |
Init |
IWDG_InitTypeDef |
初始化配置结构体,包含两个成员: • Prescaler:预分频系数,可选值从 IWDG_PRESCALER_4 到 IWDG_PRESCALER_256,对应分频系数 4~256。• Reload:重装载值,12 位有效,范围 0 ~ 0x0FFF(0~4095)。该值决定看门狗的超时时间。 |
返回值HAL_StatusTypeDef 枚举值:
-
HAL_OK:初始化成功 -
HAL_ERROR:参数错误 -
HAL_BUSY:外设忙 -
HAL_TIMEOUT:操作超时
注意事项
-
该函数会向关键字寄存器写入
0xCCCC启动看门狗,同时自动处理写保护(写入0x5555以配置 PR 和 RLR)。 -
启动后无法关闭,除非复位芯片。
2. HAL_IWDG_Refresh 函数——喂狗
函数原型HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg);
功能描述
将重装载寄存器(RLR)的值重新加载到计数器中,即“喂狗”。调用该函数可以防止看门狗计数器减到 0 而产生复位。
形参说明
-
hiwdg:IWDG 句柄指针,与初始化时使用的句柄相同。
返回值HAL_StatusTypeDef 枚举值:
-
HAL_OK:喂狗成功 -
HAL_ERROR:参数错误(如句柄无效)
注意事项
-
该函数内部向关键字寄存器写入
0xAAAA完成重载操作,同时会自动重新使能写保护。 -
必须在看门狗超时前周期性调用此函数,否则系统复位。
-
建议在主循环或定时中断中调用,调用间隔应小于超时时间。
六、程序代码
1.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
2.wdg.c
#include "./BSP/WDG/wdg.h" // 包含独立看门狗的头文件,其中可能定义了相关的宏和函数声明
/* 独立看门狗句柄 */
IWDG_HandleTypeDef iwdg_handler; /* 定义一个IWDG句柄,用于HAL库操作独立看门狗
该句柄将在初始化函数和喂狗函数中使用 */
/**
* @brief 初始化独立看门狗
* @param prer: 预分频系数,可选值 IWDG_PRESCALER_4 ~ IWDG_PRESCALER_256,
* 对应分频系数 4、8、16、32、64、128、256
* @param rlr: 重装载值,范围 0 ~ 0xFFF(0~4095),决定看门狗超时时间
* @note 超时时间计算公式(近似):Tout = ((4 * 2^prer) * rlr) / LSI(Hz)
* 其中LSI通常为32kHz~40kHz,这里按32kHz估算,Tout单位ms:
* Tout = ((4 * 2^prer) * rlr) / 32 (ms)
* 例如:prer = IWDG_PRESCALER_64 (对应分频64),rlr = 4095,
* Tout = (64 * 4095) / 32 = 8190 ms ≈ 8.2秒
* @retval 无
*/
void iwdg_init(uint32_t prer, uint16_t rlr)
{
iwdg_handler.Instance = IWDG; /* 将句柄的Instance指向IWDG外设基地址 */
iwdg_handler.Init.Prescaler = prer; /* 设置预分频系数(决定计数时钟速度) */
iwdg_handler.Init.Reload = rlr; /* 设置重装载值(决定最大计数值) */
HAL_IWDG_Init(&iwdg_handler); /* 调用HAL库初始化函数,该函数会:
1. 向关键字寄存器写入0xCCCC,使能看门狗
2. 自动处理写保护(写入0x5555),设置PR和RLR
3. 启动计数器开始递减 */
}
/**
* @brief 喂独立看门狗
* @param 无
* @retval 无
* @note 必须在看门狗超时之前周期性调用此函数,否则系统复位
*/
void iwdg_feed(void)
{
HAL_IWDG_Refresh(&iwdg_handler); /* 调用HAL库喂狗函数,内部向关键字寄存器写入0xAAAA,
将重装载值重新加载到计数器,同时自动恢复写保护 */
}
给新手的补充说明
-
句柄的作用:
iwdg_handler是一个全局结构体变量,用于存储IWDG的配置信息和状态。初始化时设置其成员,喂狗时直接使用该句柄,方便HAL库函数操作。 -
预分频系数参数:
prer应使用HAL库定义的宏,如IWDG_PRESCALER_4、IWDG_PRESCALER_64等,不要直接写数字,以提高代码可读性。 -
超时时间计算:公式中的
4 * 2^prer就是实际的分频系数(例如IWDG_PRESCALER_64对应64分频)。LSI时钟频率因芯片而异,通常在30~60kHz,计算时建议留有余量,实际调试时可实测。 -
喂狗时机:
iwdg_feed()应在主循环或定时中断中定期调用,调用间隔必须小于看门狗超时时间。例如超时2秒,则每隔1.5秒喂狗一次。 -
注意事项:独立看门狗一旦启动(调用
HAL_IWDG_Init后)就无法关闭,除非复位MCU。因此务必保证喂狗逻辑正确,否则程序会不断复位。
3.main.c
#include "./SYSTEM/sys/sys.h" // 系统头文件:时钟、中断分组等基础函数
#include "./SYSTEM/usart/usart.h" // 串口头文件:串口初始化、printf支持
#include "./SYSTEM/delay/delay.h" // 延时头文件:提供毫秒级延时
#include "./BSP/LED/led.h" // LED驱动头文件:LED初始化及控制宏
#include "./BSP/KEY/KEY.h" // 按键驱动头文件:按键初始化及扫描函数
#include "./BSP/WDG/wdg.h" // 独立看门狗驱动头文件:看门狗初始化及喂狗函数
/**
* @brief 主函数:独立看门狗实验
* @param 无
* @retval 0
*/
int main(void)
{
HAL_Init(); // 初始化HAL库(设置SysTick、中断优先级分组等)
sys_stm32_clock_init(336, 8, 2, 7); // 配置系统时钟为168MHz
delay_init(168); // 初始化延时函数(传入系统时钟频率168MHz)
usart_init(115200); // 初始化串口1,波特率115200(可用于打印调试信息)
led_init(); // 初始化LED(PF9、PF10为推挽输出,默认关闭)
key_init(); // 初始化按键(PE2/3/4上拉输入,PA0下拉输入)
delay_ms(100); // 等待系统稳定,避免上电后立即喂狗失败
/* 初始化独立看门狗:
预分频系数 IWDG_PRESCALER_64 → 分频64
重装载值 500 → 计数器从500递减
超时时间计算(近似):
LSI 时钟约为 32kHz~40kHz,以40kHz为例:
计数时钟频率 = 40kHz / 64 = 625Hz,周期 ≈ 1.6ms
超时时间 = 500 × 1.6ms ≈ 800ms
即必须在800ms内喂狗,否则系统复位。
*/
iwdg_init(IWDG_PRESCALER_64, 500);
LED0(0); // 点亮红灯(LED0),作为程序正在运行的指示
while(1) // 主循环
{
/* 扫描按键(参数1表示支持连按模式)
如果检测到 WKUP 按键按下(PA0高电平),则执行喂狗 */
if(key_scan(1) == WKUP_PRES)
{
iwdg_feed(); // 喂狗:将重装载值500重新加载到计数器,防止复位
}
delay_ms(10); // 短暂延时,降低CPU占用率,同时控制按键扫描频率
}
}
实验现象说明
-
正常情况:程序启动后红灯点亮,看门狗开始计时。若在超时时间(约800ms)内按下 WKUP 键,则执行喂狗,计数器重置,红灯保持点亮,系统正常运行。
-
异常情况:如果不按 WKUP 键(或喂狗不及时),看门狗超时后会产生系统复位。复位后程序重新运行,LED0 会被再次初始化(默认熄灭),然后点亮红灯。如果观察到红灯闪烁一下又熄灭,说明发生了复位。可以利用这个现象观察看门狗的效果。
-
注意:由于看门狗一旦启动无法关闭,若想停止实验,需要断电或重新烧录程序。
超时时间验证
-
预分频 IWDG_PRESCALER_64 → 分频系数64
-
LSI 典型值 40kHz → 计数时钟 = 40kHz / 64 = 625 Hz,周期 1.6ms
-
重载值 500 → 超时时间 = 500 × 1.6ms = 800ms
-
实际LSI可能有误差(30~60kHz),因此超时时间在 640ms ~ 1280ms 之间波动,代码中预留的 800ms 是合理范围。
更多推荐



所有评论(0)