独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效。
IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。
自由运行的递减计数器
时钟由独立的RC振荡器提供(可在停止和待机模式下工作)
看门狗被激活后,则在计数器计数至0x000时产生复位
在键寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值 0xFFF递减计数。当计数器计数到末尾0x000时,会产生一个复位信号(IWDG_RESET)。 无论何时,只要在键寄存器IWDG_KR中写入0xAAAA, IWDG_RLR中的值就会被重新加载到 计数器,从而避免产生看门狗复位 。
由于独立看门狗是由LSI内部低速时钟提供振荡源,频率是40KHz,会经过预分频系数得到一个较小的频率,然后对重装载寄存器IWDG_RLR设定计数值,就能设定独立看门狗超时时间
例如:想要设定超时时间为2秒,则看上方表的最长时间,在32分频之后可以定时3秒多,但在16分频时定时才1.6秒左右,达不到2秒,所以选择32分频之后的预分频系数都满足要求,则
看门狗频率:40KHz / 32 = 1250Hz,也就是振动源振动1250次就定时1秒,那要定时2秒,就振动1250 * 2 = 2500次,所以重装载寄存器IWDG_RLR的设定值就为2500,这样就能使独立看门狗超过2秒后产生系统复位
经过上面的计算,定时2秒,所以预分频系数为32,重装载值为2500,便完成了独立看门狗的初始化
独立看门狗的初始化函数比较简单,就是把CubeMX设置的预分频系数和重装载值赋给结构体变量
/* Includes ------------------------------------------------------------------*/
#include "iwdg.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
IWDG_HandleTypeDef hiwdg;
/* IWDG init function */
void MX_IWDG_Init(void)
{
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_32;
hiwdg.Init.Reload = 2500;
if (HAL_IWDG_Init(&hiwdg) != HAL_OK)
{
Error_Handler();
}
}
HAL库的独立看门狗只有两个函数,一个是初始化函数,另一个是喂狗函数,在自己的程序中调用该喂狗函数,就能实现喂狗
点击喂狗函数的具体实现代码,就能看到函数底层是一个宏定义,实现功能是将IWDG_KEY_RELOAD写入键寄存器KR,这样IWDG_RLR寄存器中的值就会被重新加载到计数器,防止看门狗计数溢出复位
/**
* @brief Reload IWDG counter with value defined in the reload register
* (write access to IWDG_PR and IWDG_RLR registers disabled).
* @param __HANDLE__ IWDG handle
* @retval None
*/
#define __HAL_IWDG_RELOAD_COUNTER(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_RELOAD)
而IWDG_KEY_RELOAD的值也可查看到,是0xAAAA,与文章开头提到的独立看门狗功能描述一致
#define IWDG_KEY_RELOAD 0x0000AAAAu /*!< IWDG Reload Counter Enable */
看门狗喂狗标志初始化为TRUE,喂狗函数Feed直接调用HAL库函数的喂狗函数HAL_IWDG_Refresh即可
/* Includes ------------------------------------------------------------------*/
#include "MyApplication.h"
/* Private define-------------------------------------------------------------*/
/* Private variables----------------------------------------------------------*/
static void Feed(void);
/* Public variables-----------------------------------------------------------*/
MyIWDG_t MyIWDG =
{
TRUE,
Feed
};
/* Private function prototypes------------------------------------------------*/
/*
* @name Feed
* @brief 喂狗
* @param None
* @retval None
*/
static void Feed()
{
//喂狗操作
HAL_IWDG_Refresh(&hiwdg);
}
/********************************************************
End Of File
********************************************************/
自己定义的系统运行函数中,就通过判断标志位来调用喂狗函数
/*
* @name Run
* @brief 系统运行
* @param None
* @retval None
*/
static void Run()
{
/*省略获取SHT30温湿度并往串口打印部分代码*/
//独立看门狗喂狗操作
if(MyIWDG.IWDG_Feed_Flag == TRUE)
{
printf("喂狗,程序正在运行\r\n");
MyIWDG.Feed();
}
//延时
HAL_Delay(1000);
}
按键触发外部中断,将喂狗标志位IWDG_Feed_Flag清零,则停止喂狗,系统将复位
系统复位后,喂狗标志位IWDG_Feed_Flag又会被初始化为TRUE,所以在主函数中会执行喂狗操作,不会再造成系统复位
/*
* @name HAL_GPIO_EXTI_Callback
* @brief 外部中断回调函数
* @param GPIO_Pin:触发外部中断的引脚
* @retval None
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == KEY1_Pin)
{
MyIWDG.IWDG_Feed_Flag = FALSE;
LED.LED_Fun(LED2,LED_ON);
printf("停止喂狗,系统将复位!\r\n");
}
}
系统每隔一秒执行喂狗操作,程序正常运行,如果触摸按键1按下,则停止喂狗操作,稍后系统就会复位重启,会打印系统初始化信息,再通过喂狗让系统运行
在做低功耗产品时,不能使用独立看门狗,因为当系统处于待机或者停止状态时,不会进行喂狗,但独立看门狗依然会计数,就会让系统复位,无法保持低功耗模式
窗口看门狗由内部的PCLK1提供时钟,当系统待机时,PCLK也会停止工作,所以窗口看门狗也会停止工作,可以用来做低功耗产品