学习来源----->江协科技STM32
WDG简介
- WDG(Watchdog)看门狗
- 看门狗可以监控程序的运行状态,当程序因为设计漏洞、硬件故障、电磁干扰等原因,出现卡死或跑飞现象时,看门狗能及时复位程序,避免程序陷入长时间的罢工状态,保证系统的可靠性和安全性
- 看门狗本质上是一个定时器,当指定时间范围内,程序没有执行喂狗(重置计数器)操作时,看门狗硬件电路就自动产生复位信号
- STM32内置两个看门狗
- 独立看门狗(IWDG):独立工作,对时间精度要求较低
- 窗口看门狗(WWDG):要求看门狗在精确计时窗口起作用
STM32F10xxx内置两个看门狗,提供了更高的安全性、时间的精确性和使用的灵活性。两个看门狗设备(独立看门狗和窗口看门狗)可用来检测和解决由软件错误引起的故障;当计数器达到给定的超时值时,触发一个中断(仅适用于窗口型看门狗)或产生系统复位。
独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效。窗口看门狗由从APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。
IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。 WWDG最适合那些要求看门狗在精确计时窗口起作用的应用程序。
IWDG主要性能
● 自由运行的递减计数器
● 时钟由独立的RC振荡器提供(可在停止和待机模式下工作)
● 看门狗被激活后,则在计数器计数至0x000时产生复位
IWDG框图 
1. 核心模块组成
- 寄存器模块 :
- 预分频寄存器(IWDG_PR):配置 8 位预分频器参数,对输入时钟(LSI)进行分频,调整计数器计数频率。
- 重装载寄存器(IWDG_RLR):存储 12 位重装载数值,用于初始化 12 位递减计数器的计数初值。
- 键寄存器(IWDG_KR):写入特定命令(如启动看门狗、喂狗操作),控制看门狗功能的开启与重置。
- 状态寄存器(IWDG_SR):记录看门狗状态标志(如计数器溢出标志),供软件查询。
- 时钟与计数模块 :
- LSI 时钟输入:采用 40 kHz 的低速内部时钟(LSI)作为独立看门狗的时钟源,确保在主时钟故障时仍能工作。
- 8 位预分频器:对 LSI 时钟分频,输出给 12 位递减计数器,扩展计数周期。
- 12 位递减计数器:根据预分频后的时钟递减计数,当计数到 0 时触发 IWDG 复位。
2. 工作流程
- 初始化配置:通过 IWDG_PR 设置预分频系数,通过 IWDG_RLR 设置重装载值,通过 IWDG_KR 写入命令启动看门狗。
- 计数与喂狗:计数器在预分频时钟驱动下递减,若系统正常运行,需定期通过 IWDG_KR 执行 "喂狗"(写入特定值),重新装载计数器初值,避免计数到 0。
- 复位触发:若未及时喂狗,计数器递减至 0 时,触发 IWDG 复位信号,强制系统重启。
3. 供电特性
图中红色标注强调:独立看门狗功能位于 VDD 供电区,即使系统进入停机或待机模式,仍能正常工作,确保在低功耗模式下也能监控系统状态,提升可靠性。
IWDG键寄存器
- 键寄存器本质上是控制寄存器,用于控制硬件电路的工作
- 在可能存在干扰的情况下,一般通过在整个键寄存器写入特定值来代替控制寄存器写入一位的功能,以降低硬件电路受到干扰的概率
|--------------|-------------------------|
| 写入键寄存器的值 | 作用 |
| 0xCCCC | 启用独立看门狗 |
| 0xAAAA | IWDG_RLR中的值重新加载到计数器(喂狗) |
| 0x5555 | 解除IWDG_PR和IWDG_RLR的写保护 |
| 0x5555之外的其他值 | 启用IWDG_PR和IWDG_RLR的写保护 |
键寄存器(IWDG_KR)是独立看门狗(IWDG)的核心控制寄存器,通过写入特定指令码实现以下功能:
- 启动看门狗 :向 IWDG_KR 写入
0xCCCC
,激活独立看门狗,使能内部 12 位递减计数器开始工作。 - 喂狗操作(重装载计数器) :系统正常运行时,需定期写入
0xAAAA
,触发计数器重新装载重装载寄存器(IWDG_RLR) 中的初始值,避免计数器递减至 0 引发复位。 - 寄存器写使能 :写入
0x5555
可临时使能对 预分频寄存器(IWDG_PR) 和 重装载寄存器(IWDG_RLR) 的写权限,允许修改预分频系数或重装载值,完成配置后写权限自动关闭,保障寄存器配置的安全性。
IWDG_KR 通过特定指令码实现对看门狗的启动、喂狗及寄存器配置控制,是软件与硬件看门狗交互的关键接口。
IWDG超时时间
写程序的时候超时时间要设置多少,要根据自己的项目来设置 ,如果没有特别要求,卡死后过个一两秒再复位也不影响的话,那这个超时时间可以设置大一点
- 超时时间:TIWDG = TLSI × PR预分频系数 × (RL + 1)
- 其中:TLSI = 1 / FLSI


