IWDG&WWDG

1. IWDG

(1) IWDG 简介

        独立看门狗本质上是一个定时器,这个定时器有一个输出端,可以输出复位信号。该定时 器是一个 12 位的递减计数器,当计数器的值减到 0 的时候,就会产生一个复位信号。如果在计 数没减到 0 之前,重置计数器的值的话,那么就不会产生复位信号,这个动作我们称为喂狗。 看门狗功能由 VDD 电压域供电,在停止模式和待机模式下仍然可以工作。

        STM32F10xxx支持三种复位形式,分别为系统复位、上电复位和备份区域复位。

        当发生以下任一事件时,产生一个系统复位:

        1. NRST引脚上的低电平(外部复位)

        2. 窗口看门狗计数终止(WWDG复位)

        3. 独立看门狗计数终止(IWDG复位)

        4. 软件复位(SW复位)

        5. 低功耗管理复位

(2) IWDG 框图

        从 IWDG 框图整体认知就是,IWDG 有一个输入(时钟 LSI),经过一个 8 位的可编程预分 频器提供时钟给一个 12 位递减计数器,满足条件就会输出一个复位信号。IWDG 内部输入/输 出信号如下表:

        STM32F103 的独立看门狗由内部专门的 40Khz 低速时钟(LSI)驱动,即使主时钟发生故 障,它也仍然有效。这里需要注意独立看门狗的时钟是一个内部 RC 时钟,所以并不是准确的 40Khz,而是在 30~60Khz 之间的一个可变化的时钟,只是我们在估算的时候,以 40Khz 的频率 来计算,看门狗对时间的要求不是很精确,所以,时钟有些偏差,都是可以接受的。

(3) IWDG 寄存器

⚫ 重载寄存器(IWDG_RLR)

(4) IWDG 溢出时间计算

(5) IWDG 配置步骤

1. HAL_IWDG_Init 函数

IWDG 的初始化函数,其声明如下:

HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg);

⚫ 函数描述: 用于初始化 IWDG。

⚫ 函数形参: 形参 1 是 IWDG 句柄,IWDG_HandleTypeDef 结构体类型,其定义如下:

typedef struct
{
 IWDG_TypeDef *Instance; /* IWDG 寄存器基地址 */
 IWDG_InitTypeDef Init; /* IWDG 初始化参数 */
} IWDG_HandleTypeDef;

1)Instance:指向 IWDG 寄存器基地址。

2)Init:IWDG 初始化结构体,用于配置计数器的相关参数。 

IWDG_InitTypeDef 这个结构体类型定义如下:

typedef struct
{
 uint32_t Prescaler; /* 预分频系数 */
 uint32_t Reload; /* 重装载值 */
} IWDG_InitTypeDef;

1)Prescaler:预分频系数,IWDG_PRESCALER_4 到 IWDG_PRESCALER_256。

2)Reload:重装载值,范围:0 到 0x0FFF。

⚫ 函数返回值: HAL_StatusTypeDef 枚举类型的值。

2. HAL_IWDG_Refresh 函数

HAL_IWDG_Refresh 函数是独立看门狗的喂狗函数。其声明如下:

HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg);

⚫ 函数描述: 用于把重装载寄存器的值重载到计数器中,喂狗,防止 IWDG 复位。

⚫ 函数形参: 形参 1 是 IWDG_HandleTypeDef 结构体指针类型的 IWDG 句柄。

⚫ 函数返回值: HAL_StatusTypeDef 枚举类型的值。

(6) IWDG 代码

1. iwdg.c

#include "./BSP/IWDG/iwdg.h"

IWDG_HandleTypeDef g_iwdg_handle;

/* IWDG初始化函数 */
void iwdg_init(uint8_t prep, uint16_t rlr)
{
    g_iwdg_handle.Instance = IWDG;
    g_iwdg_handle.Init.Prescaler = prep;
    g_iwdg_handle.Init.Reload = rlr;
    HAL_IWDG_Init(&g_iwdg_handle);
}

/* 喂狗函数 */

void iwdg_feed(void)
{
    HAL_IWDG_Refresh(&g_iwdg_handle);
}

2. main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/IWDG/iwdg.h"

int main(void)
{
    HAL_Init();                         /* 初始化 HAL 库 */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
    usart_init(115200);                 /* 串口初始化为115200 */
    
    printf("您还没有喂狗,请及时喂狗!!!\r\n");
    iwdg_init(IWDG_PRESCALER_32, 1250); /* 溢出时间约为1s */
    
    while(1)
    {
        delay_ms(1050);
        iwdg_feed();
        printf("已经喂狗!!!\r\n");
    }
}

2. WWDG

