一、基本介绍

全称: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,
                                           将重装载值重新加载到计数器,同时自动恢复写保护 */
}

给新手的补充说明

  1. 句柄的作用iwdg_handler 是一个全局结构体变量,用于存储IWDG的配置信息和状态。初始化时设置其成员,喂狗时直接使用该句柄,方便HAL库函数操作。

  2. 预分频系数参数prer 应使用HAL库定义的宏,如 IWDG_PRESCALER_4IWDG_PRESCALER_64 等,不要直接写数字,以提高代码可读性。

  3. 超时时间计算:公式中的 4 * 2^prer 就是实际的分频系数(例如 IWDG_PRESCALER_64 对应64分频)。LSI时钟频率因芯片而异,通常在30~60kHz,计算时建议留有余量,实际调试时可实测。

  4. 喂狗时机iwdg_feed() 应在主循环或定时中断中定期调用,调用间隔必须小于看门狗超时时间。例如超时2秒,则每隔1.5秒喂狗一次。

  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占用率,同时控制按键扫描频率
    }    
}

实验现象说明

  1. 正常情况:程序启动后红灯点亮,看门狗开始计时。若在超时时间(约800ms)内按下 WKUP 键,则执行喂狗,计数器重置,红灯保持点亮,系统正常运行。

  2. 异常情况:如果不按 WKUP 键(或喂狗不及时),看门狗超时后会产生系统复位。复位后程序重新运行,LED0 会被再次初始化(默认熄灭),然后点亮红灯。如果观察到红灯闪烁一下又熄灭,说明发生了复位。可以利用这个现象观察看门狗的效果。

  3. 注意:由于看门狗一旦启动无法关闭,若想停止实验,需要断电或重新烧录程序。

超时时间验证

  • 预分频 IWDG_PRESCALER_64 → 分频系数64

  • LSI 典型值 40kHz → 计数时钟 = 40kHz / 64 = 625 Hz,周期 1.6ms

  • 重载值 500 → 超时时间 = 500 × 1.6ms = 800ms

  • 实际LSI可能有误差(30~60kHz),因此超时时间在 640ms ~ 1280ms 之间波动,代码中预留的 800ms 是合理范围。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