窗口看门狗

一,窗口看门狗介绍

独立看门狗的喂狗范围 0-X(X由预分频器和重装载值决定,最大值为0xFFF)

独立看门狗相关介绍:传送门:独立看门狗

相比于独立看门狗,窗口看门狗限定了喂狗时间段(由喂狗上限和喂狗下限值限定的喂狗范围)
所以形象的称作窗口看门狗


二,为什么需要窗口看门狗

独立看门狗:在0-重载值之间任意时间都可以喂狗

     如果程序跑飞后又跑回正常
     或者跑乱的程序正好执行了刷新看门狗
     这样独立看门狗是不能检查到并复位芯片的

窗口看门狗:限制了喂狗时间

    如果程序跑飞并且在限制的时间段喂狗是很困难的
    从而保证了程序的正常运行

三,独立看门狗和窗口看门狗比较

独立看门狗:

 驱动:由LSI驱动,即使主时钟发生故障它仍有效

 适用场景:
      作为主程序之外能够完全独立工作
      对时间精度要求较低

窗口看门狗:

 驱动:由APB1时钟分频后得到时钟驱动

 适用场景:
      在精确计时窗口起作用的程序

四,独立看门狗工作原理

  这里写图片描述

参数:
     CNT:递减计数器
     窗口上限:寄存器设置
     窗口下限:0x3F

随时间推移,计数器值递减,经过上窗口W和下窗口

     重载值->上窗口:这段时间不允许喂狗,如果喂狗会使芯片复位
     上窗口->下窗口:这段时间允许喂狗,下窗口位固定值(0x3F)
     下窗口:进入下窗口会产生复位

T6位:
     0x3F=00111111
     在计数器到达0x3F之前第六位为1
     所以当计数器到达窗口下限前T6位为1,到达窗口下限后T6位为低电平

复位:
     当计数器到达窗口下限(喂狗失败),会产生MCU复位信号,使芯片复位

五,窗口看门狗复位分析

这里写图片描述

递减计数器时钟:
    时钟来源PCLK1
    由于PCLK1时钟频率过高/4096
    再经过预分频器WDGTB
    预分频后作为递减计数器时钟

WWDG_CR寄存器:
    T7:WDGA启动位-使能窗口看门狗
    T0-6 :6位递减计数器寄存器

WWDG_CFR寄存器:
    W0-6:设置窗口看门狗上窗口值

比较器:
    比较递减计数器CNT和上窗口寄存器大小关系
    递减计数器值>上窗口值  比较结果为1

分析一: 计数器值>上窗口值时,喂狗,会产生复位
  这里写图片描述
  

当计数器值>上窗口值时,比较器比较结果输出为1
此时喂狗,与门1下端输入为1
所以,或门1上端输入为1,导致与门2右端输入为1
此时看门狗处于使能状态,与门2左端输入为1
所以芯片产生复位

分析二: 计数器值到达0x3F,会产生复位

  复位分析2

当计数器值到达0x3F时,T6位从1跳变到0
或门1下端输入通过取反置1,所以或门1输出值为1,与门右侧输入值为1
此时看门狗处于使能状态,与门2左端输入为1
所以芯片产生复位

总结:窗口看门狗有两种情况会产生复位

1,喂狗时间大于窗口上限值
2,计数器值从0x40减到0x3F

如果启动看门狗并且允许中断,当递减计数器等于0x40时,会产生唤醒中断EWI,它可以用于喂狗避免WWDG复位

窗口看门狗使用注意

上窗口值W[6:0]必须大于下窗口值0x40(0x40产生唤醒中断),否则窗口看门狗就没有窗口了

六,窗口看门狗的超时时间

  这里写图片描述
  
时钟来源:

Fpclk1除以4096再经过WDGTB预分频器
f = Fpclk1 / (4096 * 2^WDGTB)

超时时间:

窗口看门狗时钟周期(时钟频率f分之1) * 
t = 1/f * 看门狗计数器重载值

七,窗口看门狗相关寄存器

 WWDG_CR

直接写WWDG_CR[6:0]实现喂狗
独立看门狗喂狗:向键值寄存器IWDG_KR写0xAAAA喂狗.将IWDG_RLR寄存器值重新装载到计数器

 WWDG_CFR

 位0-6设置上窗口值
 位7-8设置时基-窗口看门狗的时钟频率
 位9提前唤醒中断使能位(1:使能)当计数器到达0x40产生中断

 WWDG_SR

 WWDG_SR只用到位0:提前唤醒中断标志
 当计数器达到0x40时,由硬件置1,需软件清零

八,窗口看门狗相关库函数

stm32f10x_wwdg.h中找到相关函数头文件

/** @defgroup WWDG_Exported_Functions
  * @{
  */
