本篇总结
配置 WWDG 窗口看门狗,演示中断喂狗防复位 + 不喂狗触发系统复位两种场景。
🔑 KEIL MDK、UART调试、WWDG
硬件平台:本例程基于 W55MH32L-EVB 开发板运行。
采购推荐:点击前往 WIZnet 官方淘宝店铺 选购 W55MH32L-EVB
本示例演示 W55MH32 的窗口看门狗(WWDG)外设。与独立看门狗(IWDG)不同,WWDG 要求计数器值必须在一个窗口范围内(下限 0x40 ~ 上限 WR)才能喂狗——太早或太晚都会触发复位。本例程演示两种场景:(1) 通过提前唤醒中断(EWI)在窗口内喂狗,防止复位;(2) 故意不喂狗,观察 WWDG 触发系统复位。
超时时间公式
Twwdg = TPCLK1 × 4096 × 2WDGTB × (T[5:0] + 1)
当 PCLK1 = 36MHz、WDGTB = 3(分频 8)时,计数器减一格约 910μs,最大超时约 58.3ms。
前置工具准备
开始本例程前,请确认以下工具已安装:
- WIZ UartTool V1.0:串口调试工具:点击下载
硬件连接
WWDG 为芯片内部外设,无需外部引脚。仅需一根 Micro USB 线连接开发板 DEBUG USB 口到 PC,通过 USART1 串口日志观察看门狗触发与喂狗行为。
| 外设 | 总线 | 说明 |
| WWDG | APB1 | 窗口看门狗,计数器时钟 = PCLK1/4096/2^WDGTB |
| USART1 | APB2 | PA9(TX) / PA10(RX),板载 USB 转串口 |
工程结构
工程位于 SDK 内 1.SDK\ModuleDemo\WWDG\,核心文件如下:
WWDG/
├── USER/
│ ├── main.c ← WWDG初始化 + 中断喂狗/复位测试 + printf 重定向
│ ├── w55mh32_conf.h ← 外设头文件集中包含
│ ├── w55mh32_it.c/h ← 中断服务函数
│ ├── system_w55mh32.c/h← 系统初始化(时钟配置)
│ └── startup_w55mh32.s ← 启动文件
└── SYSTEM/
└── delay/
└── delay.c/h ← SysTick 延时函数
步骤1:USART 初始化(打印日志)
文件:USER/main.c | 函数:UART_Configuration() — 配置 USART1 用于打印时钟信息与看门狗日志。
void UART_Configuration(uint32_t bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* 开启外设时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* PA9: USART1_TX → 复用推挽输出 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* PA10: USART1_RX → 浮空输入 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* USART 参数:115200 / 8N1 / 全双工 */
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART_TEST, &USART_InitStructure);
USART_Cmd(USART_TEST, ENABLE);
}
四步完成:开时钟 → GPIO 引脚模式配置(TX 复用推挽,RX 浮空输入)→ USART 参数配置(115200 / 8N1)→ 使能外设。串口仅用于打印日志,方便观察喂狗与复位行为。
步骤2:WWDG 初始化(预分频器 + 窗口值 + 计数器)
函数:WWDG_Configuration() — 开启 WWDG 时钟,设置预分频器为 8、窗口上限 0x5F、计数器初值 0x7F。
void WWDG_Configuration(void)
{
/* 开启 WWDG 时钟(挂载在 APB1) */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
/* 预分频器 8:CNT_CK = PCLK1 / 4096 / 8 */
WWDG_SetPrescaler(WWDG_Prescaler_8);
/* 窗口上限 0x5F:计数器在 0x40~0x5F 之间喂狗才合法 */
WWDG_SetWindowValue(0x5F);
/* 使能 WWDG,初始计数器值 0x7F(最大值,T6 必须为 1) */
WWDG_Enable(0x7F);
}
三个关键参数:预分频器决定计数器减一格的时间(T = TPCLK1 × 4096 × 2WDGTB);窗口上限 WR 决定合法喂狗区间(0x40 ~ WR);计数器初值 TR 必须大于 WR 且 T6 位为 1(即 0x41~0x7F)。
如果你想自定义
- 改超时时间 → 修改
WWDG_SetPrescaler 参数为 WWDG_Prescaler_1/2/4/8,分频越大超时越长
- 改窗口范围 → 修改
WWDG_SetWindowValue 参数(0x41~0x7F),值越小窗口越宽,喂狗时机越宽松
步骤3:NVIC 配置与 WWDG 中断服务函数
函数:NVIC_Configuration() + WWDG_IRQHandler() — 配置 WWDG 中断优先级,并在中断中重装计数器(喂狗)。
/* NVIC 中断优先级配置 */
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/* WWDG 提前唤醒中断(EWI):计数器减到 0x40 时触发,此处喂狗防复位 */
void WWDG_IRQHandler(void)
{
WWDG_SetCounter(0x7F); /* 喂狗:重装计数器到最大值 */
WWDG_ClearFlag(); /* 清除中断标志,等待下一次触发 */
}
当计数器递减到 0x40(下限)时,若使能了提前唤醒中断(EWI),将触发 WWDG_IRQHandler。在中断中调用 WWDG_SetCounter(0x7F) 重装计数器即可避免复位——这也是"死前中断"的由来:进了这个中断说明程序已偏离正常序列。
中断喂狗的代价
中断喂狗虽能防复位,但若程序主循环跑飞、只剩中断在喂,看门狗就失去了监控意义。生产环境中应在中断里加上"看主循环是否正常运行"的判断,而非无条件喂狗。
步骤4:主函数 — 中断喂狗测试
文件:USER/main.c | 函数:main() — 初始化 USART → 配置 WWDG → 清标志 → 配置 NVIC → 使能 WWDG 中断 → 进入死循环等中断喂狗。
int main(void)
{
RCC_ClocksTypeDef clocks;
delay_init();
UART_Configuration(115200);
RCC_GetClocksFreq(&clocks);
printf("\n");
printf("SYSCLK: %3.1fMhz, HCLK: %3.1fMhz, PCLK1: %3.1fMhz, "
"PCLK2: %3.1fMhz, ADCCLK: %3.1fMhz\n",
(float)clocks.SYSCLK_Frequency / 1000000,
(float)clocks.HCLK_Frequency / 1000000,
(float)clocks.PCLK1_Frequency / 1000000,
(float)clocks.PCLK2_Frequency / 1000000,
(float)clocks.ADCCLK_Frequency / 1000000);
printf("WWDG Int Test.\n");
printf("Interrupt Feed Dog\n");
/* 配置 WWDG:预分频 8 / 窗口 0x5F / 计数器 0x7F */
WWDG_Configuration();
/* 使能提前唤醒中断 */
WWDG_ClearFlag();
NVIC_Configuration();
WWDG_EnableIT();
while (1); /* 主循环空转,由 EWI 中断自动喂狗 */
}
程序启动后打印时钟信息与测试提示,随后配置 WWDG 并使能 EWI 中断。主循环虽为空转,但每次计数器减到 0x40 时中断触发并重装计数器,系统不会复位。
步骤5:WWDG 复位测试(对比实验)
将上面的 main() 中"使能中断"三行去掉,主循环不喂狗——计数器减到 0x40 后无中断喂狗,WWDG 触发系统复位,程序重启。
int main(void)
{
RCC_ClocksTypeDef clocks;
delay_init();
UART_Configuration(115200);
RCC_GetClocksFreq(&clocks);
printf("\n");
printf("SYSCLK: %3.1fMhz, HCLK: %3.1fMhz, PCLK1: %3.1fMhz, "
"PCLK2: %3.1fMhz, ADCCLK: %3.1fMhz\n",
(float)clocks.SYSCLK_Frequency / 1000000,
(float)clocks.HCLK_Frequency / 1000000,
(float)clocks.PCLK1_Frequency / 1000000,
(float)clocks.PCLK2_Frequency / 1000000,
(float)clocks.ADCCLK_Frequency / 1000000);
printf("WWDG Reset Test.\n");
/* 配置 WWDG:预分频 8 / 窗口 0x5F / 计数器 0x7F */
WWDG_Configuration();
/* 不使能中断、不喂狗 → 计数器减到 0x40 触发系统复位 */
while (1);
}
与步骤4仅差三行(去掉 WWDG_ClearFlag / NVIC_Configuration / WWDG_EnableIT)。WWDG 使能后计数器开始递减,无喂狗则超时复位——串口会反复打印启动日志,形成"复位→打印→复位"的循环。
调试小技巧
若想在 WWDG_IRQHandler 中确认喂狗是否执行,可加一行 printf("[WWDG] Feed dog!\n");,串口会周期性打印该信息。
步骤6:printf 重定向
重写 fputc() 将 printf 输出重定向到 USART1,并自动在 \n 前补 \r 确保串口工具正确换行。
int fputc(int c, FILE *f)
{
if (c == '\n')
SER_PutChar('\r'); // 补回车,确保串口工具正确换行
return (SER_PutChar(c));
}
int SER_PutChar(int ch)
{
while (!USART_GetFlagStatus(USART_TEST, USART_FLAG_TC));
USART_SendData(USART_TEST, (uint8_t)ch);
return ch;
}
运行验证
打开 WIZ UartTool V1.0
,选择开发板对应 COM 口,波特率 115200 / 8N1,打开串口。
WIZ UartTool 串口输出 — WWDG 窗口超时复位测试
中断喂狗测试(步骤4代码):按 RESET 启动后,串口打印一次时钟信息与 "Interrupt Feed Dog",之后系统不再复位,主循环空转。若在中断中加了 printf 调试,会周期性看到 "[WWDG] Feed dog!"。
SYSCLK: 72.0Mhz, HCLK: 72.0Mhz, PCLK1: 36.0Mhz, PCLK2: 72.0Mhz, ADCCLK: 36.0Mhz
WWDG Int Test.
Interrupt Feed Dog
[WWDG] Feed dog!
[WWDG] Feed dog!
[WWDG] Feed dog!
...
WIZ UartTool 串口输出 — WWDG 窗口超时复位测试
复位测试(步骤5代码):串口会反复打印启动日志——每次 WWDG 超时复位后程序从头运行,形成"复位→打印→复位"的循环。
WIZ UartTool 串口输出 — WWDG 提前喂狗触发复位测试SSYSCLK: 72.0Mhz, HCLK: 72.0Mhz, PCLK1: 36.0Mhz, PCLK2: 72.0Mhz, ADCCLK: 36.0Mhz
WWDG Int Test.
Interrupt Feed Dog
SYSCLK: 72.0Mhz, HCLK: 72.0Mhz, PCLK1: 36.0Mhz, PCLK2: 72.0Mhz, ADCCLK: 36.0Mhz
WWDG Int Test.
Interrupt Feed Dog
SYSCLK: 72.0Mhz, ...
常见问题
Q: 复位测试中串口一直重复打印启动日志
这正是 WWDG 复位的预期表现——没有喂狗,计数器减到 0x40 后触发系统复位,程序从头运行。若想停止复位,回到步骤4的中断喂狗代码。
Q: 中断喂狗测试中 WWDG 仍触发复位
检查三步是否齐全:WWDG_ClearFlag() 清标志、NVIC_Configuration() 配中断优先级、WWDG_EnableIT() 使能 EWI 中断,缺一不可。另外确认 WWDG_IRQHandler 已在 w55mh32_it.c 或 main.c 中实现。
Q: 喂狗了但还是复位(窗口外喂狗)
WWDG 要求计数器值在 0x40 ~ 窗口上限(WR) 之间才能喂狗。若在计数器值大于 WR 时喂狗(太早),也会触发复位。本例 WR=0x5F,EWI 中断在计数器减到 0x40 时触发,正好在窗口内,不会出现此问题。若手动喂狗需注意时机。
Q: 超时时间太短,中断来不及处理
增大预分频器 WWDG_SetPrescaler 参数(如改为 WWDG_Prescaler_8),或降低 PCLK1 频率。超时时间 T = TPCLK1 × 4096 × 2WDGTB × (T[5:0]+1)。
Q: 串口无任何输出
确认 COM 口号正确、波特率 115200,下载后需按 RESET 键启动。若复位测试中日志一闪而过,可降低波特率或增大预分频器延长超时时间,便于观察。
总结
本文基于 W55MH32 的窗口看门狗(WWDG)演示了两种典型场景:
- WWDG 配置:预分频器 8 / 窗口上限 0x5F / 计数器初值 0x7F,超时时间由 TPCLK1 × 4096 × 2WDGTB × (T[5:0]+1) 决定
- 中断喂狗:使能 EWI 提前唤醒中断,计数器减到 0x40 时触发
WWDG_IRQHandler,在其中重装计数器防复位
- 复位测试:不使能中断、不喂狗,WWDG 超时后触发系统复位,程序反复重启
- 窗口概念:下限固定 0x40,上限由用户设置;计数器值必须在窗口内喂狗才合法,太早或太晚都会复位