一、独立看门狗
1、独立看门狗
独立看门狗本质上是一个定时器,这个定时器有一个输出端,可以输出复位信号。
该定时器是一个 12 位的递减计数器,当计数器的值减到 0 的时候,就会产生一个复位信号。如果在计数没减到 0 之前,重置计数器的值的话,那么就不会产生复位信号,这个动作我们称为喂狗。
看门狗功能由 VDD 电压域供电,在停止模式和待机模式下仍然可以工作。
2、程序
/**
* @brief 初始化独立看门狗
* @param prer: IWDG_PRESCALER_4~IWDG_PRESCALER_256,对应 4~256 分频
* @arg 分频因子 = 4 * 2^prer. 但最大值只能是 256!
* @param rlr: 自动重装载值,0~0XFFF.
* @note 时间计算(大概):Tout=((4 * 2^prer) * rlr) / 40 (ms).
* @retval 无
*/
void iwdg_init(uint8_t prer, uint16_t rlr)
{
g_iwdg_handle.Instance = IWDG;
g_iwdg_handle.Init.Prescaler = prer; /* 设置 IWDG 分频系数 */
g_iwdg_handle.Init.Reload = rlr; /* 重装载值 */
HAL_IWDG_Init(&g_iwdg_handle);
}
/**
* @brief 喂独立看门狗
* @param 无
* @retval 无
*/
void iwdg_feed(void)
{
HAL_IWDG_Refresh(&g_iwdg_handle); /* 重装载计数器 */
}
int main(void)
{
HAL_Init(); /* 初始化 HAL 库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
led_init(); /* 初始化 LED */
key_init(); /* 初始化按键 */
delay_ms(100); /* 延时 100ms 再初始化看门狗,LED0 的变化可见 */
iwdg_init(IWDG_PRESCALER_64, 500); /* 预分频数为 64,重载值为 500,溢出时间约为 1s*/
LED0(0); /* 点亮 LED0(红灯) */
while(1)
{
if (key_scan(1) == WKUP_PRES) /* 如果 KEY_UP 按下,则喂狗,支持连按 */
{
iwdg_feed(); /* 喂狗 */
}
delay_ms(10);
}
}
二、窗口看门狗
1、窗口看门狗
窗口看门狗通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。
窗口看门狗跟独立看门狗一样,也是一个递减计数器,不同的是它们的复位条件不一样。窗口看门狗产生复位信号有两个条件:
1) 当递减计数器的数值从
0x40
减到
0x3F
时(
T6
位跳变到
0
)。
2) 当喂狗的时候如果计数器的值大于
W[6:0]
时,此数值在
WWDG_CFR
寄存器定义。
上述的两个条件详细解释是,当计数器的值减到 0x40 时还不喂狗的话,到下一个计数就会 产生复位,这个值称为窗口的下限值,是固定的值,不能改变。这个跟独立看门狗类似,不同的是窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值 W[6:0]由用户设置。窗口看门狗计数器的上限值和下限值就是窗口的含义,喂狗也必须在窗口之内,否则就会复位。
2、程序
/**
* @brief 初始化窗口看门狗
* @param tr: T[6:0],计数器值
* @param tw: W[6:0],窗口值
* @param fprer: 分频系数(WDGTB),范围:WWDG_PRESCALER_1~WWDG_PRESCALER_8,
* 表示 2^WDGTB 分频, Fwwdg=PCLK1/(4096*2^fprer). 一般 PCLK1=42Mhz
* @retval 无
*/
void wwdg_init(uint8_t tr, uint8_t wr, uint32_t fprer)
{
wwdg_handle.Instance = WWDG;
wwdg_handle.Init.Prescaler = fprer; /* 设置分频系数 */
wwdg_handle.Init.Window = wr; /* 设置窗口值 */
wwdg_handle.Init.Counter = tr; /* 设置计数器值 */
wwdg_handle.Init.EWIMode = WWDG_EWI_ENABLE; /* 使能窗口看门狗提前唤醒中断 */
HAL_WWDG_Init(&wwdg_handle); /* 初始化 WWDG */
}
void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)
{
__HAL_RCC_WWDG1_CLK_ENABLE(); /* 使能窗口看门狗时钟 */
HAL_NVIC_SetPriority(WWDG_IRQn, 2, 3); /* 抢占优先级 2,子优先级为 3 */
HAL_NVIC_EnableIRQ(WWDG_IRQn); /* 使能窗口看门狗中断 */
}
/**
* @brief 窗口看门狗中断服务程序
* @param 无
* @retval 无
*/
void WWDG_IRQHandler(void)
{
HAL_WWDG_IRQHandler(&g_wwdg_handle);
}
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef* hwwdg)
{
HAL_WWDG_Refresh(&g_wwdg_handle);/* 更新窗口看门狗值 */
LED1_TOGGLE(); /* LED1 闪烁 */
}
// 主函数
int main(void)
{
HAL_Init(); /* 初始化 HAL 库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为 115200 */
led_init(); /* 初始化 LED */
LED0(0); /* 点亮 LED0(红灯) */
delay_ms(300); /* 延时 100ms 再初始化看门狗,LED0 的变化可见 */
/* 计数器值为 7f,窗口寄存器为 5f,分频数为 8 */
wwdg_init(0X7F, 0X5F, WWDG_PRESCALER_8);
while(1)
{
LED0(1); /* 关闭 LED0(红灯) */
}
}