STM32的看门狗

独立看门狗(IWDG)

IWDG简介

独立看门狗(Independent Watchdog,通常缩写为IWDG)主要作用是主要用于检测外界电磁干扰,或硬件****异常导致的程序跑飞问题

  • WDG本质上是一个12 位的递减计数器(滴答定时器24位递减计数器、通用定时器16位计数器)。当计数器的值从某个初始值开始递减,并一直减到0时,系统会产生一个复位信号(IWDG_RESET****)。CPU在接收到这个复位信号后,会重新启动系统,以确保系统从可能的错误或死锁状态中恢复。
  • 在计数器的值减到0之前,如果程序通过特定的"喂狗"操作(即重置计数器的值)来刷新计数器,那么就不会产生复位信号 ,系统将继续正常运行。这种"喂狗"操作通常是由程序在正常运行时定期执行的,以确保IWDG不会因计数器超时而产生复位信号。
  • 它使用专用的低速时钟(LSI):40KHz作为时钟源,即使在主时钟发生故障时,IWDG仍然能够继续运行。IWDG 可以在停止模式待机模式工作,确保在这些模式下系统仍然受到保护。

IWDG工作原理及框图

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

IWDG的寄存器

  • 键寄存器(IWDG_KR) - 控制寄存器
  • 在寄存器中不写0和1的原因?

在独立看门狗(Independent Watchdog Timer, IWDG)中,键寄存器(Key Register)的写入值被严格限制为特定值(如 0xAAAA0x55550xCCCC),而不允许直接写入 01 。这种设计的核心目的是通过硬件层面的安全机制,防止因软件错误或意外操作导致看门狗被错误配置或失效。以下是具体原因和机制:

关键点 说明
安全设计 通过硬件限制写入值,防止意外操作或恶意篡改。
硬编码逻辑 仅响应特定"密码"值(如 0xAAAA0x5555),其他值无效。
流程控制 强制按顺序操作(解锁→配置→锁定),避免配置错误。
抗干扰能力 程序跑飞时,随机写入 01 不会干扰看门狗运行。

启动看门狗后就不能随便弃养

  • 预分频寄存器**(IWDG_PR)**
  • 重装载寄存器**(IWDG_RLR)**
  • 状态寄存器**(IWDG_SR)**

IWDG库函数

  • HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg)

-------这个函数内部代码的执行逻辑:

  1. 开启看门狗
  1. 配置预分频寄存器和重装载寄存器

3.进行"喂狗" - 配置KEY寄存器

  • HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg)

------- 这个函数是进行"喂狗" - 自动重装载值得函数。

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

溢出时间计算

  • 公式:
  • 最大时间和最小时间:

配置步骤

小实验:独立看门狗喂狗实验

实验目的

配置 IWDG 溢出时间为 1 秒(根据表格中最长的溢出时间,来选择psc和rl的值)(psc =32,rl(arr)= **1250)**左右,并验证未及时喂狗时系统将被复位。

硬件清单

开发板、ST-Link、USB转TTL

  • 控制**/状态寄存器(RCC_CSR)**

文件代码

  • iwdg.c文件代码
cs 复制代码
#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);
}
  • iwdg.h文件代码
cs 复制代码
#ifndef __IWDG_H__
#define __IWDG_H__
#include "stm32f1xx.h"

void iwdg_init(uint8_t psc,uint16_t rlr);
void iwdg_feed(void);

#endif
  • main.c文件代码

实验1:0.5s进行一次喂狗

cs 复制代码
#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:检测是不是由看门狗引起的系统复位

cs 复制代码
#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简介

窗口看门狗用于监测单片机程序运行时效是否精准,主要检测软件异常,一般用于需要精准检测程序运行时间的场合。

  • 窗口看门狗的本质是一个能产生系统复位信号提前唤醒中断6位计数器。
  • 窗口期内 重装载计数器的值,防止复位,也就是所谓的 喂狗

产生复位条件:

  • 当递减计数器值从0x40 减到 0x3F 时复位(即T6位跳变到0);
  • 计数器的值大于W[6:0] 值时喂狗会复位。

产生中断条件:

  • 当递减计数器等于 0x40 可产生提前唤醒中断 (EWI)

0x40的来源:
看门狗是一个6位的计数器:但控制寄存器有7位,最高的当计数器的值减到0时,控制寄存器中的数100,000转换成二进制就是0x40。

0x3F的来源:

