1.WDG简介
看门狗可以监控程序的运行状态,当程序因为设计漏洞、硬件故障、电磁干扰等原因,出现卡死或跑飞现象时,看门狗能及时复位程序,避免程序陷入长时间的罢工状态,保证系统的可靠性和安全性
看门狗本质是一个定时器,当指定时间范围内,程序没有执行喂狗(重复计数器)操作时,看门狗硬件电路就自动产生复位信号
STM32内置两个看门狗
独立看门狗(IWDG):独立工作,对时间精度要求较低
窗口看门狗(WWDG):要求看门狗在精确计时窗口起作用
IWDG独立看门狗 | WWDG窗口看门狗 | |
复位 | 计数器减到0后 | 计数器T[5:0]减到0后、过早重装计数器 |
中断 | 无 | 早期唤醒中断 |
时钟源 | LSI(40kHz) | PCLK1(36MHz) |
预分频系数 | 4、8、32、64、128、256 | 1、2、4、8 |
计数器 | 12位 | 6位(有效计数) |
超时时间 | 0.1ms~26214.4ms | 113us~58.25ms |
喂狗方式 | 写入键寄存器,重装固定值RLR | 直接写入计数器,写多少重装多少 |
防误操作 | 键寄存器和写保护 | 无 |
用途 | 独立工作,对时间精度要求较低 | 要求看门狗在精确计时窗口起作用 |
2.IWDG
键寄存器本质上是控制寄存器,用于控制硬件电路的工作
在可能存在干扰的情况下,一般通过在整个键寄存器写入特定值来代替控制寄存器写入一位的功能,以降低硬件电路受到干扰的概率
写入键寄存器的值 | 作用 |
0xCCCC | 启用独立看门狗 |
0xAAAA | IWDG_RLR中的值重新加载到计数器(喂狗) |
0x5555 | 解除IWDG_PR和IWDG_RPR的写保护 |
0x5555之外的值 | 启用IWDG_PR和IWDG_RPR的写保护 |
3.WWDG
递减计数器T[6:0]的值小于0x40时,WWDG产生复位
递减计数器T[6:0]在窗口W[6:0]外被重新装载时,WWDG产生复位
递减计数器T[6:0]等于0x40时可以产生早期唤醒中断(EWI),用于重装载计数器以避免WWDG复位
定期写入WWDG_CR寄存器(喂狗)以避免WWDG复位
4.案例
4.1独立看门狗
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key.h"
int main(void)
{
OLED_Init();
Key_Init();
OLED_ShowString(1,1,"IWDG TEST");
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET)
{
OLED_ShowString(2,1,"IWDGRST");
Delay_ms(500);
OLED_ShowString(2,1," ");
Delay_ms(100);
RCC_ClearFlag();
}
else
{
OLED_ShowString(3,1,"RST");
Delay_ms(500);
OLED_ShowString(3,1," ");
Delay_ms(100);
}
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_Prescaler_16);
IWDG_SetReload(2499); //1000ms
IWDG_ReloadCounter();
IWDG_Enable();
while(1)
{
Key_GetNum();
IWDG_ReloadCounter();
OLED_ShowString(4,1,"FEED");
Delay_ms(200);
OLED_ShowString(4,1," ");
Delay_ms(600);
}
}
4.2窗口看门狗
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key.h"
int main(void)
{
OLED_Init();
Key_Init();
OLED_ShowString(1,1,"WWDG TEST");
if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET)
{
OLED_ShowString(2,1,"WWDGRST");
Delay_ms(500);
OLED_ShowString(2,1," ");
Delay_ms(100);
RCC_ClearFlag();
}
else
{
OLED_ShowString(3,1,"RST");
Delay_ms(500);
OLED_ShowString(3,1," ");
Delay_ms(100);
}
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);
WWDG_SetPrescaler(WWDG_Prescaler_8);
WWDG_SetWindowValue(0x40 | 21);
WWDG_Enable(0x40 | 54);
while(1)
{
Key_GetNum();
OLED_ShowString(4,1,"FEED");
Delay_ms(20);
OLED_ShowString(4,1," ");
Delay_ms(20);
WWDG_SetCounter(0x40 | 54);
}
}