目录
一、介绍
WDG(Watchdog)看门狗被启动后无法关闭,除非系统复位修改初始化
看门狗可以监控程序的运行状态,当程序因为设计漏洞、硬件故障、电磁干扰等原因,出现卡死或跑飞现象时,看门狗能及时复位程序,避免程序陷入长时间的罢工状态
看门狗本质上是一个定时器,当指定时间范围内,程序没有执行喂狗(重置计数器)操作时,看门狗硬件电路就自动产生复位信号 STM32内置两个看门狗
- 独立看门狗(IWDG):独立工作,对时间精度要求较低
- 窗口看门狗(WWDG):要求看门狗在精确计时窗口起作用
时钟树:
HSI (内部高速时钟):8M。 (配合PLL倍频,通常为72MHz)
HSE(外部高速时钟):4MHz。
LSE(外部低速时钟):32KHz。(可用于RTC时钟)
LSI (外部低速时钟):40kHz。 (可用于独立看门狗)
时钟源:独立看门狗由 LSI 时钟(这里是40KHz) ,窗口看门狗由 APB1 时钟(36MHz)提供
二、独立看门狗
1、IWDG主要性能
- 自由运行的递减计数器
- 时钟由独立的RC振荡器提供(可在停止和待机模式下工作)
- 看门狗被激活后,则在计数器计数至0x000时产生复位
看门狗时钟:如果独立看门狗已经由硬件选项或软件启动, LSI振荡器将被强制在打开状态,并且不能被关闭。在LSI振荡器稳定后,时钟供应给IWDG。(函数:IWDG_Enable(); )
2、框图
3、键寄存器
- 键寄存器本质上是控制寄存器,用于控制硬件电路的工作
- 在可能存在干扰的情况下,一般通过在整个键寄存器写入特定值来代替控制寄存器写入一位的功能,以降低硬件电路受到干扰的概率
4、超时时间
超时时间:TIWDG = TLSI × PR预分频系数 × (RL + 1)
其中:TLSI = 1 / FLSI (FLSI:40KHz)
第一行最短时间0.1ms: = 1/40000 * 4 * (0+1)
第一行最长时间409.6ms: = 1/40000 * 4 * (4095+1)
5、示例代码
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
Key_Init(); //按键初始化
/*判断复位信号来源*/
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET) //如果是独立看门狗复位
{
OLED_ShowString(2, 1, "IWDGRST"); //OLED闪烁IWDGRST字符串
Delay_ms(500);
OLED_ShowString(2, 1, " ");
Delay_ms(100);
RCC_ClearFlag(); //清除标志位
}
else //否则,即为其他复位
{
OLED_ShowString(3, 1, "RST"); //OLED闪烁RST字符串
Delay_ms(500);
OLED_ShowString(3, 1, " ");
Delay_ms(100);
}
/*IWDG初始化*/
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //独立看门狗写使能
IWDG_SetPrescaler(IWDG_Prescaler_16); //设置预分频为16
IWDG_SetReload(2499); //设置重装值为2499,独立看门狗的超时时间为1000ms
IWDG_ReloadCounter(); //重装计数器,喂狗
IWDG_Enable(); //独立看门狗使能
while (1)
{ //调用阻塞式的按键扫描函数,模拟主循环卡死
Key_GetNum(); //若按键不放,程序卡死,等待看门狗复位
//若按键松开,下面正常喂狗
IWDG_ReloadCounter(); //重装计数器,喂狗
OLED_ShowString(4, 1, "FEED"); //OLED闪烁FEED字符串
Delay_ms(200); //喂狗间隔为200+600=800ms
OLED_ShowString(4, 1, " ");
Delay_ms(600);
}
}
三、窗口看门狗
- IWDG过晚喂狗会复位,WWDG过早或过晚喂狗都会产生复位
- IWDG时钟精确度要求不高,一般都有误差; WWDG对时钟精确度要求高一些
1、WWDG主要特性
可编程的自由运行递减计数器
● 条件复位 (若窗口看门狗被启动)
─ 当递减计数器的值小于0x40(T6为0),则产生复位
─ 当递减计数器在窗口外被重新装载(T6:T0>W6:W0), 则产生复位
● 如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可
以被用于重装载计数器以避免WWDG复位
2、框图
3、WWDG工作特性
- 递减计数器T[6:0]的值小于0x40时,WWDG产生复位
- 递减计数器T[6:0]在窗口W[6:0]外被重新装载时,WWDG产生复位
- 递减计数器T[6:0]等于0x40时可以产生早期唤醒中断(EWI),用于重装载计数器以避免WWDG复位
- 定期写入WWDG_CR寄存器(喂狗)以避免WWDG复位
4、超时时间
由于APB1时钟:36MHz对于看门狗过高,默认已经设置先12分频过了(4096)
超时时间:
TWWDG = TPCLK1 × 4096 × WDGTB预分频系数 × (T[5:0] + 1)
窗口时间:
TWIN = TPCLK1 × 4096 × WDGTB预分频系数 × (T[5:0] - W[5:0])
其中:TPCLK1 = 1 / FPCLK1
5、示例代码
超时时间(50ms)、窗口时间(30ms)计算:
由上面图知,WDGTB需取3,即预分频 = 2 ^ WDGTB = 8
1、先计算超时时间:50ms = 1/36M * 4096 * 预分频 * ( T[5:0] + 1 )
预分频取8(2^3),则 T[5:0] 为 54—— WWDG_Enable(0x40 | 54);
2、计算窗口时间:30ms = 1/36M * 4096 * 预分频 * (T[5:0] - W[5:0])
由上一步确定的参数,算出 W[5:0]为21 ——WWDG_SetWindowValue(0x40 | 21);
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
Key_Init(); //按键初始化
/*显示静态字符串*/
OLED_ShowString(1, 1, "WWDG TEST");
/*判断复位信号来源*/
if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET) //如果是窗口看门狗复位
{
OLED_ShowString(2, 1, "WWDGRST"); //OLED闪烁WWDGRST字符串
Delay_ms(500);
OLED_ShowString(2, 1, " ");
Delay_ms(100);
RCC_ClearFlag(); //清除标志位
}
else //否则,即为其他复位
{
OLED_ShowString(3, 1, "RST"); //OLED闪烁RST字符串
Delay_ms(500);
OLED_ShowString(3, 1, " ");
Delay_ms(100);
}
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //开启WWDG的时钟
/*WWDG初始化*/
WWDG_SetPrescaler(WWDG_Prescaler_8); //设置预分频为8
WWDG_SetWindowValue(0x40 | 21); //设置窗口值,窗口时间为30ms
WWDG_Enable(0x40 | 54); //使能并第一次喂狗,超时时间为50ms
while (1)
{
Key_GetNum(); //调用阻塞式的按键扫描函数,模拟主循环卡死
OLED_ShowString(4, 1, "FEED"); //OLED闪烁FEED字符串
Delay_ms(20); //喂狗间隔为20+20=40ms
OLED_ShowString(4, 1, " ");
Delay_ms(20);
WWDG_SetCounter(0x40 | 54); //重装计数器,喂狗
}
}
三、IWDG和WWDG对比
-----------------------------------------结束符--------------------------------------