飞道的博客

看门狗定时器

338人阅读  评论(0)

看门狗定时器(WTD)

WTD概述

一般很多嵌入式设备工作在无人环境下,不能实时监测系统工作的状态,因此需要用看门狗定时器来自动检测重启设备。看门狗定时器是系统内部的定时器。

  • 看门狗定时器
    用于检测系统设备在受到噪声和系统误差等故障干扰造成设备死机,可以通过看门狗定时器产生一个复位信号 或 请求中断服务,自动恢复让系统重新运行。
  • WDT与PWM定时器的不同之处在于WDT产生复位信号。

WTD实现过程

1)PCLK经过一级分频器和二级选择器后产生看门狗时钟后,通过计数逻辑模块WTCNT,开始计数。

2)WTDAT是预先存放的计数初值,WTCNT是减量计数模块。当WTCNT从WTDAT赋的值减到0的时候,如果还没有更新重载WTCNT,则认为没有喂狗,系统死机产生reset复位信号。
注意:更新赋新值的寄存器是WTCNT,不是WTDAT。

3)发出reset 信号,强制系统重启

独立看门狗

注意:独立看门狗没有上限,只有下限,且IWDG没有中断,也没有ISR中断服务函数

https://www.cnblogs.com/pertor/p/9483445.html

https://blog.csdn.net/qq_35362464/article/details/53814711

窗口看门狗


窗口看门狗产生复位 2 中情况:
(1)CNT寄存器的值在WWDG_CFG之前,重新加载 CNT寄存器:上限,上限值必须大于0x40
(2)CNT值递减到0x40->0x3F时,导致T6位由1->0,产生MCU复位

注意:在CNT递减到0x40时,如果开启了EWI(early wakeup interrupt),则会产生提前唤醒中断,可在此中断中喂狗;中断标志flag需要手动软件清除WWDG_FLAG_EWIF

如果系统复位后,WWDG处于 close 状态,一旦激活WWDG则除非系统复位,否则无法关闭WWDG


注意:
(1)t pCLK1 是 经APB分频以后得到的,需要注意PCLK1是系统时钟经过多少分频得到的
(2)WDGTB取值为(0, 1 ,2, 3),分别对应PCLK1经过1/2/4/8分频得到WWDG的时钟源
(3)t[5:0]是最大值为0x3F,因此t[5:0]max = 0x3F = 63
(4)注意单位是毫秒ms
公式一般是:tWWDG = (1 / 32(或者/72)MHZ) * 4096 * (1/2/4/8)* (63 + 1)ms

代码

其中变量 ww_dog 可以根据用户自定义 控制喂狗时间

HAL库


/**---------------------------- 窗口看门狗(WWDG) ---------------------------*/
#define WINDOWS_VAL     70 
#define COUNTER_VAL     127
#define WWDG_TIME       300

static uint32_t ww_dog = WWDG_TIME;

/**
 * @brief 窗口看门狗的中断产生:上限和下限
 * WWDG Counter refresh is allowed between the following limits :
 * (++) min time (mS) = 1000 * (Counter - Window) * (4096 * Prescaler) / WWDG clock
 * (++) max time (mS) = 1000 * (Counter - 0x40)   * (4096 * Prescaler) / WWDG clock
 * max = 58.25ms
 * min = 51.88ms   ?
 */
WWDG_HandleTypeDef wwdg;

int wwdg_init(void)
{
   
    __HAL_RCC_WWDG_CLK_ENABLE();

    wwdg.Instance = WWDG;
    wwdg.Init.Prescaler = WWDG_PRESCALER_8;
    wwdg.Init.Window  = WINDOWS_VAL;
    wwdg.Init.Counter = COUNTER_VAL;
    wwdg.Init.EWIMode = WWDG_EWI_ENABLE;
    if (HAL_WWDG_Init(&wwdg) != HAL_OK) {
   
        printf("WWDG init fail\n");
        return -1;
    }

    HAL_NVIC_SetPriority(WWDG_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(WWDG_IRQn);
    return 0;
}

void WWDG_feedDog(void)
{
   
    ww_dog = WWDG_TIME;
}

/**
 * @brief ww_dog: 起控制窗口看门狗复位重启MCU的延迟时间,
 *                在一定时间内不喂狗,MCU会在(ww_dog * max_time毫秒)后复位
 */
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
   
    if (ww_dog > 0) {
   
        HAL_WWDG_Refresh(&wwdg);
        ww_dog--;
        // _debug(SYS_INFO,"ww_dog=%d",ww_dog);
    } else {
   
        _debug(SYS_EMERG, "fail wwdg refresh: ww_dog(%d)", ww_dog);
    }
}

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

