STM32看门狗功能详解
独立看门狗(IWDG)
IWDG简介
独立看门狗(Independent Watchdog,通常缩写为IWDG)主要作用是主要用于检测外界电磁干扰,或硬件异常导致的程序跑飞问题。
IWDG工作原理及框图


说明: 时钟源:LSI(40KHz)十分不精确,经过预分频器。计数器进行递减计数,当计数器减到0后,会进行系统复位。要即使的“喂狗” – 设置自动重装载的值。
IWDG的寄存器



在独立看门狗(Independent Watchdog Timer, IWDG)中,键寄存器(Key Register)的写入值被严格限制为特定值(如 0xAAAA、0x5555 或 0xCCCC),而不允许直接写入 0 或 1。这种设计的核心目的是通过硬件层面的安全机制,防止因软件错误或意外操作导致看门狗被错误配置或失效。以下是具体原因和机制:
| 关键点 | 说明 |
|---|---|
| 安全设计 | 通过硬件限制写入值,防止意外操作或恶意篡改。 |
| 硬编码逻辑 | 仅响应特定“密码”值(如 0xAAAA、0x5555),其他值无效。 |
| 流程控制 | 强制按顺序操作(解锁→配置→锁定),避免配置错误。 |
| 抗干扰能力 | 程序跑飞时,随机写入 0 或 1 不会干扰看门狗运行。 |
启动看门狗后就不能随便弃养






IWDG库函数

——-这个函数内部代码的执行逻辑:
- 开启看门狗

![]()
2. 配置预分频寄存器和重装载寄存器

3.进行“喂狗” – 配置KEY寄存器
![]()
![]()

——- 这个函数是进行“喂狗” – 自动重装载值得函数。

溢出时间计算 和 IWDG配置步骤
溢出时间计算


配置步骤

小实验:独立看门狗喂狗实验
实验目的
配置
IWDG
溢出时间为
1
秒(根据表格中最长的溢出时间,来选择psc和rl的值)(psc =32,rl(arr)=
1250)左右,并验证未及时喂狗时系统将被复位。
硬件清单
开发板、ST-Link、USB转TTL


文件代码
#include "iwdg.h"
//初始化看门狗
IWDG_HandleTypeDef iwdg_handle = {0};
void iwdg_init(uint8_t psc,uint16_t rlr){
iwdg_handle.Init.Prescaler = psc;
iwdg_handle.Init.Reload = rlr;
iwdg_handle.Instance = IWDG;
HAL_IWDG_Init(&iwdg_handle);
}
void iwdg_feed(void){
HAL_IWDG_Refresh(&iwdg_handle);
}
#ifndef __IWDG_H__
#define __IWDG_H__
#include "stm32f1xx.h"
void iwdg_init(uint8_t psc,uint16_t rlr);
void iwdg_feed(void);
#endif
实验1:0.5s进行一次喂狗
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "iwdg.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init(); /* LED初始化 */
uart1_init(115200);
printf("hello,world");
iwdg_init(IWDG_PRESCALER_32,1250);
printf("狗e了,该喂狗了\n");
while(1)
{
delay_ms(500); //时间溢出时间是1s,这里计0.5s时,进行重装载值。喂狗
iwdg_feed();
printf("狗子喂饱了\n");
}
}
实验2:检测是不是由看门狗引起的系统复位
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "iwdg.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init(); /* LED初始化 */
uart1_init(115200);
printf("hello,world");
iwdg_init(IWDG_PRESCALER_64,625);
printf("狗e了,该喂狗了\n");
if(__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != RESET){
printf("这是由于看门狗饿了引起的复位!!!\n");
__HAL_RCC_CLEAR_RESET_FLAGS();
}else
printf("其他复位!!!\n");
while(1)
{
delay_ms(2000); //时间溢出时间是1s,这里计0.5s时,进行重装载值。喂狗
iwdg_feed();
printf("狗喂饱了\r\n");
}
}
注意事项和出现的问题:
当进行1s的时间溢出时,分频写32,rlr写1250时。在while循环中延时函数Delay_ms(1500),不会进行系统复位。
解决方案1:psc = 64,rlr = 625。
原因:分频系数越高,输出时钟频率越低,对晶振稳定性的要求越低。(晶振有优劣)
解决方案2:在 iwdg_init(IWDG_PRESCALER_32,1250) 前后加上20ms的延时函数
好处:外设初始化稳定了,电源电压稳定了,时钟源稳定了,各种外设可能一定的时间才能稳定,没有延时可能导致时序问题,造成看门狗没有正常的初始化。
窗口看门狗(WWDG)
WWDG简介
窗口看门狗用于监测单片机程序运行时效是否精准,主要检测软件异常,一般用于需要精准检测程序运行时间的场合。
产生复位条件:
产生中断条件:
当递减计数器等于
0x40
时可产生提前唤醒中断
(EWI)
。
0x40的来源:
看门狗是一个6位的计数器:但控制寄存器有7位,最高的当计数器的值减到0时,控制寄存器中的数100,000转换成二进制就是0x40。
0x3F的来源:
当看门狗计控制寄存器的第7位由1减到0时,000,000对应的二进制就是0x30。
WWDG工作原理及框图
简图:

框图:


工作原理:
-
时间窗口定义
-
窗口看门狗设定了一个允许喂狗的时间区间,通常由两个关键参数决定:
-
窗口起点(T_start):计数器从初始值递减到某一阈值后,允许开始喂狗。
-
窗口终点(T_end):计数器归零前必须完成喂狗的最后时刻。
-
例如,若计数器初始值为
0x7F(127),窗口起点可能设为0x40(64),终点为0x3F(63)时触发复位。 -
强制复位条件
-
过早喂狗:在计数器值高于窗口起点时(如未进入窗口期)进行喂狗,触发复位。
-
过晚喂狗:计数器递减至窗口终点后仍未喂狗,触发复位。
-
正常喂狗:仅在计数器处于窗口期(T_start到T_end之间)时喂狗有效,重置计数器。
-
计数器递减机制
-
窗口看门狗的计数器通常由系统时钟驱动,逐周期递减。
-
若未及时喂狗,计数器溢出(例如从
0x40减到0x3F)后触发复位。
WWDG寄存器介绍






WWDG函数介绍





WWDG溢出时间计算

WWDG配置步骤

小实验:窗口看门狗喂狗实验
实验目的
开启窗口看门狗,计数器值设置为 0X7F ,窗口值设置为 0X5F ,预分频系数为 8 。
![]()
计算出:
实验现象:

硬件清单
上官二号、ST-Link、USB转TTL
文件代码
#include "wwdg.h"
#include "led.h"
WWDG_HandleTypeDef wwdg_handle = {0};
void wwdg_init(uint8_t tr,uint8_t wr,uint32_t psc){
wwdg_handle.Instance = WWDG;
wwdg_handle.Init.Prescaler = psc; //预分频器的值
wwdg_handle.Init.Counter = tr; //计数器的值
wwdg_handle.Init.EWIMode = WWDG_EWI_ENABLE; //提前唤醒中断
wwdg_handle.Init.Window = wr; //窗口的值
HAL_WWDG_Init(&wwdg_handle);
}
//配置MSP函数初始化MCU的相关外设
void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg){
if(hwwdg->Instance ==WWDG){ //判断这个函数是否被占用
__HAL_RCC_WWDG_CLK_ENABLE();
HAL_NVIC_SetPriority(WWDG_IRQn,2,2);
HAL_NVIC_EnableIRQ(WWDG_IRQn);
}
}
//配置中断服务函数
void WWDG_IRQHandler(void){
HAL_WWDG_IRQHandler(&wwdg_handle);
}
//中断回调函数
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg){
if(hwwdg->Instance == WWDG){
wwdg_feed();
led2_toggle();
}
}
//喂狗函数
void wwdg_feed(void){
HAL_WWDG_Refresh(&wwdg_handle);
}
#ifndef __WWDG_H__
#define __WWDG_H__
#include "stm32f1xx.h"
void wwdg_feed(void);
void wwdg_init(uint8_t tr,uint8_t wr,uint32_t psc);
#endif
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "wwdg.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init(); /* LED初始化 */
uart1_init(115200);
printf("hello,world");
wwdg_init(0x7f,0x5f,WWDG_PRESCALER_8);
if(__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET){
printf("窗口看门狗复位 \n");
__HAL_RCC_CLEAR_RESET_FLAGS();
}else
printf("其他复位!!!\n");
while(1)
{
delay_ms(30);
wwdg_feed();
led1_toggle();
}
}
IWDG与WWDG的区别
|
对比点 |
独立看门狗 |
窗口看门狗 |
|
时钟源 |
独立时钟, |
PCLK1 |
|
复位条件 |
递减计数到 |
窗口期外喂狗或减到 |
|
中断 |
无 |
计数值减到 |
|
递减计数器位数 |
12 |
7 |
|
喂狗方式 |
写入键寄存器,重装固定值 直接 |
直接写入计数器,写多少重装多少 |
|
应用场合 |
防止程序跑飞,死循环,死机 |
检测程序时效,防止软件异常 |
作者:许有杨