(1) WWDG 简介

        窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序 背离正常的运行序列而产生的软件故障。窗口看门狗跟独立看门狗一样,也是一个递减计数器, 不同的是它们的复位条件不一样。窗口看门狗产生复位信号有两个条件:

        1) 当递减计数器的数值从 0x40 减到 0x3F 时(T6 位跳变到 0)。

        2) 当喂狗的时候如果计数器的值大于 W[6:0]时,此数值在 WWDG_CFR 寄存器定义。

        上述的两个条件详细解释是,当计数器的值减到 0x40 时还不喂狗的话,到下一个计数就会 产生复位,这个值称为窗口的下限值,是固定的值,不能改变。这个跟独立看门狗类似,不同 的是窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上 限,上限值 W[6:0]由用户设置。窗口看门狗计数器的上限值和下限值就是窗口的含义,喂狗也 必须在窗口之内,否则就会复位。

(2)WWDG工作原理

        结合寄存器分析窗口看门狗的上限值和下限值。W[6:0] 是 WWDG_CFR 寄存器的低 7 位, 用于与递减计数器 T[6:0]比较的窗口值,也就是我们说的上限值,由用户设置。0x3F 就是下限 值,递减计数器达到这个值就会产生复位。T6 位就是 WWDG_CR 寄存器的位 6,即递减计数 器 T[6:0]的最高位。

       递减计数器的值递减过程中,当 T[6:0]>W[6:0]是不允许刷新 T[6:0] 的值,即不允许喂狗,否则会产生复位。只有在 W[6:0]<T[6:0]<0x3F这个时间可以喂狗,这就 是喂狗的窗口时间。当 T[6:0]=0x3F,即 T6 位为 0 这一刻,也会产生复位。

        上限值 W[6:0]是由用户自己设置,但是一定要确保大于 0x40,否则就不存在上图的窗口了, 下限值 0x40 是固定的,不可修改。

(3)WWDG 框图

        WWDG 有一个来自 RCC 的 PCLK1 输入时钟,经过一个 4096 的分频器(4096 分频在设计 时已经设定死了,图中并没有给出来,但我们可以通过查看寄存器 WWDG_CFR 的 WDGTB 位 的描述知道),再经过一个分频系数可选(1、2、4、8)的可编程预分频器提供时钟给一个 7 位 递减计数器,这里有两个输出信号。

(4) WWDG 超时时间计算

(5) WWDG 寄存器

⚫ 控制寄存器(WWDG_CR)

⚫ 配置寄存器(WWDG_CFR)

⚫ 状态寄存器(WWDG_SR)

        该寄存器用来记录当前是否有提前唤醒的标志。该寄存器仅有位 0 有效,其他都是保留位。 当计数器值达到 0x40 时,此位由硬件置 1。它必须通过软件写 0 来清除。对此位写 1 无效。即 使中断未被使能,在计数器的值达到 0x40 的时候,此位也会被置 1。

(6) WWDG配置步骤

1. HAL_WWDG_Init 函数

IWDG 的初始化函数,其声明如下:

 HAL_StatusTypeDef HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg);

⚫ 函数描述: 用于初始化 WWDG。

⚫ 函数形参: 形参 1 是 WWDG 句柄,WWDG_HandleTypeDef 结构体类型,其定义如下:

typedef struct
{
 WWDG_TypeDef *Instance; /* WWDG 寄存器基地址 */
 WWDG_InitTypeDef Init; /* WWDG 初始化参数 */
}WWDG_HandleTypeDef;

1)Instance:指向 WWDG 寄存器基地址。

2)Init:WWDG 初始化结构体,用于配置计数器的相关参数。

WWDG_InitTypeDef 这个结构体类型定义如下:

typedef struct
{
 uint32_t Prescaler; /* 预分频系数 */
 uint32_t Window; /* 窗口值 */
 uint32_t Counter; /* 计数器值 */
 uint32_t EWIMode; /* 提前唤醒中断使能 */
} WWDG_InitTypeDef;

1) Prescaler:预分频系数,WWDG_PRESCALER_1\ WWDG_PRESCALER_2\ WWDG_PRESCALER_4\ WWDG_PRESCALER_8 四个值,分别表示 1~8 分频。

2)Window:窗口值,即上限值。

3)Counter:计数器值,用于保存要设置计数器的值。

4)EWIMode:提前唤醒中断使能。

⚫ 函数返回值:HAL_StatusTypeDef 枚举类型的值。

2. HAL_WWDG_Refresh函数

函数 HAL_WWDG_Refresh 函数是窗口看门狗的喂狗函数。其声明如下:

HAL_StatusTypeDef HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg);

⚫ 函数描述: 该函数实际就是往 CR 寄存器重写 Counte 这个预先保存的计数器值。

⚫ 函数形参: 形参 1 是 WWDG_HandleTypeDef 结构体指针类型的 WWDG 句柄。

⚫ 函数返回值: HAL_StatusTypeDef 枚举类型的值。

窗口看门狗配置步骤

1)使能 WWDG 时钟

WWDG 不同于 IWDG,IWDG 有自己独立的 40Khz 时钟。而 WWDG 使用的是 PCLK1 的 时钟,需要先使能时钟。方法是:

__HAL_RCC_WWDG_CLK_ENABLE(); 

2)设置窗口值,分频数和计数器初始值

