【FreeRTOS】事件组 event group(附源码)

2024-06-11 13:12

本文主要是介绍【FreeRTOS】事件组 event group(附源码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引言:事件组是一种用于同步多个任务之间的状态和行为的机制。在操作系统中,事件组通常由操作系统提供,用于实现任务间的通信和同步。
事件组通常包含一组独立的事件或标志,每个事件或标志都可以表示一种特定的状态或条件。任务可以等待事件组中的一个或多个事件被设置,也可以设置、清除或检查事件组中的事件状态。

1.事件组的概念

首先我们先用生活中的实例来举例一下什么是事件组,春游三个同学,三个同学一起出发前需要相互等待,这个出发就是的关系,三个同学春游之后需要交报告,这个报告就是的关系,其中一个人交即可,在FreeRTOS中,事件组event group可以解决上述的问题。

概念:事件组可以简单地认为就是一个整数:

  • 的每一位表示一个事件
  • 每一位事件的含义由程序员决定,比如:Bit0表示用来串口是否就绪,Bit1表示按键是否被按下
  • 这些位,值为1表示事件发生了,值为0表示事件没发生
  • 一个或多个任务、ISR都可以去写这些位;一个或多个任务、ISR都可以去读这些位
  • 可以等待某一位、某些位中的任意一个,也可以等待多位

事件组用一个整数来表示,其中的高8位留给内核使用,只能用其他的位来表示事件。那么这个整数是多少位的?

  • 如果configUSE_16_BIT_TICKS是1,那么这个整数就是16位的,低8位用来表示事件
  • 如果configUSE_16_BIT_TICKS是0,那么这个整数就是32位的,低24位用来表示事件
  • configUSE_16_BIT_TICKS是用来表示Tick Count的,怎么会影响事件组?这只是基于效率来考虑
    如果configUSE_16_BIT_TICKS是1,就表示该处理器使用16位更高效,所以事件组也使用16 位
    如果configUSE_16_BIT_TICKS是0,就表示该处理器使用32位更高效,所以事件组也使用32 位

事件组的操作:

事件组和队列、信号量等不太一样,主要集中在2个地方:

1.唤醒谁?

队列、信号量:事件发生时,只会唤醒一个任务
事件组:事件发生时,会唤醒所有符号条件的任务,简单地说它有"广播"的作用

2.是否清除事件?

队列、信号量:是消耗型的资源,队列的数据被读走就没了;信号量被获取后就减少了
事件组:被唤醒的任务有两个选择,可以让事件保留不动,也可以清除事件

以上图为列,事件组的常规操作如下:

先创建事件组,

任务C、D等待事件:等待什么事件?可以等待某一位、某些位中的任意一个,也可以等待多位。简单地说就 是"或"、"与"的关系。 得到事件时,要不要清除?可选择清除、不清除。

任务A、B产生事件:设置事件组里的某一位、某些位

2.事件组的函数

创建:

/* 创建一个事件组,返回它的句柄。* 此函数内部会分配事件组结构体 * 返回值: 返回句柄,非NULL表示成功*/
EventGroupHandle_t xEventGroupCreate( void );
/* 创建一个事件组,返回它的句柄。* 此函数无需动态分配内存,所以需要先有一个StaticEventGroup_t结构体,并传入它的指针* 返回值: 返回句柄,非NULL表示成功*/
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * 
pxEventGroupBuffer );

删除:

/** xEventGroup: 事件组句柄,你要删除哪个事件组*/
void vEventGroupDelete( EventGroupHandle_t xEventGroup )

设置事件:

可以设置事件组的某个位、某些位,使用的函数有2个:
在任务中使用 xEventGroupSetBits()
在ISR中使用 xEventGroupSetBitsFromISR()
有一个或多个任务在等待事件,如果这些事件符合这些任务的期望,那么任务还会被唤醒。 函数原型如下:

/* 设置事件组中的位* xEventGroup: 哪个事件组* uxBitsToSet: 设置哪些位? *             如果uxBitsToSet的bitX, bitY为1, 那么事件组中的bitX, bitY被设置为1*               可以用来设置多个位,比如 0x15 就表示设置bit4, bit2, bit0* 返回值: 返回原来的事件值(没什么意义, 因为很可能已经被其他任务修改了)*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet );
/* 设置事件组中的位* xEventGroup: 哪个事件组* uxBitsToSet: 设置哪些位? *             如果uxBitsToSet的bitX, bitY为1, 那么事件组中的bitX, bitY被设置为1*               可以用来设置多个位,比如 0x15 就表示设置bit4, bit2, bit0* pxHigherPriorityTaskWoken: 有没有导致更高优先级的任务进入就绪态? pdTRUE-有, 
pdFALSE-没有* 返回值: pdPASS-成功, pdFALSE-失败*/
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet,BaseType_t * pxHigherPriorityTaskWoken );

