FreeRTOS 独立看门狗监测任务执行状态
以下转载自安富莱电子: http://forum.armfly.com/forum.php
通过前面的几个章节,我们基本已经完成了 FreeRTOS 所有功能的讲解,本章节为大家介绍一种使用
独立看门狗监测任务执行状态的方法,借此为大家提供一种在软件或者硬件死机时,FreeRTOS 系统如何
保证系统复位的思路。
什么是独立看门狗
假设有一只饥饿的狗正在看守一座房子,而有人要闯入。 如果这个强盗的同谋以 2 分钟的时间间隔不
停的向看门狗扔肉。 那么这只狗将忙于吃肉而忽视保卫工作,因此将不会犬叫。 然而,如果同谋扔完了肉
或者由于其它原因忘了喂肉,狗将开始犬叫,从而惊动邻居、 房屋主人或者警察。
嵌入式化的独立看门狗定时器遵循同样的方法。 用户需要每隔一段时间就刷新看门狗定时器,否则将
导致看门狗定时器溢出。 在大多数情况下,看门狗定时器的溢出将使得系统复位。 即使经过仔细规划和设
计,嵌入式系统也有可能由于出乎预料的问题而死机,看门狗定时器就是用来处理类似情况的,看门狗定
时器可用于从这种状态恢复。
教程使用的 STM32F103,STM32F407 和 STM32F429 都自带独立看门狗,使用也比较简单,用户
初始化好看门狗,并设置好看门狗溢出时间即可,剩下就是在溢出时间范围内及时喂狗。
下面就提供一种利用独立看门狗监测多任务的执行状态的思路。
多任务监测实现思路
为了保证 FreeRTOS 的所有用户任务都在正常的运行,我们通过独立看门狗的形式来监测,一旦发现
有某个任务长时间没有执行,看门狗就会将系统复位。

