网站建设规划设计方案,中国建设招标网站,网站不做icp备案,统计站老站长推荐app视频笔者在学习看门狗的视频后#xff0c;对看门狗仍然是一知半解#xff0c;后面在实际应用中发现它是一个很好用的检测或者调试工具。所以总结一下笔者作为初学小白对看门狗的理解。
主函数初始化阶段、循环阶段和复位
众所周知#xff0c;程序的运行一般是这样的#xff1…笔者在学习看门狗的视频后对看门狗仍然是一知半解后面在实际应用中发现它是一个很好用的检测或者调试工具。所以总结一下笔者作为初学小白对看门狗的理解。
主函数初始化阶段、循环阶段和复位
众所周知程序的运行一般是这样的 程序在进入循环阶段之前会在初始化阶段将每个寄存器或者某些变量赋值。初始化阶段的代码执行一次后就不再执行了。而循环阶段的代码会执行很多次一直循环反复的执行下去。这时如果进行了 复位程序就会从头开始执行一次初始化代码再反复执行循环代码。
而如何进行 复位 呢常用的方法就是“RESET” 键也就是复位键。在程序故障、跑飞或者卡死的时候让它重头开始跑一遍避免程序陷入到长时间的罢工状态。不过复位键是人为按下在程序自动运行的应用环境中显然不适用。于是在程序中使用 看门狗 就可以代替 复位键 来重启程序。 避免程序陷入到长时间的罢工状态。这一句话非常关键比如下面这个检测按键是否被按下的程序当中while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 0); 会等待按键是否被释放松手。 如果这个按键一直被按下或者这个按键出现了故障导致这个while循环一直出不来就会造成程序始终被卡在这个地方。
因此另一种复位方式——看门狗它可以通过定时来重新启动程序。 看门狗本质上是一个递减的定时器如果程序在某个循环卡住了当看门狗定时器时间跑完看门狗就会复位程序从而跳出循环重头开始。
喂狗
看门狗只是一个检测程序故障的工具。当我们在程序的初始化阶段设置了一个看门狗当看门狗定时器时间跑完就会进行复位重头开始。而我们的程序是一个循环过程这就导致了我们需要用一个方法让看门狗在程序正常时不作为又要在程序故障时起作用。
这时就要进行喂狗操作。喂狗一般是在循环阶段的最后进行喂狗的本质是将定时器重装从头递减一旦喂了狗看门狗就会重新定时不会执行复位操作。而遇到程序卡死在某一个等待循环时就不会执行到喂狗操作函数。这个时候看门狗一到时间就会进行复位。另外如果没有及时喂狗在看门狗定时器倒计时结束前还没有喂狗也会重启程序。也就是说循环程序执行一次的时间需要在看门狗定时器的时间规定范围内。
独立看门狗和窗口看门狗
独立看门狗和窗口看门狗都是规定了程序循环时间一旦时间到了就会执行复位操作。独立看门狗是规定了一个最大时间点时间从这个最大时间点递减为0即倒计时为0后执行复位。而窗口看门狗是规定了一个时间段如果没有在这个时间段范围进行喂狗也会执行复位。
写入键寄存器的值作用0xCCCC启用独立看门狗0xAAAA重新加载到计数器 (喂狗)0x5555 解除IWDG_PR和IWDG_RLR的写保护除0x5555其他值启用IWDG_PR和IWDG_RLR的写保护
键寄存器KR是一个控制寄存器通过写入值来控制看门狗的操作。
独立看门狗IWDG初始化 首先要设置看门狗需要有个钥匙这个钥匙是保护寄存器被其他程序随意修改降低干扰。
IWDG_WriteAccess_Enable 将写保护解除后续可以设置预分频寄存器和重装寄存器
IWDG_Prescaler_16 设置预分频寄存器为16分频。
独立看门狗时钟是由一个 独立 的内部低速时钟LSI 提供。LSI 40kHzIWDG超时时间计算公式T(IWDG) 1 / LSI * PR预分频系数 * RL重装值1
上面代码预分频器为16分频40k/162500即一秒可以计数2500设置重装值为2499最大定时时间为一秒。
IWDG_ReloadCounter(); 为喂狗操作这里作用是重新计数在每次循环都需要进行喂狗操作。
程序完整版
#include stm32f10x.h // Device header
#include Delay.h
#include OLED.h
#include Key.hint main(void)
{/*模块初始化*/OLED_Init(); //OLED初始化Key_Init(); //按键初始化/*显示静态字符串*/OLED_ShowString(1, 1, IWDG TEST);/*判断复位信号来源*/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); //设置预分频为16IWDG_SetReload(2499); //设置重装值为2499独立看门狗的超时时间为1000msIWDG_ReloadCounter(); //重装计数器喂狗IWDG_Enable(); //独立看门狗使能while (1){Key_GetNum(); //调用阻塞式的按键扫描函数模拟主循环卡死IWDG_ReloadCounter(); //重装计数器喂狗OLED_ShowString(4, 1, FEED); //OLED闪烁FEED字符串Delay_ms(200); //喂狗间隔为200600800msOLED_ShowString(4, 1, );Delay_ms(600);}
}窗口看门狗WWDG初始化 窗口看门狗时钟是由APB1时钟分频得到PCLK36MHz。
预分频系数最小超时值最大超时值1113 μs7.28 ms2227 μs 14.56 ms4455 μs29.12 ms8910 μs58.25 ms
WWDG超时时间计算公式T(WWDG) 1 / PCLK * 4096 * WDG预分频系数 * T[5:0]1
WWDG窗口时间计算公式T(WIN) 1 / PCLK * 4096 * WDG预分频系数 * T[5:0] - W[5:0]
图中想让T(WWDG) 50 ms , 50 ms 1 / 36 Mhz * 4096 * 8 *T[5:0]1求得T[5:0]54
想让T(WIN) 30 ms , 30 ms 1 / 36 Mhz * 4096 * 8 *T[5:0]- W[5:0]求得T[5:0]21
WWDG_SetCounter(0x40 | 54); 为喂狗操作这里作用是重新计数在每次循环都需要进行喂狗操作。
循环程序时间应该在30ms和50ms之间低于或者超过都会 让看门狗进行复位。
程序完整版
#include stm32f10x.h // Device header
#include Delay.h
#include OLED.h
#include Key.hint 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); //设置预分频为8WWDG_SetWindowValue(0x40 | 21); //设置窗口值窗口时间为30msWWDG_Enable(0x40 | 54); //使能并第一次喂狗超时时间为50mswhile (1){Key_GetNum(); //调用阻塞式的按键扫描函数模拟主循环卡死OLED_ShowString(4, 1, FEED); //OLED闪烁FEED字符串Delay_ms(20); //喂狗间隔为202040msOLED_ShowString(4, 1, );Delay_ms(20);WWDG_SetCounter(0x40 | 54); //重装计数器喂狗}
}