目录
[1. 计数器与窗口](#1. 计数器与窗口)
[2. 时钟计算](#2. 时钟计算)
[1. 初始化配置](#1. 初始化配置)
[2. 喂狗函数](#2. 喂狗函数)
[3. 早期唤醒中断配置(可选)](#3. 早期唤醒中断配置(可选))
[1. WWDG_SetPrescaler](#1. WWDG_SetPrescaler)
[2. WWDG_SetWindowValue](#2. WWDG_SetWindowValue)
[3. WWDG_Enable](#3. WWDG_Enable)
[4. WWDG_SetCounter](#4. WWDG_SetCounter)
[5. WWDG_EnableIT](#5. WWDG_EnableIT)
[6. WWDG_ClearFlag](#6. WWDG_ClearFlag)
[1. 窗口值设置](#1. 窗口值设置)
[2. 喂狗时机](#2. 喂狗时机)
[3. 早期唤醒中断](#3. 早期唤醒中断)
[4. 时钟依赖](#4. 时钟依赖)
八、常见问题与解决方案(question&&solution)
[Q1. 窗口看门狗总是复位](#Q1. 窗口看门狗总是复位)
[Q2. 早期唤醒中断不触发](#Q2. 早期唤醒中断不触发)
[Q3. 超时时间不准确](#Q3. 超时时间不准确)
独立看门狗复习入口
一、窗口看门狗基本概念

窗口看门狗(Window Watchdog,简称WWDG)是STM32微控制器中的另一种看门狗外设,与独立看门狗(IWDG)相比,具有 时间窗口限制的特点:
喂狗时机限制 :喂狗操作必须在特定的时间窗口内进行,太早或太晚都会触发复位
更高的安全性 :可以防止程序在错误的时间点喂狗(例如程序跑飞后进入死循环,定期喂狗但逻辑错误)
主时钟依赖 :使用APB1时钟(最高48MHz),速度更快
早期唤醒中断 :当计数器值降到窗口下限时,可触发中断,用于紧急处理
与独立看门狗不同的是, 独立看门狗是在独立计数器减至 0 前喂狗均为有效喂狗, CPU 不会复位。 而窗口看门狗只有在时间窗口范围内喂狗才为有效喂狗, 其余时间段均为无效喂狗, CPU 会执行复位。

主要特点
7位递减计数器 :从0x7F(127)开始递减,到0x3F(63)时触发复位
窗口机制 :只有当计数器值在窗口上限和窗口下限(0x40)之间时,喂狗才有效
早期唤醒中断 :计数器值降到0x40时触发,可用于在复位前执行紧急操作
时钟源 :使用APB1时钟经过预分频后的时钟,频率为PCLK1/(4096×预分频系数)
二、工作原理
1. 计数器与窗口
计数器 :7位递减计数器,范围0x7F-0x00
窗口上限 :由WWDG_CFR寄存器的W[6:0]位设置(必须大于0x40)
窗口下限 :固定为0x40(当计数器值≤0x40时,不能喂狗)
复位条件 :计数器值从0x40减到0x3F时
喂狗操作在窗口外执行时
2. 时钟计算
输入时钟 :PCLK1(APB1时钟,最高48MHz)
预分频系数 :可选1、2、4、8
计数器时钟 :
计数周期 :
超时时间 :
三、标准库使用步骤
1. 初始化配置
cpp
/**
* @brief 初始化窗口看门狗
* @param prescaler: 预分频系数,可选值:
* WWDG_Prescaler_1, WWDG_Prescaler_2, WWDG_Prescaler_4, WWDG_Prescaler_8
* @param windowValue: 窗口值(必须大于0x40,小于0x7F)
* @param counter: 计数器初始值(建议设置为0x7F)
* @retval 无
*/
void WWDG_Init(uint32_t prescaler, uint8_t windowValue, uint8_t counter)
{
// 使能WWDG时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
// 设置预分频系数
WWDG_SetPrescaler(prescaler);
// 设置窗口值
WWDG_SetWindowValue(windowValue);
// 设置计数器初始值并启用WWDG
WWDG_Enable(counter);
// 可选:启用早期唤醒中断
WWDG_EnableIT();
}
2. 喂狗函数
cpp
/**
* @brief 喂狗函数
* @param counter: 计数器值(建议设置为0x7F)
* @retval 无
* @note 必须在窗口时间内调用,否则会触发复位
*/
void WWDG_Feed(uint8_t counter)
{
// 喂狗,重置计数器
WWDG_SetCounter(counter);
}
3. 早期唤醒中断配置(可选)
cpp
/**
* @brief 配置WWDG早期唤醒中断
* @param 无
* @retval 无
*/
void WWDG_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// 配置WWDG中断
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);
}
// 早期唤醒中断处理函数
void WWDG_IRQHandler(void)
{
// 清除中断标志位
WWDG_ClearFlag();
// 在这里执行紧急操作,例如保存关键数据
// ...
// 喂狗(注意:必须在窗口时间内)
WWDG_Feed(0x7F);
}
四、完整使用示例
示例1:基本配置(无中断)
cpp
#include "stm32f10x.h"
#include "delay.h"
/**
* @brief 初始化窗口看门狗,超时时间约50ms
* @param 无
* @retval 无
*/
void WWDG_Init_50ms(void)
{
// 使能WWDG时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
// 设置预分频系数为8(PCLK1=36MHz时,WWDG时钟=36MHz/(4096×8)≈1.1kHz)
WWDG_SetPrescaler(WWDG_Prescaler_8);
// 设置窗口值为0x5F(当计数器值>0x5F时才能喂狗)
WWDG_SetWindowValue(0x5F);
// 启用WWDG,计数器初始值为0x7F
WWDG_Enable(0x7F);
}
int main(void)
{
// 系统初始化...
// 初始化窗口看门狗
WWDG_Init_50ms();
while(1)
{
// 正常程序代码...
// 模拟程序运行,确保在窗口时间内喂狗
delay_ms(10);
// 喂狗(必须在窗口时间内)
WWDG_SetCounter(0x7F);
// 模拟程序运行
delay_ms(30);
}
}
示例2:带早期唤醒中断的配置
cpp
#include "stm32f10x.h"
#include "delay.h"
/**
* @brief 初始化窗口看门狗
* @param 无
* @retval 无
*/
void WWDG_Init(void)
{
// 使能WWDG时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
// 配置NVIC
WWDG_NVIC_Config();
// 设置预分频系数为8
WWDG_SetPrescaler(WWDG_Prescaler_8);
// 设置窗口值为0x5F
WWDG_SetWindowValue(0x5F);
// 启用早期唤醒中断
WWDG_EnableIT();
// 启用WWDG,计数器初始值为0x7F
WWDG_Enable(0x7F);
}
/**
* @brief 配置WWDG中断
* @param 无
* @retval 无
*/
void WWDG_NVIC_Config(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中断处理函数
void WWDG_IRQHandler(void)
{
// 清除中断标志位
WWDG_ClearFlag();
// 执行紧急操作,例如保存数据
// ...
// 喂狗
WWDG_SetCounter(0x7F);
}
int main(void)
{
// 系统初始化...
// 初始化窗口看门狗
WWDG_Init();
while(1)
{
// 正常程序代码...
// 无需手动喂狗,由中断处理
delay_ms(40);
}
}
五、关键函数解析
1. WWDG_SetPrescaler
cpp
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);
功能 :设置窗口看门狗的预分频系数
参数 :
WWDG_Prescaler_1 :预分频系数1
WWDG_Prescaler_2 :预分频系数2
WWDG_Prescaler_4 :预分频系数4
WWDG_Prescaler_8 :预分频系数8
说明 :决定WWDG计数器的时钟频率
2. WWDG_SetWindowValue
cpp
void WWDG_SetWindowValue(uint8_t WindowValue);
功能 :设置窗口看门狗的窗口值
参数 :窗口值(必须大于0x40,小于0x7F)
说明 :喂狗操作必须在计数器值大于窗口值且大于0x40时进行
3. WWDG_Enable
cpp
void WWDG_Enable(uint8_t Counter);
功能 :启用窗口看门狗并设置初始计数器值
参数 :初始计数器值(建议设置为0x7F)
说明 :一旦启用,WWDG开始计数
4. WWDG_SetCounter
cpp
void WWDG_SetCounter(uint8_t Counter);
功能 :设置窗口看门狗的计数器值(喂狗)
参数 :计数器值(建议设置为0x7F)
说明 :必须在窗口时间内调用,否则会触发复位
5. WWDG_EnableIT
cpp
void WWDG_EnableIT(void);
功能 :启用窗口看门狗的早期唤醒中断
参数 :无
说明 :当计数器值降到0x40时触发中断
6. WWDG_ClearFlag
cpp
void WWDG_ClearFlag(void);
功能 :清除窗口看门狗的早期唤醒中断标志位
参数 :无
说明 :在中断处理函数中调用,清除中断标志
六、使用注意事项
1. 窗口值设置
必须大于0x40 :否则会触发复位
建议小于0x7F :留有足够的计数空间
2. 喂狗时机
必须在窗口时间内 :计数器值 > 窗口值 且 计数器值 > 0x40
避免在中断中喂狗 :除非使用早期唤醒中断,否则可能在窗口外喂狗
3. 早期唤醒中断
用途 :在复位前执行紧急操作,如保存关键数据
处理时间 :中断处理函数的执行时间必须小于从0x40到0x3F的计数时间,否则会触发复位
4. 时钟依赖
依赖APB1时钟 :若APB1时钟故障,WWDG可能无法正常工作
频率计算 :根据PCLK1频率和预分频系数,计算准确的计数周期
七、窗口看门狗与独立看门狗的对比

八、常见问题与解决方案(question&&solution)
Q1. 窗口看门狗总是复位
原因 :喂狗操作不在窗口时间内,或窗口值设置错误
解决 :检查窗口值是否大于0x40,调整喂狗时机
Q2. 早期唤醒中断不触发
原因 :未启用中断,或NVIC配置错误
解决 :确保调用 WWDG_EnableIT() 并正确配置NVIC
Q3. 超时时间不准确
原因 :APB1时钟频率与预期不符,或预分频系数计算错误
解决 :确认PCLK1频率,重新计算预分频系数和窗口值