运行条件:
创建 5 个用户任务 Task1,Task2,Task3,Task4 和 Task5。 其中 Task5 的优先级最高,然后依次
是 Task4,Task3,Task2,Task1。
任务 Task1 到 Task4 定期发事件标志给任务 Task5,表示任务运行正常。
实现思路:
喂狗程序放在最高优先级的任务 Task5 里面,其它的 4 个任务都定期的向最高优先级任务发送事件标
志,只有四个任务都发来了事件标志才进行喂狗。
看门狗的复位时间设置为多少合适呢?这个要根据四个任务 Task1 到 Task4 的最大发送事件标志间隔
来确定。 假设测试发现,最大的发送事件标志时间间隔是由 Task4 产生的,间隔是 6s,我们可以在
此基础上再设置一些时间容限,把看门狗的复位时间设置为 10s,也就是说,四个任务 Task1 到 Task4
需要在 10s 内给任务 Task5 发送事件标志,让 Task5 执行喂狗操作,否则看门狗定时器溢出,从而导
致系统将复位。
推荐在最高优先级任务里面实现喂狗,这样才可以保证其它低优先级任务发来了事件标志后,Task5
可以及时的喂狗。 如果放在一个低优先级的任务里面会存在问题,比如所有的任务都已经发送了表示
自己正常运行的事件标志,但是此低优先级任务在执行喂狗程序前被其它高优先级的任务抢占了,造
成不能及时喂狗,从而导致系统复位,这种误判断会使得系统不能够正常工作。
按照上面的实现思路,我们在开发板上面实战演练下。
代码练兵场:
首先设置4个任务,其中一个任务使用按键控制阻塞20s,当按键不按下的时候,其余任务正常发送事件消息给优先级最高的任务,如果4s内有任何任务没有给接收事件的任务发送消息,将会导致喂狗失败而系统复位。
创建事件组:
static void AppObjCreate (void)
{
/* 创建事件标志组 */
xCreatedEventGroup = xEventGroupCreate(); if(xCreatedEventGroup == NULL)
{
/* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
printf("create event failure!\n");
}
}
所有任务创建函数:
static void AppTaskCreate(void)
{ xTaskCreate(vTaskWork, /* 任务函数 */
"vTaskWork", /* 任务名 */
, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
, /* 任务优先级*/
&xHandleTaskWork ); /* 任务句柄 */ xTaskCreate( vTaskLed1, /* 任务函数 */
"vTaskLed1", /* 任务名 */
, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
, /* 任务优先级*/
&xHandleTaskLED1); /* 任务句柄 */ xTaskCreate( vTaskBeep, /* 任务函数 */
"vTaskBeep", /* 任务名 */
, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
, /* 任务优先级*/
&xHandleTaskBeep ); /* 任务句柄 */
xTaskCreate( vTaskStart, /* 任务函数 */
"vTaskStart", /* 任务名 */
, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
, /* 任务优先级*/
&xHandleTaskStart ); /* 任务句柄 */ }
分别实现:
static void vTaskStart(void *pvParameters)
{
EventBits_t uxBits;
const TickType_t xTicksToWait = / portTICK_PERIOD_MS; /* 最大延迟1000ms */ /*
开始执行启动任务主函数前使能独立看门狗。
设置LSI是64分频,下面函数参数范围0-0xFFF,分别代表最小值2ms和最大值8192ms
下面设置的是4s,如果4s内没有喂狗,系统复位。
*/
IWDG_Config(IWDG_Prescaler_64 ,*); /* 打印系统开机状态,方便查看系统是否复位 */
printf("=====================================================\r\n");
printf("=系统开机执行\r\n");
printf("=====================================================\r\n"); while()
{
/* 等待所有任务发来事件标志 */
uxBits = xEventGroupWaitBits(xCreatedEventGroup, /* 事件标志组句柄 */
TASK_BIT_ALL, /* 等待TASK_BIT_ALL被设置 */
pdTRUE, /* 退出前TASK_BIT_ALL被清除,这里是TASK_BIT_ALL都被设置才表示“退出”*/
pdTRUE, /* 设置为pdTRUE表示等待TASK_BIT_ALL都被设置*/
xTicksToWait); /* 等待延迟时间 */ if((uxBits & TASK_BIT_ALL) == TASK_BIT_ALL)
{
IWDG_Feed();
printf("五个用户任务都正常运行\r\n");
}
else
{
printf("五个用户任务并非都正常运行\r\n");
/* 基本是每xTicksToWait进来一次 */
/* 通过变量uxBits简单的可以在此处检测那个任务长期没有发来运行标志 */
}
}
}
void vTaskBeep(void *pvParameters)
{ while()
{
xEventGroupSetBits(xCreatedEventGroup, TASK_BIT_3);
BEEP_TOGGLE;
vTaskDelay();
}
}
void vTaskLed1(void *pvParameters)
{
TickType_t xLastWakeTime;
const TickType_t xFrequency = ; /* 获取当前的系统时间 */
xLastWakeTime = xTaskGetTickCount(); while()
{ LED3_TOGGLE;
xEventGroupSetBits(xCreatedEventGroup, TASK_BIT_2);
/* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
vTaskDelayUntil(&xLastWakeTime, xFrequency);
} }
static void vTaskWork(void *pvParameters)
{
const TickType_t xTicksToWait = / portTICK_PERIOD_MS; /* 最大延迟20s */ while()
{
if (key1_flag==)
{
key1_flag=; }
/* K2键按下,向xQueue1发送数据 */
if(key2_flag==)
{
key2_flag=;
printf("K2按键按下,让vTaskWork任务延迟20s,以实现看门狗复位情况\r\n");
vTaskDelay(xTicksToWait);
// TIM_Mode_Config(); }
xEventGroupSetBits(xCreatedEventGroup, TASK_BIT_1);
vTaskDelay();
}
}
当按键不按下的时候:

当按键按下之后,事件发送有一个会阻塞20s:

解释一下为什么按键K2按下之后,会显示一次都正常运行,才识别到有非正常运行的。
K2按下,这个按键任务会被阻塞20s,此时,xEventGroupWaitBits函数由于超时返回,而超时返回,不会清除之前的置位信息,此时还是会保持上次正常状态的值,这样会打印任务都正常,当打印正常之后,标志会被清零。所以再等到下一次vTaskStart任务等待响应时,按键阻塞的任务迟迟没有发来消息,故打印出不是所有任务都正常运行。要清除置位标志,必须是超时以外的情形。官方解释:

如果xClearOnExit设置为pdTRUE,则在xEventGroupWaitBits()返回时,如果xEventGroupWaitBits()由于超时之外的任何原因而返回,则在作为uxBitsToWaitFor参数传递的值中设置的任何位将被清除。 超时值由xTicksToWait参数设置。
顺带一句,如果vTaskStart任务中的等待超时时间小于(比如100ms)其他任务的阻塞时间,那么接收事件标志位不会和你程序写的那样显示打印消息,因为当第一次其他任务向vTaskStart发送事件时,是可以正确响应的,而当其他任务,比如Beep任务需要阻塞1s,在这1s的阻塞中,vTaskStart函数的接收超时已经过去好几次了,这样,在Bee还在阻塞时,会打印并非都正常运行,而当Beep从阻塞回到运行时,又会正确打印所有任务正常运行。所以,知道这个了之后,vTaskStart任务的超时时间需要结合实际项目好好思考,而且下面的else判断一定要谨慎思考逻辑之后再使用。

按下超过4s之后,看门狗喂狗失败导致复位了:

FreeRTOS 独立看门狗监测任务执行状态的更多相关文章
- FreeRTOS独立看门狗检测任务执行状态
为了保证FreeRTOS的所有用户任务都在正常的运行,我们通过独立看门狗的形式来检测,一旦发现有某个任务长时间没有执行,看门狗就会将系统复位. 运行条件: 创建5个用户任务Task1,Task2,Ta ...
- STM32之独立看门狗与窗口看门狗总结
一.独立看门狗 STM32 的独立看门狗由内部专门的 40Khz 低速时钟驱动,即使主时钟发生故障,它也仍然有效. 看门狗的原理:单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路 ...
- STM32之------独立看门狗(IWDG)和窗体看门狗(WWDG)
一 前沿废语: 之前有很风靡的游戏,名字叫<看门狗>.该游戏用了很新的引擎技术,打造出了一个辽阔庞大的世界,内容是玩家Aiden·Pearce(主角)是一名精通黑客技术的高手,当时 ...
- STM32之独立看门狗(IWDG)与窗口看门狗(WWDG)总结
一.独立看门狗 STM32 的独立看门狗由内部专门的 40Khz 低速时钟驱动,即使主时钟发生故障,它也仍然有效. 看门狗的原理:单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路 ...
- STM8S 独立看门狗配置及使用
//独立看门口的时钟来源 内部低速时钟 128khz 除以2 即64khz //选择 IWDG_Prescaler_128 //64/128 =0.5 khz 2ms周期 #define IWDG_5 ...
- stm8的独立看门狗与窗口看门狗
STM8拥有两个硬件看门狗,分别叫做独立看门狗和窗口看门狗 独立看门狗的框图如下 我们可以看到,独立看门狗的时钟来自于LSI内部低速振荡器,经过二分频到达看门狗外设单元,在经过一个七位的预分频到达计数 ...
- [STM31F103]独立看门狗
独立看门狗步骤: l 取消寄存器写保护: n IWDG_WriteAccessCmd(); l 设置独立看门狗的预分频系数,确定时钟: n IWDG_SetPrescaler(); l 设置看门狗重装 ...
- 【转】STM32 独立看门狗简介
STM32 的独立看门狗由内部专门的 40Khz 低速时钟驱动,即使主时钟发生故障,它也仍然有效. 看门狗的原理:单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路就是为了避免这种 ...
- IWDG—独立看门狗
本章参考资料:<STM32F4XX 中文参考手册> IWDG 章节.学习本章时,配合<STM32F4XX 中文参考手册> IWDG 章节一起阅读,效果会更佳,特别是涉及到寄存器 ...
随机推荐
- java装箱拆箱
基本数据类型的自动装箱(autoboxing).拆箱(unboxing)是自J2SE 5.0开始提供的功能. 一般我们要创建一个类的对象的时候,我们会这样: Class a = new Class(p ...
- JDBC实例--通过连接工具类DBUtil +配置文件来获取连接数据库,方便又快捷
根据前面的连接方法,还有缺点就是,如果人家要换数据库,还得改动源代码,然后还要编译什么的.这样客户修改也不容易. 做法:我们写一个配置文件,把该数据写在配置文件上面,然后通过类来加载改文件,然后读取相 ...
- MySQL Desc指令相关
MySQL Desc指令相关 2011-08-09 11:25:50| 分类: my基本命令 |举报 |字号 订阅 1.desc tablename; 例如 :mysql> desc jo ...
- LR杂记 - 性能測试指标及经常使用的监控工具
监控指标 性能測试通常须要监控的指标包含: 1.serverLinux(包含CPU.Memory.Load.I/O). 2.数据库:1.Mysql 2.Oracle(缓存命中.索引.单条SQL性能.数 ...
- 解决windows下MySQL表名大写自动变小写的问题
解决windows下MySQL表名大写自动变小写的问题 有些人可能会遇到在windows下,表名不能用大写字母, 即使使用了大写字母的建表语句,还是会被自动转成小写. 解决方法: 打开 My ...
- C-常用字符串操作函数详解
//使用字符串操作应时刻注意字符串或者数组长度!!避免溢出!! 1. size_t strlen(char const *str); //计算字符串长度, 注意返回size_t类型的值, 即unsig ...
- mysql 必须掌握的工具pt-query-digest安装
mysql 必须掌握的工具pt-query-digest 古人云:工欲善其事,必先利其器.作为一名优秀的mysql dba也需要有掌握几个好用的mysql管理工具,所以我也一直在整理和查找一些能够便于 ...
- FastJSON使用案例(fastjson-1.1.28.jar)
import java.util.List; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; ...
- 【Linux】目录配置
为什么每套Linux distributions的配置文件.执行文件.每个目录内放置的文件其实都差不多?因为有一套需要依据的标准!我们底下就来瞧一瞧. 因为利用Linux来开发产品或distribut ...
- C#委托、事件剖析(下)
本节对事件进行总结. 二.事件: 1.概念:Event:A member that enables an object or class to provide notifications;官方的解释是 ...