当看门狗计控制寄存器的第7位由1减到0时,000,000对应的二进制就是0x30。

WWDG****工作原理及框图

简图:

框图:

工作原理:

  1. 时间窗口定义

    • 窗口看门狗设定了一个允许喂狗的时间区间,通常由两个关键参数决定:

      • 窗口起点(T_start):计数器从初始值递减到某一阈值后,允许开始喂狗。

      • 窗口终点(T_end):计数器归零前必须完成喂狗的最后时刻。

    • 例如,若计数器初始值为0x7F(127),窗口起点可能设为**0x40** (64),终点为**0x3F**(63)时触发复位。

  2. 强制复位条件

    • 过早喂狗:在计数器值高于窗口起点时(如未进入窗口期)进行喂狗,触发复位。

    • 过晚喂狗:计数器递减至窗口终点后仍未喂狗,触发复位。

    • 正常喂狗:仅在计数器处于窗口期(T_start到T_end之间)时喂狗有效,重置计数器。

  3. 计数器递减机制

    • 窗口看门狗的计数器通常由系统时钟驱动,逐周期递减。

    • 若未及时喂狗,计数器溢出(例如从0x40减到0x3F)后触发复位。

WWDG****寄存器介绍

  • 控制寄存器**(WWDG_CR)**
  • 配置寄存器**(WWDG_CFR)**
  • 状态寄存器**(WWDG_SR)**

WWDG****函数介绍

  • HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg)
  • void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)
  • void HAL_WWDG_IRQHandler(WWDG_HandleTypeDef *hwwdg)
  • HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg)

WWDG****溢出时间计算

WWDG****配置步骤

小实验:窗口看门狗喂狗实验

实验目的

开启窗口看门狗,计数器值设置为 0X7F ,窗口值设置为 0X5F预分频系数为****8

计算出:

  • T[6:0]-W[6:0]到窗口的时间: 29.13ms;
  • W[6:0] -0x3F的时间:58.25ms。

实验现象:

  • 在****while 循环里喂狗同时翻转 LED1****状态
  • 提前唤醒中断服务函 数进行喂狗 ,同时翻转****LED2 状态。

硬件清单

上官二号、ST-Link、USB转TTL

文件代码

  • wwdg.c文件代码
cs 复制代码
#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); 
}
  • wwdg.h文件代码
cs 复制代码
#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
  • main.c文件代码
cs 复制代码
#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的区别

|-------------|------------------------|-----------------------|
| 对比点 | 独立看门狗 | 窗口看门狗 |
| 时钟源 | 独立时钟, LSI (40KHz) ,不精确 | PCLK1 ( 36MHz ),精确 |
| 复位条件 | 递减计数到 0 | 窗口期外喂狗或减到 0x3F |
| 中断 | 无 | 计数值减到 0x40 产生中断 |
| 递减计数器位数 | 12 位(最大计数范围: 4096~0 ) | 7 位(最大计数范围: 127~63 ) |
| 喂狗方式 | 写入键寄存器,重装固定值 RLR 直接 | 直接写入计数器,写多少重装多少 |
| 应用场合 | 防止程序跑飞,死循环,死机 | 检测程序时效,防止软件异常 |

相关推荐
武汉芯源半导体30 分钟前
新品发布 | 96MHz主频 M0+内核低功耗单片机CW32L011产品介绍
单片机·嵌入式硬件
仰泳之鹅39 分钟前
【STM32F1标准库】理论——通信协议:串口
stm32·单片机·嵌入式硬件
焦佩奇2 小时前
STM32裸机开发问题汇总
stm32·单片机·嵌入式硬件
CircuitWizard2 小时前
阿里云平台与STM32的物联网设计
stm32·物联网·阿里云
SZ1701102312 小时前
数据报(Datagram)与虚电路(Virtual Circuit)的区别
网络·单片机·嵌入式硬件
weixin_452813093 小时前
MCU怎么运行深度学习模型
单片机·嵌入式硬件·深度学习
每月一号准时摆烂3 小时前
数字电子技术基础(五十五)——D触发器
嵌入式硬件·fpga开发
qq_401700414 小时前
STM32开发printf函数支持
stm32
努力做小白4 小时前
4.系统定时器&基本定时器
stm32·单片机·嵌入式硬件
AIGC方案5 小时前
基于STM32F103的智能机械臂识别与控制项目(课件PPT+源代码)
stm32·嵌入式硬件·powerpoint