WWDG简介
窗口看门狗通常被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在T6位变成0前被刷新,看门狗电路在达到预置的时间周期时,会产生一个MCU复位。在递减计数器达到窗口寄存器数值之前,如果7位的递减计数器数值(在控制寄存器中)被刷新, 那么也将产生一个MCU复位。这表明递减计数器需要在一个有限的时间窗口中被刷新。
WWDG功能描述
如果看门狗被启动(WWDG_CR寄存器中的WDGA位被置'1'), 并且当7位(T[6:0])递减计数器从0x40翻转到0x3F(T6位清零)时,则产生一个复位。如果软件在计数器值大于窗口寄存器中的数值时重新装载计数器,将产生一个复位。

WWDG工作特性
- 递减计数器T[6:0]的值小于0x40时,WWDG产生复位
- 递减计数器T[6:0]在窗口W[6:0]外被重新装载时,WWDG产生复位
- 递减计数器T[6:0]等于0x40时可以产生早期唤醒中断(EWI),用于重装载计数器以避免WWDG复位
- 定期写入WWDG_CR寄存器(喂狗)以避免WWDG复位

该窗口看门狗时序图展示了计数器递减过程、刷新窗口限制及复位触发逻辑,具体解读如下:
1. 计数器递减过程
- T [6:0] 递减计数器:从初始值开始持续递减,横坐标为时间,纵坐标为计数器值。
- 关键阈值 :
- W [6:0](窗口值):预设的上限阈值,定义 "不允许刷新" 与 "刷新窗口" 的分界。
- 0x3Fh:计数器的下限阈值(T6 位变为 0),若此时未完成喂狗,触发复位。
2. 刷新窗口限制
- 不允许刷新区间 :计数器值 > W[6:0] 时,若执行 "喂狗"(刷新计数器),会触发复位。这是因为此时刷新属于 "窗口外操作",违背时序要求。
- 刷新窗口区间 :计数器值处于 W[6:0] ~ 0x3Fh 时,允许通过写寄存器更新计数器(合法喂狗),避免计数器递减至 0x3Fh 触发复位。
3. T6 位与复位触发
- T6 位变化:当计数器递减至 0x3Fh 时,T6 位从 1 变为 0。
- 复位逻辑:若计数器到达 0x3Fh 仍未喂狗,硬件触发复位信号,强制系统重启,确保程序异常时恢复运行
WWDG超时时间
要根据自己的项目要求来设置,确定想要设置的超时时间(最晚时间)和窗口时间(最晚时间)
超时时间:
- TWWDG = TPCLK1 × 4096 × WDGTB预分频系数 × (T[5:0] + 1)
窗口时间:
- TWIN = TPCLK1 × 4096 × WDGTB预分频系数 × (T[5:0] - W[5:0])
- 其中:TPCLK1 = 1 / FPCLK1 =1/36MHz
计算方法和IDWG看门狗一样
IWDG和WWDG对比
|-------|--------------------|-------------------------|
| | IWDG 独立看门狗 | WWDG 窗口看门狗 |
| 复位 | 计数器减到0后 | 计数器T[5:0]减到0后、过早重装计数器 |
| 中断 | 无 | 早期唤醒中断 |
| 时钟源 | LSI(40KHz) | PCLK1(36MHz) |
| 预分频系数 | 4、8、32、64、128、256 | 1、2、4、8 |
| 计数器 | 12位 | 6位(有效计数) |
| 超时时间 | 0.1ms~26214.4ms | 113us~58.25ms |
| 喂狗方式 | 写入键寄存器,重装固定值RLR | 直接写入计数器,写多少重装多少 |
| 防误操作 | 键寄存器和写保护 | 无 |
| 用途 | 独立工作,对时间精度要求较低 | 要求看门狗在精确计时窗口起作用 |
独立看门狗程序
初始化IWDG
①开启LSI时钟(但是不需我们手动开启)

