STM32之看门狗

1. 独立看门狗

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

• IWDG本质上是一个12 位递减的计数器 。当计数器的值从某个初始值 开始递减,并一直减到0时,系统会产生一个复位信号。CPU在接受到这个复位信号后,会重新启动系统,以确保系统从可能的错误或死锁的状态中恢复。

• 在计数器减到0之前,如果程序通过特定的"喂狗操作 "(即重置计数器的值)来刷新计数器,那么就不会产生复位信号,系统将继续正常的运行下去。这种"喂狗操作"通常是由程序在正常运行时定期执行的,确保IWDG不会因计数器超时而产生复位信号。

• IWDG使用专用的低速时钟 (LSI) 作为时钟源,即使主时钟发生故障,IWDG仍然能继续运行,IWDG可以在停止模式和待机模式下运行,确保在这些模式下系统仍然受到保护。

• 低速时钟(LSI)的频率是不准确的,频率范围大概在30khz-60khz,一般用40khz。

• 由于IWDG处于VDD 供电区,所以在停止和待机模式还能使用,因为VDD有一端是接VBAT的。

1.2 框图

1.3 IWDG溢出时间的计算,如图:

• Tout是表示溢出时间,rlr是重装载值,psc是预分频系数,fiwdg是IWDG的时钟频率。如图:

1.4 IWDG配置步骤

• 取消预分频器及重装载值寄存器写保护

• 设置IWDG预分频系数及重载值

• 启动IWDG

• 以上三条都在HAL_IWDG_Init()中设置,具体库函数已经配置了寄存器。

• 喂狗是HAL_IWDG_Refresh()

• 阅读HAL_IWDG_Init()的源码,主要是核心是这4步,启动IWDG,写使能,赋值PR和RLR寄存器,下面还有一次"喂狗操作"(没截取出来),如图:

• 喂狗是HAL_IWDG_Refresh()这个函数,实际里面是封装了__HAL_IWDG_RELOAD_COUNTER()这个宏函数,这个宏函数里面实际是,如图:

• 这是将重装载指令写入到KR寄存器,来重装载值。

1.5 实操 配置 IWDG 溢出时间为 1 秒左右,并验证未及时喂狗时系统将被复位。

• iwgd.c

cpp 复制代码
#include "iwdg.h"

IWDG_HandleTypeDef iwdg_handle = {0};
//初始化独自看门狗
void iwdg_init(uint16_t rlr,uint8_t psc){
    iwdg_handle.Instance = IWDG;
    iwdg_handle.Init.Prescaler = psc;
    iwdg_handle.Init.Reload = rlr;
    HAL_IWDG_Init(&iwdg_handle);
}

//喂狗操作 
void iwdg_feed(){
    HAL_IWDG_Refresh(&iwdg_handle);
}

• main.c

cpp 复制代码
#include "sys.h"
#include "uart1.h"
#include "delay.h"
#include "led.h"
#include "iwdg.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    uart1_init(115200);
    iwdg_init(625,IWDG_PRESCALER_64);
    //看门狗初始化那里32改成64 1250改成625 晶振不太稳 降低频率就可以了 
    printf("hello world\r\n");
    printf("狗儿肚子饿了饿了\r\n");
    if(__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != RESET ){
        printf("独立看门狗复位\r\n");
        __HAL_RCC_CLEAR_RESET_FLAGS();//软件清0,RCC_FLAG_IWDGRST位
    }else {
        printf("外部复位\r\n");
    }
    while(1)//流水灯实验
    { 
        delay_ms(1500);
        iwdg_feed();
        printf("狗儿吃饱了\r\n");
    }
}

2. 窗口看门狗

2.1 WWDG简介

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

• 窗口看门狗的本质是一个能产生系统复位信号 和提前唤醒中断 的6 位计数器。

• 产生复位的条件:

• 当计数器从0x40减到0x3F时复位(T6 位跳变到 0)。

• 计数器的值大于**W6:0**时喂狗会复位。(这里W6:0表示的时窗口值)。

• 产生中断的条件:当递减计数器等于0x40 时会产生提前唤醒中断 (EWI)。

2.2 "喂狗操作"

• "喂狗操作"是在窗口期内重装载计数器的值,防止复位,也就是喂狗。如图:

• 也就是说喂狗操作只能在窗口期。

2.3 框图:

2.4 溢出时间计算,如图:

• 注:这里是Twwdg是时间,不是频率,是频率的倒数。

2.5 WWDG配置步骤:

• 设置WWDG预分频系数,重装载值,窗口值(HAL_WWDG_Init())

• msp初始化(NVIC,CLOCK)

• 编写中断服务函数(WWDG_IRQHandler)

• 编写提前唤醒回调函数

• 喂狗(在窗口期)HAL_WWDG_Refresh()

• 阅读源码,HAL_WWDG_Init()的源码,下面是初始化函数最核心部分,这里调用了Msp函数,并且相应寄存器赋值,如图:

• "喂狗操作"的函数的源码,HAL_WWDG_Refresh()的源码,如图:

• 这是直接将值赋给CR寄存器。

2.6 实操 开启窗口看门狗,计数器值设置为 0X7F ,窗口值设置为 0X5F ,预分频系数为 8 。在 while 循环里喂狗,同时翻转 LED1 状态;在提前唤醒中断服务函数进行喂狗,同时翻转 LED2 状态。

• wwdg.c

cpp 复制代码
#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.Counter = tr;
    wwdg_handle.Init.EWIMode = WWDG_EWI_ENABLE;
    wwdg_handle.Init.Prescaler = psc;
    wwdg_handle.Init.Window = wr;
    HAL_WWDG_Init(&wwdg_handle);
}

void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg){
    if(hwwdg->Instance == WWDG){
        __HAL_RCC_WWDG_CLK_ENABLE();
        HAL_NVIC_SetPriority(WWDG_IRQn,2,0);
        HAL_NVIC_EnableIRQ(WWDG_IRQn);
    }

}

void wwdg_feed(){
    HAL_WWDG_Refresh(&wwdg_handle);
}

void WWDG_IRQHandler(){
    HAL_WWDG_IRQHandler(&wwdg_handle);
}

void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg){
    if(hwwdg->Instance == WWDG){
        wwdg_feed();
        led2_toggle();
    }

}

• main.c

cpp 复制代码
#include "sys.h"
#include "uart1.h"
#include "delay.h"
#include "led.h"
#include "wwdg.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    uart1_init(115200);
    wwdg_init(0x7F,0x5F,WWDG_PRESCALER_8);
    printf("hello world\r\n");
    if(__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET){
        printf("被窗口看门狗复位了\r\n");
        __HAL_RCC_CLEAR_RESET_FLAGS();
    }else {
        printf("外部复位\r\n");
    }
    while(1)
    { 
        delay_ms(30);
        wwdg_feed();
        led1_toggle();
    }
}

3. 独立看门狗和窗口看门狗的区别,如图:

相关推荐
皓月盈江6 分钟前
Linux Debian下STM32CubeProgrammer串口连接失败解决方案
linux·stm32·debian·串口下载·stm32f103c8t6·usb转ttl·stm32cubepro
深圳老胡11 分钟前
C语言实现C++面向对象程序设计示例
笔记·stm32·单片机·代码规范
2501_9226395812 分钟前
率能半导体 SS6226双通道直流电机驱动芯片:7.2V/1.4A双路,覆盖玩具、小家电、直流有刷电机三大应用场景
单片机·嵌入式硬件·硬件工程
LCG米20 分钟前
STM32时钟树配置实测:HSE起振失败回退HSI、PLL分频倍频计算与Flash等待周期陷阱
stm32·单片机·嵌入式硬件·嵌入式
巴巴媛6661 小时前
【Debug1】程序死机,while(1)循环,怎么办?
c语言·笔记·stm32·嵌入式硬件·bug
Lxx_Zw1 小时前
PID 用顺了,然后呢:增强手术与前馈
c语言·stm32·单片机·嵌入式硬件
张怀民3162 小时前
PFC_CCM_NCP1654详讲
单片机·嵌入式硬件·硬件工程·pfc
linweidong2 小时前
RTC 走偏、时间跳变?嵌入式时间管理的工程避坑
嵌入式硬件·面试·实时音视频·rtc·嵌入式面经·嵌入式ntp·嵌入式对时
Yiran_G2 小时前
ZigBee单播、广播与组播详解:从寻址机制到批量控制设计
嵌入式硬件·物联网·智能家居
youcans_3 小时前
【STM32C5教程】(9)DAC 模拟量信号输出实验
stm32·单片机·嵌入式硬件·stm32c5·cubemx2