/**
 * @brief (1)关闭WWDG中断
 *        (2)关闭WWDG的RCC时钟源
 *        (3)挂起wwdg_task任务
 * @attention (1)低功耗 (2)升级 都需要提前关闭wwdg
 */
void close_wwdg(void)
{
   
    HAL_NVIC_DisableIRQ(WWDG_IRQn);
    __HAL_RCC_WWDG_CLK_DISABLE();
}

void open_wwdg(void)
{
   
    HAL_NVIC_EnableIRQ(WWDG_IRQn);
    __HAL_RCC_WWDG_CLK_ENABLE();
}

STD标准库

///-------------窗口看门狗---------//


#define WWDOG_TIME 100 //大概5.8s左右 (58.25ms * 100)
#define WWDOG_H 70

static uint32_t ww_dog = WWDOG_TIME;

void Wwdong_Init(void)
{
   
    //return;
    NVIC_InitTypeDef NVIC_InitStructure;
    //时钟使能
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);

    WWDG_SetPrescaler(WWDG_Prescaler_8);
    /* Set Window value to 80; WWDG counter should be refreshed only when the counter
    is below 80 (and greater than 64 (0x40)) otherwise a reset will be generated */
    WWDG_SetWindowValue(WWDOG_H); //设置窗口比较值
    /* 
    72MHZ / 2 pre = 36Mhz
    4096 * 64 * 8 / 36 = 58.25 ms
     - On Value line devices,
    Enable WWDG and set counter value to 127, WWDG timeout = ~1366 us * 64 = 87.42 ms 
    In this case the refresh window is: ~1366us * (127-80) = 64.20 ms < refresh window < ~1366us * 64 = 87.42ms
     - On other devices
    Enable WWDG and set counter value to 127, WWDG timeout = ~910 us * 64 = 58.25 ms 
    In this case the refresh window is: ~910 us * (127-80) = 42.77 ms < refresh window < ~910 us * 64 = 58.25ms     
    */
    
   WWDG_Enable(0x7F);
   WWDG_ClearFlag();
    //注册中断
    NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    WWDG_EnableIT(); //使能窗口看门狗中断
    
}

void Wwdong_Uninit(void)
{
   
    ww_dog = WWDOG_TIME;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, DISABLE);
    //WWDG_ClearFlag();
    // WWDG_SetCounter(0x7F);//重设计时器值
}

void WWDG_FeedDog(void)
{
   
    ww_dog = WWDOG_TIME;
}

void WWDG_IRQHandler(void)
{
   
    WWDG_ClearFlag();	  //去除提前唤醒中断标志位   //用户代码
    if(ww_dog > 0){
   
        WWDG_SetCounter(0x7F);//重设计时器值
        ww_dog--;
    }
}

LL库


#define WWDG_CMP        0x70
#define WWDG_CNT        0x7F
#define WWDG_TIME       100     // 喂狗次数

static int wwdg_n = WWDG_TIME;

/**
 * @brief 32Mhz
 * tWWDG = (1 / 32Mhz) * 4096 * (2 ^ pre) * (t[5:0] + 1)  ms
 * tWWDG = 4096 * 64 * 8 = 65.536ms
 * t = tWWDG * 100 = 6.55s
 */
void wwdg_init(void)
{
   
  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_WWDG);

  LL_WWDG_SetCounter(WWDG, WWDG_CNT);
  LL_WWDG_SetPrescaler(WWDG, LL_WWDG_PRESCALER_8);
  LL_WWDG_SetWindow(WWDG, WWDG_CMP);
  LL_WWDG_Enable(WWDG);
  LL_WWDG_EnableIT_EWKUP(WWDG);

  /* WWDG interrupt Init */
  NVIC_SetPriority(WWDG_IRQn, 0);
  NVIC_EnableIRQ(WWDG_IRQn);
}

void WWDG_FeedDog(void)
{
   
    wwdg_n = WWDG_TIME;
}

void WWDG_IRQHandler(void)
{
   
    LL_WWDG_ClearFlag_EWKUP(WWDG);
    if (wwdg_n > 0) {
   
        LL_WWDG_SetCounter(WWDG, WWDG_CNT);
        wwdg_n--;
    }
}

转载:https://blog.csdn.net/m0_46170433/article/details/116452921
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场