void WWDG_DeInit(void);                          // 窗口看门狗复位
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler); // 设置预分频系数-WWDG_CFR[8:7]
void WWDG_SetWindowValue(uint8_t WindowValue);   // 设置上窗口值-WWDG_CFR[6:0]
void WWDG_EnableIT(void);                    // 使能窗口看门狗中断-提前唤醒中断WWDG_CFR[9]
void WWDG_SetCounter(uint8_t Counter);          // 喂狗-重新写WWDG_CR[6:0]
void WWDG_Enable(uint8_t Counter);               // 使能窗口看门狗并设置初值-WWDG_CR[7]+WWDG_CR[6:0]
FlagStatus WWDG_GetFlagStatus(void);             // 获取WWDG_SR寄存器标志位
void WWDG_ClearFlag(void);                       // 清除WWDG_SR寄存器标志位

九,窗口看门狗相关配置步骤

// 1,使能看门狗时钟:
    RCC_APB1PeriphClockCmd(); // 窗口看门狗时钟来自APB1时钟
// 2,设置分频系数:
    WWDG_SetPrescaler();      // 确定窗口看门狗时钟
// 3,设置上窗口值:
    WWDG_SetWindowValue();    // 设置上窗口值(下窗口值为0x3F)
// 4,开启提前唤醒中断并设置中断优先级:
    WWDG_EnableIT();          // 开启提前唤醒中断,当到达0x40时产生中断,在中断喂狗
    NVIC_Init();              // 使用中断要NVIC初始化(先进行中断优先级分组)
// 5,使能看门狗:
    WWDG_Enable();
// 6,喂狗:
    WWDG_SetCounter();
// 7,编写中断服务函数
    WWDG_IRQHandler();        // 在中断中喂狗

十,窗口看门狗代码:

HARDWARE/WDG目录新建wgd.h

#ifndef __WDG_H
#define __WDG_H
#include "sys.h"                      // 用到了u8 u32

void WWDG_Init(u8 tr,u8 wr,u32 fprer);// 初始化WWDG
void WWDG_Set_Counter(u8 cnt);        // 设置WWDG的计数器 - 喂狗
void WWDG_NVIC_Init(void);            // 初始化窗口看门狗中断优先级配置

#endif

HARDWARE/WDG目录新建wgd.c

#include "wdg.h"
#include "led.h"

//WWDG计数器值,默认为最大0x7F
u8 WWDG_CNT=0x7f;

//初始化窗口看门狗     
//  tr   : T[6:0],计数器值
//  wr   : W[6:0],窗口值
//  fprer: 分频系数(WDGTB),仅最低2位有效
//  Fwwdg = PCLK1 / (4096 * 2^fprer).
void WWDG_Init(u8 tr, u8 wr, u32 fprer)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  // WWDG时钟使能

    WWDG_CNT=tr&WWDG_CNT;             // 初始化WWDG_CNT (只取低7位,防止溢出)

    WWDG_SetPrescaler(fprer);         // 设置IWDG预分频值

    WWDG_SetWindowValue(wr);          // 设置窗口值

    WWDG_Enable(WWDG_CNT);            // 设置看门狗使能位,并第一次喂狗               

    WWDG_ClearFlag();                 // 清除提前唤醒中断标志位

    WWDG_NVIC_Init();                 // 窗口看门狗中断优先级设置

    WWDG_EnableIT();                  // 开启窗口看门狗中断
}

// 喂狗-重置WWDG计数器值
void WWDG_Set_Counter(u8 cnt)
{
    WWDG_Enable(cnt);        // 使能窗口看门狗并设置初值(首次喂狗)   
}

// 窗口看门狗中断服务程序
void WWDG_NVIC_Init()
{
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;            // WWDG中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  // 抢占2,子优先级3,组2   
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;         // 抢占2,子优先级3,组2   
    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;              // 使能
    NVIC_Init(&NVIC_InitStructure);                            // NVIC初始化
}

//计数器到达0x40时进入
void WWDG_IRQHandler(void)
{
    WWDG_SetCounter(WWDG_CNT);      // 注释此句,窗口看门狗将产生复位

    WWDG_ClearFlag();               // 清除提前唤醒中断标志位

    LED1=!LED1;                     // LED1状态翻转 - 指示喂狗成功
}

USER/main.c主函数编写


#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "wdg.h"


 int main(void)
 {       
    delay_init();          // 延时函数初始化

    // 设置中断优先级分组为组2:2位抢占优先级,2位响应优先级    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    uart_init(115200);     // 串口初始化为115200
    LED_Init();            // LED端口初始化
    KEY_Init();            // 按键初始化 

    LED0=0;                // LED0点亮
    delay_ms(300);         // 延时300ms

    // 计数器值为7f,窗口寄存器为5f,分频数为8
    WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);

    while(1)
    {
        LED0=1;            // LED0熄灭       
    }   
}

以上程序实现:

程序初始化LED点亮延时300ms熄灭
窗口看门狗从0x7F开始递减计数,上窗口为0x5F,下窗口为0x7F
计数器到达0x40进入提前唤醒中断,
在中断函数中进行喂狗操作,计数器翻转(从0x7F重新计数),LED1翻转
以此循环...
翻转频率为从0x7F计数到0x40,翻转时间可以根据公式计算

正常喂狗:
     LED0亮300ms之后熄灭,LED1不断闪烁

喂狗失败(注释掉喂狗函数):
     程序不断复位,LED0闪烁
  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BraveWangDev

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值