FREERTOS队列集和事件标志组

队列集 

一个队列只允许任务间传递的消息为同一种数据类型,如果需要在任务间传递不同数据类型的消息时,那么就可以使用队列集!

作用:用于对多个队列或信号量(信号量本质上也是个队列)进行“监听”,其中不管哪一个消息到来,都可让任务退出阻塞状态。

假设:有个接收任务,使用到队列接收和信号量的获取,如下:

如果不使用队列集,而是使用常规的多个队列的方式

这样如果第一行被阻塞,那么第二行也就得不到执行。

但是如果使用的是队列集

只要其中有一个队列有效即可,我们可以根据队列的句柄来执行不同的动作。

队列集相关API函数

接下来分别说明。

创建队列集

队列添加到队列集中

注意,不能先往队列中发送消息后再添加到队列集。

从队列集中移除队列

获取队列集中有有效消息的队列

事件标志组

前面我们学习了使用信号量来完成同步,但是使用信号量来同步的话任务只能与单个的事件或任务进行同步。有时候某个任务可能会需要与多个事件或任务进行同步。

这里说明下,什么是跟多个任务进行同步?

用裸机中标志位的角度来看,就是:

if(flagA == 1 && flagB == 1 && flagC == 1 && flagD == 1){……}

想要实现这种需求,队列集没法用,因为队列集里的队列是“或”的关系;

貌似使用多个信号量也可以,其他任务都释放信号量,然后目标任务依次获取,只有都获取到才能执行后续的代码,不过比较麻烦。

FreeRTOS 为此提供了一个可选的解决方法,那就是事件标志组。

事件位(事件标志)

事件位用来表明某个事件是否发生,事件位通常用作事件标志,比如下面的几个例子:

● 当收到一条消息并且把这条消息处理掉以后就可以将某个位(标志)1,当队列中没有消息需要处理的时候就可以将这个位(标志)0

● 当把队列中的消息通过网络发送输出以后就可以将某个位(标志)1,当没有数据需要从网络发送出去的话就将这个位(标志)0

● 现在需要向网络中发送一个心跳信息,将某个位(标志)1。现在不需要向网络中发送心跳信息,这个位(标志)0

事件组

一个事件组就是一组的事件位,事件组中的事件位通过位编号来访问,同样,以上面列出的三个例子为例:

● 事件标志组的 bit0 表示队列中的消息是否处理掉。

● 事件标志组的 bit1 表示是否有消息需要从网络中发送出去。

● 事件标志组的 bit2 表示现在是否需要向网络发送心跳信息。

事件标志组和事件位的数据类型

事件标志组的数据类型为 EventGroupHandle_t,当 configUSE_16_BIT_TICKS 1 的时候事件标志组可以存储 8 个事件位,当 configUSE_16_BIT_TICKS 0 的时候事件标志组存储 24 个事件位。

事件标志组中的所有事件位都存储在一个无符号的 EventBits_t 类型的变量中,EventBits_t 在 event_groups.h 中有如下定义:

typedef TickType_t EventBits_t;

数据类型 TickType_t 在文件 portmacro.h 中有如下定义:

可以看出当 configUSE_16_BIT_TICKS 0 的时候 TickType_t 是个 32 位的数据类型,因此 EventBits_t 也是个 32 位的数据类型。EventBits_t 类型的变量可以存储 24 个事件位,另外的那高 8 位有其他用。事件位 0 存放在这个变量的 bit0 上,变量的 bit1 就是事件位 1,以此类推。

对于 STM32 来说一个事件标志组最多可以存储 24 个事件位,如下图所示:

其实就是一个uint32_t类型的数组,每个数组的位置存着一个标志位,只不过操作系统对其进行了管理。

创建事件标志组

FreeRTOS 提供了两个用于创建事件标志组的函数,如下表所示:

函数 xEventGroupCreate()

此函数用于创建一个事件标志组,所需要的内存通过动态内存管理方法分配。由于内部处理的原因,事件标志组可用的 bit 数取决于 configUSE_16_BIT_TICKS , 当configUSE_16_BIT_TICKS1 为 1 的 时 候 事 件 标 志 组 有 8 个 可 用 的 位 (bit0~bit7) , 当 configUSE_16_BIT_TICKS 为 0 的时候事件标志组有 24 个可用的位(bit0~bit23)EventBits_t 类型的变量用来存储事件标志组中的各个事件位。

函数原型如下:

设置事件位

FreeRTOS 提供了 4 个函数用来设置事件标志组中事件位(标志),事件位(标志)的设置包括清零和置 1 两种操作,这 4 个函数如下表所示:

函数 xEventGroupClearBits()

将事件标志组中的指定事件位清零,此函数只能用在任务中,不能用在中断服务函数中!中断服务函数有其他的 API 函数。函数原型如下:

函数 xEventGroupClearBitsFromISR()

此函数为函数 xEventGroupClearBits()的中断级版本,也是将指定的事件位(标志)清零。此函数用在中断服务函数中,此函数原型如下:

函数 xEventGroupSetBits()

设置指定的事件位为 1,此函数只能用在任务中,不能用于中断服务函数,此函数原型如下:

函数 xEventGroupSetBitsFromISR()

此函数也用于将指定的事件位置 1,此函数是 xEventGroupSetBits()的中断版本,用在中断服务函数中,函数原型如下:

获取事件标志组值

我们可以通过 FreeRTOS 提供的 API 函数来查询事件标准组值,FreeRTOS 一共提供了两个这样的 API 函数,如下表所示:

函数 xEventGroupGetBits()

此函数用于获取当前事件标志组的值,也就是各个事件位的值。此函数用在任务中,不能用在中断服务函数中。此函数是个宏,真正执行的是函数 xEventGroupClearBits(),函数原型如下:

函数 xEventGroupGetBitsFromISR()

获取当前事件标志组的值,此函数是 xEventGroupGetBits()的中断版本,函数原型如下:

等待指定的事件位

某个任务可能需要与多个事件进行同步,那么这个任务就需要等待并判断多个事件位(标志),使用函数 xEventGroupWaitBits()可以完成这个功能。调用函数以后如果任务要等待的事件位还没有准备好(1 或清零)的话任务就会进入阻塞态,直到阻塞时间到达或者所等待的事件位准备好。函数原型如下:

FreeRTOS队列FreeRTOS操作系统提供的一种数据结构,用于实现任务与任务、任务与中断之间的通信。队列可以存储有限的、大小固定的数据项目,并提供了入队和出队的操作。入队是将数据项添加到队列中,而出队则是从队列中获取队列项(消息)。队列在任务与任务、任务与中断之间传递消息,并且可以根据需要指定队列的长度和数据项目的大小。因为队列用于传递消息,所以也被称为消息队列。在FreeRTOS中,信号量也是基于队列实现的,因此深入了解FreeRTOS队列对于使用该操作系统非常重要。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [基于matlab数字pid控制代码-ARClab:先进的机器人控制-实验室课程](https://download.csdn.net/download/weixin_38739101/18987007)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [FreeRTOS队列](https://blog.csdn.net/qq_26195179/article/details/114657409)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值