在 HAL 库中,这三个值都是通过函数 HAL_WWDG_Init 来设置的,详见本例程源码。

3)开启 WWDG

通过设置 WWDG_CR 寄存器的 WDGA(bit7)位为 1 来实现开启窗口看门狗,同样是在 HAL_WWDG_Init 函数里面实现。

4)使能中断通道并配置优先级

(如果开启了 WWDG 中断) WWDG 的中断也是通过 HAL_NVIC_EnableIRQ 函数使能,通过 HAL_NVIC_SetPriority 函 数设置优先级。

HAL 库同样为看门狗提供了 MSP 回调函数 HAL_WWDG_MspInit,一般情况下,步骤 1 和 步骤 4 的步骤,我们均放在该回调函数中。

5)编写中断服务函数

在最后,还是要编写窗口看门狗的中断服务函数,通过该函数来喂狗,喂狗要快,否则当 窗口看门狗计数器值减到 0X3F 的时候,就会引起软复位了。在中断服务函数里面也要将状态 寄存器的 EWIF 位清空。

窗口看门狗中断服务函数为:WWDG_IRQHandler,喂狗函数为:HAL_WWDG_Refresh。

6)重写窗口看门狗唤醒中断处理回调函数 HAL_WWDG_EarlyWakeupCallback

HAL 库定义了一个 WWDG 中断处理共用函数 HAL_WWDG_IRQHandler,我们在 WWDG 中断服务函数中会调用该函数。同时该函数会调用回调函数 HAL_WWDG_EarlyWakeupCallback, 提前唤醒中断逻辑(喂狗、闪灯)我们写在回调函数 HAL_WWDG_EarlyWakeupCallback 中。

(7)代码

wwdg.c

#include "./BSP/WWDG/wwdg.h"
#include "./BSP/LED/led.h"
#include "./SYSTEM/delay/delay.h"

WWDG_HandleTypeDef g_wwdg_handle;

/* 窗口看门狗初始化函数 */
/* WWDG_Init 是独立看门狗初始化函数,主要设置预分频数、窗口值和计数器的值,以及选
择是否使能窗口看门狗提前唤醒中断。 */
void wwdg_init(uint8_t tr, uint8_t wr, uint32_t fprer)
{
    g_wwdg_handle.Instance = WWDG;
    g_wwdg_handle.Init.Counter = tr;
    g_wwdg_handle.Init.Window = wr;
    g_wwdg_handle.Init.Prescaler = fprer;
    g_wwdg_handle.Init.EWIMode = WWDG_EWI_ENABLE;
    HAL_WWDG_Init(&g_wwdg_handle);
}

/* WWDG MSP 回调函数 */
/* 因为用到中断,我们用 HAL_WWDG_MspInit 函数来编写窗口看门狗中断的初始化代码。
当然大家也可以 HAL_WWDG_MspInit 函数的代码放到 wwdg_init 函数里面。这个初始化框架
就是 HAL 库的特点。HAL_WWDG_MspInit 函数会被 HAL_WWDG_Init 函数调用。该函数使能窗口看门狗的时
钟,并设置窗口看门狗中断的抢占优先级为 3,响应优先级为 2。 */
void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)
{
    __HAL_RCC_WWDG_CLK_ENABLE();
    
    HAL_NVIC_SetPriority(WWDG_IRQn, 3, 2);
    HAL_NVIC_EnableIRQ(WWDG_IRQn);
}

/* WWDG中断服务函数 */
void WWDG_IRQHandler(void)
{
    HAL_WWDG_IRQHandler(&g_wwdg_handle);
}
/* WWDG_IRQHandler 函数是窗口看门狗中断服务函数,而这个函数实际上就是调用 HAL 库
的中断处理函数 HAL_WWDG_IRQHandler。逻辑程序在下面的这个回调函数中: */
/* WWDG提前唤醒回调函数 */
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
    HAL_WWDG_Refresh(&g_wwdg_handle);
    LED1_TOGGLE();
}
/* 在回调函数内部调用 HAL_WWDG_Refresh 函数喂狗,并翻转 LED1。 */

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/WWDG/wwdg.h"

int main(void)
{
    HAL_Init();                             /* 初始化 HAL 库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    delay_init(72);                         /* 延时初始化 */
    usart_init(115200);                     /* 串口波特率为115200*/
    led_init();
    
    if(__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET)
    {
        printf("窗口看门狗复位\r\n");
        __HAL_RCC_CLEAR_RESET_FLAGS();
    }
    else
    {
        printf("外部复位\r\n");
    }
    
    delay_ms(1000);
    printf("请在窗口期内喂狗\r\n\r\n");
    wwdg_init(0x7f, 0x5f, WWDG_PRESCALER_8);    /* 0x7f->0x5f约为29ms,0x7f->0x3f约为58ms */
    
    while(1)
    {
        delay_ms(90);
        HAL_WWDG_Refresh(&g_wwdg_handle);
        LED0_TOGGLE();
    }
}

3. IWDG和WWDG的主要区别

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值