值得注意的是,ISR中的函数,比如队列函数 xQueueSendToBackFromISR 、信号量函数 xSemaphoreGiveFromISR ,它们会唤醒某个任务,最多只会唤醒1个任务。
但是设置事件组时,有可能导致多个任务被唤醒,这会带来很大的不确定性。所以 xEventGroupSetBitsFromISR 函数不是直接去设置事件组,而是给一个FreeRTOS后台任务(daemon task)发送队列数据,由这个任务来设置事件组。
如果后台任务的优先级比当前被中断的任务优先级高, xEventGroupSetBitsFromISR 会设置 *pxHigherPriorityTaskWoken 为pdTRUE。
如果daemon task成功地把队列数据发送给了后台任务,那么 xEventGroupSetBitsFromISR 的返回值 就是pdPASS。

等待事件:

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,const BaseType_t xClearOnExit,const BaseType_t xWaitForAllBits,TickType_t xTicksToWait );

先引入一个概念:unblock condition。一个任务在等待事件发生时,它处于阻塞状态;当期望的时间 发生时,这个状态就叫"unblock condition",非阻塞条件,或称为"非阻塞条件成立";当"非阻塞条件成 立"后,该任务就可以变为就绪态。

3.示例:等待多个事件

要使用事件组,代码中要有如下操作:

* 1. 工程中添加event_groups.c */
/* 2. 源码中包含头文件 */
##include "event_groups.h"

假设大厨要等手下做完这些事才可以炒菜:洗菜、生火。
本程序创建3个任务:

  • 任务1:洗菜
  • 任务2:生火
  • 任务3:炒菜。

main函数代码如下,它创建了3个任务:

int main( void )
{prvSetupHardware();/* 创建递归锁 */xEventGroup = xEventGroupCreate( );if( xEventGroup != NULL ){/* 创建3个任务: 洗菜/生火/炒菜*/xTaskCreate( vWashingTask, "Task1", 1000, NULL, 1, NULL );xTaskCreate( vFiringTask,  "Task2", 1000, NULL, 2, NULL );xTaskCreate( vCookingTask, "Task3", 1000, NULL, 3, NULL );/* 启动调度器 */vTaskStartScheduler();}else{/* 无法创建事件组 */}/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */return 0;
}

这篇关于【FreeRTOS】事件组 event group(附源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1051267

相关文章

mysql中的group by高级用法详解

《mysql中的groupby高级用法详解》MySQL中的GROUPBY是数据聚合分析的核心功能,主要用于将结果集按指定列分组,并结合聚合函数进行统计计算,本文给大家介绍mysql中的groupby... 目录一、基本语法与核心功能二、基础用法示例1. 单列分组统计2. 多列组合分组3. 与WHERE结合使

8种快速易用的Python Matplotlib数据可视化方法汇总(附源码)

《8种快速易用的PythonMatplotlib数据可视化方法汇总(附源码)》你是否曾经面对一堆复杂的数据,却不知道如何让它们变得直观易懂?别慌,Python的Matplotlib库是你数据可视化的... 目录引言1. 折线图(Line Plot)——趋势分析2. 柱状图(Bar Chart)——对比分析3

Android实现一键录屏功能(附源码)

《Android实现一键录屏功能(附源码)》在Android5.0及以上版本,系统提供了MediaProjectionAPI,允许应用在用户授权下录制屏幕内容并输出到视频文件,所以本文将基于此实现一个... 目录一、项目介绍二、相关技术与原理三、系统权限与用户授权四、项目架构与流程五、环境配置与依赖六、完整

Android实现定时任务的几种方式汇总(附源码)

《Android实现定时任务的几种方式汇总(附源码)》在Android应用中,定时任务(ScheduledTask)的需求几乎无处不在:从定时刷新数据、定时备份、定时推送通知,到夜间静默下载、循环执行... 目录一、项目介绍1. 背景与意义二、相关基础知识与系统约束三、方案一:Handler.postDel

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

mysql中的group by高级用法

《mysql中的groupby高级用法》MySQL中的GROUPBY是数据聚合分析的核心功能,主要用于将结果集按指定列分组,并结合聚合函数进行统计计算,下面给大家介绍mysql中的groupby用法... 目录一、基本语法与核心功能二、基础用法示例1. 单列分组统计2. 多列组合分组3. 与WHERE结合使

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C#如何动态创建Label,及动态label事件

《C#如何动态创建Label,及动态label事件》:本文主要介绍C#如何动态创建Label,及动态label事件,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#如何动态创建Label,及动态label事件第一点:switch中的生成我们的label事件接着,

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很