②写入键值0x5555解除写保护,然后再写入预分频值和重装载值
③写入键寄存器0xCCCC启动独立看门狗
④然后再主循环执行喂狗操作
cs
int main(void)
{
OLED_Init(); //OLED初始化
Key_Init(); //按键初始化
OLED_ShowString(1, 1, "IWDG TEST");
/*判断复位信号来源*/
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET) //如果是独立看门狗复位
{
OLED_ShowString(2, 1, "IWDGRST"); //OLED闪烁IWDGRST字符串
Delay_ms(500);
OLED_ShowString(2, 1, " ");
Delay_ms(100);
RCC_ClearFlag(); //清除标志位
}
else //否则,即为其他复位
{
OLED_ShowString(3, 1, "RST"); //OLED闪烁RST字符串
Delay_ms(500);
OLED_ShowString(3, 1, " ");
Delay_ms(100);
}
/*IWDG初始化*/
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //独立看门狗写使能
IWDG_SetPrescaler(IWDG_Prescaler_16); //设置预分频为16
IWDG_SetReload(2499); //设置重装值为2499,独立看门狗的超时时间为1000ms
IWDG_ReloadCounter(); //重装计数器,喂狗
IWDG_Enable(); //独立看门狗使能
while (1)
{
Key_GetNum(); //调用阻塞式的按键扫描函数,模拟主循环卡死
IWDG_ReloadCounter(); //重装计数器,喂狗
OLED_ShowString(4, 1, "FEED"); //OLED闪烁FEED字符串
Delay_ms(200); //喂狗间隔为200+600=800ms
OLED_ShowString(4, 1, " ");
Delay_ms(600);
}
}
独立看门狗超时时间计算 上面草稿有写,如果不懂就跳转视频看看:超时时间计算
相关函数:
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess)//启用或禁用对IWDG_PR和IWDG_RLR寄存器的写访问
|------------------|----------------------------|
| 参数 | 说明 |
| IWDG_WriteAccess | IWDG_PR和IWDG_RLR寄存器写访问的新状态 |
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler)//设置IWDG预分频值
|----------------|-------------|
| 参数 | 说明 |
| IWDG_Prescaler | 指定IWDG预分频器值 |

void IWDG_SetReload(uint16_t Reload)//设置IWDG 重装值
|--------|-----------------------------------|
| 参数 | 说明 |
| Reload | 指定IWDG的重装值,该参数必须为0 ~ 0x0FFF之间的数字 |
void IWDG_ReloadCounter(void)//用重新加载寄存器中定义的值重新加载IWDG计数器
void IWDG_Enable(void)//启用IWDG(开启对IWDG_PR和IWDG_RLR寄存器的写保护)
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)//检查是否设置了指定的RCC标志
|----------|----------|
| 参数 | 说明 |
| RCC_FLAG | 指定要检查的标志 |
窗口看门狗
WWDG初始化
①开启窗口看门狗ABP1的时钟
②配置各个寄存器(设置预分频和设置窗口值)
③写入控制寄存器CR(包含看门狗使能位,计数器标志溢出位,计数器有效位)
④最后,再运行过程中向计数器写入想要的计数重装值
cs
int main(void)
{
OLED_Init(); //OLED初始化
Key_Init(); //按键初始化
OLED_ShowString(1, 1, "WWDG TEST");
/*判断复位信号来源*/
if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET) //如果是窗口看门狗复位
{
OLED_ShowString(2, 1, "WWDGRST"); //OLED闪烁WWDGRST字符串
Delay_ms(500);
OLED_ShowString(2, 1, " ");
Delay_ms(100);
RCC_ClearFlag(); //清除标志位
}
else //否则,即为其他复位
{
OLED_ShowString(3, 1, "RST"); //OLED闪烁RST字符串
Delay_ms(500);
OLED_ShowString(3, 1, " ");
Delay_ms(100);
}
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //开启WWDG的时钟
/*WWDG初始化*/
WWDG_SetPrescaler(WWDG_Prescaler_8); //设置预分频为8
WWDG_SetWindowValue(0x40 | 21); //设置窗口值,窗口时间为30ms
WWDG_Enable(0x40 | 54); //使能并第一次喂狗,超时时间为50ms
while (1)
{
Key_GetNum(); //调用阻塞式的按键扫描函数,模拟主循环卡死
OLED_ShowString(4, 1, "FEED"); //OLED闪烁FEED字符串
Delay_ms(20); //喂狗间隔为20+20=40ms
OLED_ShowString(4, 1, " ");
Delay_ms(20);
WWDG_SetCounter(0x40 | 54); //重装计数器,喂狗
}
}
超时时间和窗口时间计算和独立看门狗一样:计算步骤
相关函数:
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler)//设置WWDG预分频器
|----------------|------------|
| 参数 | 说明 |
| WWDG_Prescaler | 指定WWDG预分频器 |

void WWDG_SetWindowValue(uint8_t WindowValue)//设置WWDG窗口值
|-------------|------------------------------|
| 参数 | 说明 |
| WindowValue | 指定要与下计数器进行比较的窗口值,该参数必须小于0x80 |
void WWDG_SetCounter(uint8_t Counter)//设置WWDG计数器值
|---------|----------------------------------|
| 参数 | 说明 |
| Counter | 看门狗计数器的值,该参数必须为0x40 ~ 0x7F之间的数字 |
void WWDG_Enable(uint8_t Counter)//启用WWDG窗口看门狗并加载计数器值
|---------|----------------------------------|
| 参数 | 说明 |
| Counter | 看门狗计数器的值,该参数必须为0x40 ~ 0x7F之间的数字 |