假设你已经看过FreeRTOS 事件标志组这篇随笔了。

之前的基础篇,真的就只是简单了解一下,相当于大学实验室的实验,但是,我们实际公司项目中,需要更多地思考,就算我们之前只是学习了基础概念以及基础语法,只要我们勤加思考,就能灵活的运用基础知识了,基础是内功,基础打好了,功力自然上升。

事件标志组的概念就不再解释了,直接来正题。

你一定和我刚开始接触FreeRTOS一样,知道了事件标志组,也调用过API函数,并且也实现了开发板上历程的功能,不过开发板历程仅仅是介绍了某些API函数的用法,仅仅使用法而已。是否有和我当初一样的想法,到底事件标志组用来干什么,在我的程序设计中,我到底什么时候需要使用事件标志组?

在基础篇说到,事件标志组,相当于我们裸机开发中最常用的标志位flag。由于在os上跑,全局变量要谨慎使用。

事件标志组有自己的超时等待,也有同步线程的作用。

现在举例说明:

网络通信模块,SIM868,这个我已经使用裸机编写了第一代代码,切实体会到超时等待的优势,如果你没有足够的裸机编程经验,确实很难从教程中体会到超时等待,比如这个SIM868,我发送AT指令,有些指令1s就返回,有些指令几十秒甚至上分钟才返回,裸机开发中,要么一个阻塞延时等待(第一代代码采用的这种方式),要么定时器中断不断查询,这就出现一个问题,比如,我采取发送一个AT指令,延时3s之后,再去读模块返回的数据,在网络好的时候,可能只需要1s就可以读到模块返回的数据,这样我们功能正常,只是多花了2s,但是在网络不好的时候,可能需要5s模块才返回,这样的话,我们的裸机程序就会因为超时没有接收到数据需要重新发送或者其他什么处理,这就有很大弊端。所以,现在采取操作系统的方式。

其优势在于,创建两个任务(线程),一个发送,一个接收。发送任务只管发送,接收任务接收到模块返回之后立即和发送任务通信,实现消息同步。我们的网络通信模块SIM868,就是发送一条AT指令,收到返回数据之后,解析数据,再发送下一条。

好的,那么问题就来了,这,恰恰就是我们事件标志组的用途了啊。

首先说裸机,接收到SIM868返回数据的时候,我们可以立即解析,也可以设置标志,通过这个标志,在其他函数中做处理;

os,通过事件标志组,在接收任务中解析数据,解析完成之后,设置一个事件标志,发送任务等待这个事件的触发,然后周期性执行。

eg:

声明和定义:

static void AppTaskCreate (void);
static TaskHandle_t xHandleTaskSIM868send = NULL;
static TaskHandle_t xHandleTaskSIM868recive = NULL;
static EventGroupHandle_t xCreatedEventGroup = NULL; #define BIT_0 (1 << 0)
#define BIT_1 (1 << 1)
#define BIT_ALL (BIT_0 | BIT_1)

main函数:

    AppTaskCreate();

        /* 创建任务通信机制 */
AppObjCreate(); /* 启动调度,开始执行任务 */
vTaskStartScheduler();

其他函数:

static void AppObjCreate (void)
{
/* 创建事件标志组 */
xCreatedEventGroup = xEventGroupCreate(); if(xCreatedEventGroup == NULL)
{
/* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
printf("creak event failure!\r\n");
}
}
static void vTaskSIM868send(void *pvParameters)
{ EventBits_t uxBits;
const TickType_t xTicksToWait =; /* 最大延迟10s */
SIM868_PowerReset();
SIM868_instruction();
while()
{
comSendBuf(COM4,(uint8_t *)(SendCommand_Init.Echo_Off),strlen(SendCommand_Init.Echo_Off)); uxBits = xEventGroupWaitBits(xCreatedEventGroup, /* 事件标志组句柄 */
BIT_0, /* 等待bit0被设置 */
pdTRUE, /* 退出前bit0被清除,这里是bit0被设置才表示“退出”*/
pdTRUE, /* 设置为pdTRUE表示等待bit0被设置*/
xTicksToWait); /* 等待延迟时间 */ if((uxBits & BIT_ALL) == BIT_0)
{
/* 接收到bit0都被设置的消息 */
printf("接收到bit0被设置的消息\r\n");
}
else
{ printf("没接收到bit0被设置的消息\r\n");
}
} }
static void vTaskSIM868recive(void *pvParameters)
{ uint8_t read;
int count =;
char buf[]={};
char buf1[];
EventBits_t uxBits;
while()
{
for(int i=;i<;i++)
{
while(comGetChar(COM4, &read))
{
sprintf(buf1, "%c", read);
if((read!='\r')&&( read !='\n'))//不存放这两个特殊字符
{
buf[count++]=read;
} vTaskDelay();
}
count=;
switch(buf[])
{
case 'A':
if(!strncmp(buf,"ATE0OK",))
{
comClearRxFifo(COM4);//清除缓
printf("去除回显\r\n");
memset(buf,,);
uxBits = xEventGroupSetBits(xCreatedEventGroup, BIT_0);
if((uxBits & BIT_0) != )
{
printf("收到ok返回并且事件标志置位");
}
else
{
printf("noready\r\n");
}
break;
}
break;
}
} }
}
static void AppTaskCreate (void)
{
xTaskCreate( vTaskSIM868send, /* 任务函数 */
"vTaskSIM868send", /* 任务名 */
, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
, /* 任务优先级*/
&xHandleTaskSIM868send ); /* 任务句柄 */ xTaskCreate( vTaskSIM868recive, /* 任务函数 */
"vTaskSIM868recive", /* 任务名 */
, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
, /* 任务优先级*/
&xHandleTaskSIM868recive ); /* 任务句柄 */ }

在启动调度之前,我们先创建了事件标志组,采用24bit的方式,这个在基础篇已有说明。

现在,创建两个任务,一个发送,一个接收。

发送函数,首先,通过串口给SIM868发送去回显指令,然后就进入阻塞态,因为wait函数会让其阻塞,这里设置的最大等待时间是10s,一般的指令,10s内都返回了,特殊的关系到网络问题的指令,时间再根据需要更改。

然后,接收任务中,就在串口里面读取SIM868返回的数据,解析数据之后,调用set函数,此时高优先级的发送任务立即退出阻塞态,打断低优先级的接收任务,执行后面的指令,当然这里仅仅举例,因为我这里就一条指令,以后有机会分享不涉及公司的demo。

这样的好处在于,第一,通过os的方式,独立发送和接收,发送只管发,接收到了就把相应的事件标志位置位,通知wait的任务,为了立即响应,wait任务优先级设置比set任务的高,这样在10s超时等待时间内,如果网络好,我1s就可返回,网络不好,等待5s也无所谓,特殊需要长时间等待的指令再特殊处理。这样,就会让系统运行更加高效,尤其是低功耗类产品。其次,在裸机开发中,我之前使用阻塞延时方式,当多个指令都返回的是ok的时候,我不能很方便的打印出到底是哪个指令返回的ok,而os使用事件标志组之后,我一定能知道是哪个触发的。最后,一个任务通知另外一个,标志着某个动作完成或者异常时,就是我们使用事件标志组的时候。

在这里,因为当初很是困惑,开发板厂商的代码大多换汤不换药,一个调调:

这里,由于接收任务优先级低于发送,所以if条件不会满足,为什么呢?因为事件标志置位,让wait的高优先级任务返回了,会清除这个标志,所以,打印else的内容。在最初开开发板教程的时候,我只觉得if满足的条件才证明是事件被置位了,可是它依托于wait函数,这个在基础教程中也说到了。

那么,我们实际项目中,其实就应该只判断else的内容,满足else分支,证明执行wait函数的任务已经返回(当然这是建立在执行wait函数的任务优先级高于执行set函数的任务的前提下,这个也是比较推荐的方式),这说明了什么?说明我们不能死板地学习教程,开发板教程仅仅是熟悉,需要自己思考,自己去官网,论坛,Google查询资料,并且一定要有自己独立思考地过程,这样,基础有了,进阶就会容易得多。

FreeRTOS 事件标志组 ——提高篇的更多相关文章

  1. FreeRTOS 事件标志组

    以下转载自安富莱电子: http://forum.armfly.com/forum.php 为什么要使用事件标志事件标志组是实现多任务同步的有效机制之一.也许有不理解的初学者会问采用事件标志组多麻烦, ...

  2. FreeRTOS_事件标志组

    FreeRTOS事件标志组 事件标志组简介 1. 事件位(事件标志) 事件位用于表明某个事件是否发生,事件位通常用作事件标志,比如下面的几个例子: 当收到一条消息并且把这条消息处理掉以后就可以将某个位 ...

  3. FreeRTOS 任务计数信号量,任务二值信号量,任务事件标志组,任务消息邮箱

    以下基础内容转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 FreeRTOS 计数信号量的另一种实现方式----基于任务通知(Task Not ...

  4. FreeRTOS 任务通知模拟事件标志组

    实验 //设置事件位的任务 void eventsetbit_task(void *pvParameters) { u8 key; while(1) { if(EventGroupTask_Handl ...

  5. 16.3-uC/OS-III同步 (事件标志组实验)

    事件标志组,顾名思义,就是若干个事件标志的组合,代表若干个事件是否发生,通常用于集合两个或两个以上事件的状态 . 1.如果想要使用事件标志组,就必须事先使能事件标志组.消息队列的使能位于“os_cfg ...

  6. 16.2-uC/OS-III同步 (事件标志组)

    事件标志组 1.当任务要与多个事件同步时可以使用事件标志.若其中的任意一个事件发生时任务被就绪, 叫做逻辑或(OR).若所有的事件都发生时任务被就绪,叫做逻辑与( AND). 2.用户可以创建任意个事 ...

  7. RTX——第13章 事件标志组

    以下内容转载自安富莱电子: http://forum.armfly.com/forum.php 前面的章节我们已经讲解了任务管理和时间管理,从本章节开始讲解任务间的通信和同步机制.首先讲解任务间的通信 ...

  8. UCOSIII事件标志组

    两种同步机制 "或"同步 "与"同步 使能 #define OS_CFG_FLAG_EN 1u /* Enable (1) or Disable (0) cod ...

  9. ucos中信号量 事件标志 消息队列都怎么用

    信号量 事件标志和消息队列分别应用于什么场景(反正我学的时候有点闹不清,现在总结一下): 信号量和事件标志用于任务同步.详细来说,这个功能可以替代以前裸机中你打一个标记的功能,比如使用了一个定时器,5 ...

随机推荐

  1. 工欲善其事,必先利其器 软件工具开发关键词 protractor自动化测试工具 RegexBuddy正则 CodeSmith,LightSwitch:代码生成 CheatEngine:玩游戏修改内存值必备神器 ApkIDE:Android反编译工具 Reflector:反编译dll动态链接库

    工欲善其事,必先利其器 本文版权归翟士丹(Stan Zhai)和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利. 原文地址:http ...

  2. xcode9报错 Safe Area Layout Guide before iOS9.0

    运行工程的时候会遇到  Safe Area Layout Guide before iOS9.0 这是因为xcode9  storyboard的设置里面多了 个 Safe Area Layout Gu ...

  3. 使用Unified Auditing Policy审计数据泵导出操作

    1.创建审计策略 SQL> alter session set container=pdb1; SQL> create or replace directory dumpdir as '/ ...

  4. 在没有创建Provision Profile权限的情况下 发布Enterprise inhouse app 的方法

    由于用普通开发者证书,发布的app或ipa没法在普通机器上安装运行,原因是apple限制了普通开发者发布appstore以外的环境中,只有Enterprise企业版证书才能发布inhouse. 今天在 ...

  5. Maven for Eclipse 第三章 ——创建和导入 Maven 项目

    这一章主要介绍 Maven 项目的结构,它的构建的架构,主要涵盖了必需的主题,最后将学习如何创建一个简单的 Maven 项目.这章主要包括以下部分. Maven 项目的结构 POM 文件(Projec ...

  6. debian 8 解压安装mysql(版本5.7.19)

    debian 8 解压安装mysql(版本5.7.19)一.下载 根据目标主机的型号官网下载mysql安装包如: mysql-server_5.7.19-1debian8_amd64.deb-bund ...

  7. 怎样让HTML 表格中内容自动换行??

    <table style="word-break:break-all; word-wrap:break-all;">

  8. django 自动化测试的故障排查

    [问题背景] django使用mysql做为后台数据库.在使用django的自动化测试命令test时报如下错误 python3 manage.py test polls Creating test d ...

  9. ansible 视频学习

    ansible 视频地址 https://ninghao.net/video/4040

  10. MySql(十七):MySql架构设计——高可用设计之思路及方案

    前言: 数据库系统是一个应用系统的核心部分,要想系统整体可用性得到保证,数据库系统就不能出现任何问题.对于一个企业级的系统来说,数据库系统的可用性尤为重要.数据库系统一旦出现问题无法提供服务,所有系统 ...