在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的芯片,俗称“看门狗”(watchdog)。”
看门狗通常是一个定时器,定时器定时到预定时间就会产生复位信号让单片机复位。要想避免看门狗复位单片机,要及时“喂狗”(恢复定时器初始值),也就是说只要程序能正常运行,就能及时喂狗,避免复位。反之,若程序跑飞,则无法及时喂狗,导致单片机能够复位,解决了程序跑飞的问题。
通常在裸机中编程的时候,一般都是一个大循环,采用时间片的方式去执行各种形式的任务。通常选择一个固定的时间片(比如每5ms)给看门狗喂狗,当然遇到一些可能会操作比较久的任务时,会追加一些额外的喂狗操作。
1.2、RTOS中使用看门狗查看了网上很多关于如何在RTOS中使用看门狗的策略,其实每种策略都有其使用场景,下面主要提到的几种方式。
1、建立一个看门狗的定时任务,并将该任务定义为最低优先级。使用STM32CubeMX来配置STM32的内部看门狗,超时时间为1000ms。
我们定义一个线程每200ms喂一次狗,优先级为RT_THREAD_PRIORITY_MAX-2。(这里只是举例,任务多了得仔细考虑如何喂狗)
extern IWDG_HandleTypeDef hiwdg;
/* 200ms 喂一次看门狗 */
static void iwdg_control(void *parameter)
{
int i = 0;
while(1)
{
rt_thread_mdelay(200);
i++;
/* Refresh IWDG: reload counter */
HAL_IWDG_Refresh(&hiwdg);
rt_kprintf("第%d次喂狗\n",i);
}
}
static rt_thread_t iwdg_tid = RT_NULL;
int iwdg_init(void)
{
/* 创建电机线程*/
iwdg_tid = rt_thread_create("iwdg_thread", // 线程名字
iwdg_control, // 线程入口函数
RT_NULL, // 线程入口参数
512, // 堆栈大小,
RT_THREAD_PRIORITY_MAX-2, // 线程优先级
5); // 时间片长度
/* 如果获得线程控制块,启动这个线程 */
if (iwdg_tid != RT_NULL)
rt_thread_startup(iwdg_tid);
return 0;
}
INIT_DEVICE_EXPORT(iwdg_init); // 自动初始化
效果如下:
接下来屏蔽喂狗操作,可以看到看门狗起作用了,单片机不断复位。
extern IWDG_HandleTypeDef hiwdg;
/* 200ms 喂一次看门狗 */
static void iwdg_control(void *parameter)
{
int i = 0;
while(1)
{
rt_thread_mdelay(200);
i++;
rt_kprintf("第%d次200ms\n",i);
}
}
static rt_thread_t iwdg_tid = RT_NULL;
int iwdg_init(void)
{
/* 创建电机线程*/
iwdg_tid = rt_thread_create("iwdg_thread", // 线程名字
iwdg_control, // 线程入口函数
RT_NULL, // 线程入口参数
512, // 堆栈大小,
RT_THREAD_PRIORITY_MAX-2, // 线程优先级
5); // 时间片长度
/* 如果获得线程控制块,启动这个线程 */
if (iwdg_tid != RT_NULL)
rt_thread_startup(iwdg_tid);
return 0;
}
INIT_DEVICE_EXPORT(iwdg_init); // 自动初始化
可以看到每5次200ms,单片机就会重启。