IWDG由内部专门的 32Khz 低速时钟(LSI) 驱动,
时钟是一个内部 RC时钟,所以并不是准确的 32Khz,而是在 15~47Khz 之间的一个可变化的时钟,只是我们在估算的时候,以 32Khz 的频率来计算。
相 关 的 库 函 数 操 作 函 数 在
文 件 stm32f4xx_hal_iwdg.c 和 对 应 的 头 文件stm32f4xx_hal_iwdg.h 中。
++++++++++++++++++++++++++++++++
取消写保护和设置预分频系数以及重装载值在 HAL 库中是通过函数 HAL_IWDG_Init 实现的。该函数声明为:
HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg);
入口参数 hiwdg,该参数是 IWDG_HandleTypeDef 结构体指针类型。这是IWDG的句柄。
typedef struct
{
IWDG_TypeDef *Instance;
IWDG_InitTypeDef Init;
HAL_LockTypeDef Lock;
__IO HAL_IWDG_StateTypeDef State;
}IWDG_HandleTypeDef;
成员变量 Instance 用来设置看门狗寄存器基地址,实际上在 HAL 库中已经通过标识符定义
了,这里对于独立看门狗直接设置为标识符 IWDG 即可。
成员变量 Init 是一个 IWDG_InitTypeDef 结构体类型,该结构体只有 2 个成员变量,分别用
来设置独立看门狗的预分频系数和重装载值,定义如下:
typedef struct
{
uint32_t Prescaler;
uint32_t Reload;
}IWDG_InitTypeDef;
成员变量 Lock 是一个锁存变量,该变量在 HAL 库中当操作配置 IWDG 之前设置为锁住
LOCK,当配置操作完成之后设置为 UNLOCK,实际上是一个操作状态标识符。
成员变量 State 也是 HAL 定义的一个过程标识符,用来记录 IWDG 处理状态。
++++++++++++++++++++++++++++++
HAL_IWDG_Init 函数使用的一般方法为:
IWDG_HandleTypeDef IWDG_Handler; //独立看门狗句柄
IWDG_Handler.Instance=IWDG; //独立看门狗
IWDG_Handler.Init.Prescaler=IWDG_PRESCALER_64; //设置 IWDG 分频系数
IWDG_Handler.Init.Reload=500; //重装载值
HAL_IWDG_Init(&IWDG_Handler);
上面程序的作用是初始化 IWDG,设置分频系数为 64,重装载值为 500。
Tout=((4× 2^prer) × rlr) /32
Tout 为看门狗溢出时间(单位为 ms); prer 为看门狗时钟预分频值(IWDG_PR 值),
范围为 0~7; rlr 为看门狗的重装载值(IWDG_RLR 的值);
设定 prer 值为 4( 4 代表的是 64 分频, HAL 库中可以使用宏定义标识符
IWDG_PRESCALER_64), rlr 值为 500,那么就可以得到 Tout=64× 500/32=1000ms,
只要在1秒钟之内,有一次或者多次写入 0XAAAA 到 IWDG_KR,就不会导致看门狗复位。
HAL 中重载计数值的函数是 HAL_IWDG_Refresh,该函数声明为:
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg);
它的作用是把值0xAAAA写入到IWDG_KR寄存器,从而触发计数器重载, 即实现独立看门狗的喂狗操作。
HAL 库函数里面启动独立看门狗的函数是 HAL_IWDG_Start:
HAL_StatusTypeDef HAL_IWDG_Start(IWDG_HandleTypeDef *hiwdg);
使能了看门狗,在程序里面就必须间隔一定时间喂狗,否则将导致程序复位。
+++++++++++++++++++++++++++++++++++++
WWDG通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。
递减计数器需要在一个有限的时间窗口中被刷新。
T[6:0]就是 WWDG_CR 的低七位, W[6:0]即是 WWDG->CFR 的低七位。
T[6:0]就是窗口看门狗的计数器,
W[6:0]则是窗口看门狗的上窗口(最大值0x7F),下窗口值是固定的(0X40)。
当窗口看门狗的计数器在上窗口值之上被刷新,或者低于下窗口值都会产生复位。当该计数器的值从 0X40 变为 0X3F 的时候,将产生看门狗复位。
Twwdg=(4096× 2^WDGTB× (T[5:0]+1)) /Fpclk1;
Twwdg: WWDG 超时时间(单位为 ms)
Fpclk1: APB1 的时钟频率(单位为 Khz)
WDGTB: WWDG 的预分频系数
T[5:0]:窗口看门狗的计数器低 6 位
计数周期(4096× 2^ WDGTB)
EWI 是提前唤醒中断,也就是在快要产生复位的前一段时间(T[6:0]=0X40) 来提醒我们,需要进行喂狗了,否则将复位!因此,我们一般用该位来设置中断,
当窗口看门狗的计数器值减到 0X40 的时候,如果该位设置,并开启了中断,则会产生中断,
在进入中断后, 必须在不大于 1 个窗口看门狗计数周期的时间(在 PCLK1 频率为 42M 且 WDGTB 为 0 的条件下,该时间为 97.52us)内重新写 WWDG_CR,否则,看门狗将产生复位!
++++++++++++++++++++++++++++++++
HAL 中用中断的方式来喂狗
HAL 库相关源码和定义分布在文件 stm32f4xx_hal_wwdg.c 文件和头文件 stm32f4xx_hal_wwdg.h 中。
使能 WWDG 时钟,
WWDG使用的是 PCLK1 的时钟,需要先使能时钟。方法是:
__HAL_RCC_WWDG_CLK_ENABLE(); //使能窗口看门狗时钟
设置窗口值,分频数和计数器初始值
HAL 库中,这三个值都是通过函数 HAL_WWDG_Init 来设置的。该函数声明如下:
HAL_StatusTypeDef HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg);
入口参数,是 WWDG_HandleTypeDef 结构体类型指针变量。这是WWDG的句柄。
WWDG_HandleTypeDef 结构体定义:
typedef struct
{
WWDG_TypeDef *Instance;
WWDG_InitTypeDef Init;
HAL_LockTypeDef Lock;
__IO HAL_WWDG_StateTypeDef State;
}WWDG_HandleTypeDef;
成员变量Init,它是 WWDG_InitTypeDef 结构体类型,该结构体定义如下:
typedef struct
{
uint32_t Prescaler; //预分频系数
uint32_t Window; //窗口值
uint32_t Counter; //计数器值
}WWDG_InitTypeDef;
HAL_WWDG_Init 的使用范例如下:
WWDG_Handler.Instance=WWDG; //窗口看门狗
WWDG_Handler.Init.Prescaler=WWDG_PRESCALER_8;//设置分频系数为 8
WWDG_Handler.Init.Window=0X5F; //设置窗口值 0X5F
WWDG_Handler.Init.Counter=0x7F; //设置计数器值 0x7F
HAL_WWDG_Init(&WWDG_Handler); //初始化 WWDG
++++++++++++++++++++++++++++++++++++
HAL 库中开启 WWDG 的函数有两个:
HAL_StatusTypeDef HAL_WWDG_Start(WWDG_HandleTypeDef *hwwdg);
HAL_StatusTypeDef HAL_WWDG_Start_IT(WWDG_HandleTypeDef *hwwdg);
HAL_WWDG_Start_IT 除了启动 WWDG,还同时启动 WWDG 中断。
使能中断通道并配置优先级
HAL_NVIC_SetPriority(WWDG_IRQn,2,3); //抢占优先级 2,子优先级为 3
HAL_NVIC_EnableIRQ(WWDG_IRQn); //使能窗口看门狗中断
跟 串 口 一 样 , HAL 库 同 样 为 看 门 狗 提 供 了 MSP 回 调 函 数HAL_WWDG_MspInit,
++++++++++++++++++++++++++++++++++++++
编写中断服务函数
看门狗的中断服务函数,通过该函数来喂狗,喂狗要快,否则当窗口看门狗计数器值减到 0X3F 的时候,就会引起软复位了。
窗口看门狗中断服务函数为:
void WWDG_IRQHandler(void);
HAL 库中,喂狗函数为:
HAL_StatusTypeDef HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg, uint32_t cnt);
++++++++++++++++++++++++++++++++++++++
重写窗口看门狗唤醒中断处理回调函数 HAL_WWDG_WakeupCallback
首先, HAL 库定义了一个中断处理共用函数HAL_WWDG_IRQHandler,我们在 WWDG 中断服务函数中会调用该函数。
该函数内部,会经过一系列判断,最后调用回调函数 HAL_WWDG_WakeupCallback,所以提前唤醒中断逻辑我们一般些在回调函数 HAL_WWDG_WakeupCallback 中。
回调函数声明为:
void HAL_WWDG_WakeupCallback(WWDG_HandleTypeDef* hwwdg);
+++++++++++++++++++++++++++++++++++++++++++++++
实例:
中断喂狗。
在ISR处理中,会调用callback,我们在callback中喂狗,以免产生软复位。
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef* hwwdg)
{
HAL_WWDG_Refresh(&WWDG_Handler);//更新窗口看门狗值
LED1=!LED1;
}
同时用灯的状态翻转,来作为输出的人机交互接口,提示我们执行了一次callback。