写在前面:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。
目录
一、事件位(或标志)与事件组
二、事件组和事件位数据类型
三、使用事件组必须克服的问题
四、事件组的 RTOS API函数
五、实例代码
事件位:用于指示事件是否发生;事件位通常称为事件标志。
事件组:是一组事件位;事件组中的各个事件位由位号引用(即每一 bit代表某个事件)
事件组由 EventGroupHandle_t类型的变量引用
如果 configUSE_16_BIT_TICKS设置为 1,则事件组中存储的位数(或标志)为 8;如果 configUSE_16_BIT_TICKS设置为 0,则为24;对 configUSE_16_BIT_TICKS的依赖性是由于在内部实现中用于线程本地存储的数据类型任务
configUSE_16_BIT_TICKS的具体的描述可以看 FreeRTOS篇章之 FreeRTOSConfig.h分析
事件组中的所有事件位都存储在 EventBits_t类型的单个无符号变量中。事件位 0存储在位位置 0,事件位1存储在位位置 1,依此类推
下图显示了一个 24位事件组,该组使用三个位来保存已描述的三个示例事件。在图像中,仅事件位 2被设置
实施事件组时,RTOS必须克服的两个主要挑战是:
1、避免在用户的应用程序中创建竞争条件:
在以下情况下,事件组的实现将会在应用程序中创建竞争条件:
FreeRTOS事件组的实现通过智能的建立来确保设置、测试和清除位的原子性,从而消除了竞争条件的可能性。线程本地存储和谨慎使用 API函数返回值使这成为可能
2、避免不确定性:
事件组的概念隐含了不确定性行为,因为它不知道事件组上有多少个任务被阻止,因此,当设置了事件位时,也不知道需要测试多少条件或解除多少任务阻塞。
FreeRTOS质量标准不允许不确定的行为在中断禁用或者中断服务中发生。为确保在设置事件位时不会违反这些严格的质量标准,需要以下两点:
事件组的 API函数允许任务或者其他事项来设置事件组中的一个或多个事件位,清除事件组中的 一个或多个事件位,并暂挂(进入“阻止”状态,因此任务不会占用任何处理时间)以等待一个或多个事件位在事件组中被置位
事件组还可用于同步任务,创建通常称为任务 “会合” 的任务。任务同步点是应用程序代码中的一个位置,在这个位置上,任务将处于阻塞状态(不消耗任何 CPU时间)等待,直到参与同步的所有其他任务也到达它们的同步点
需要 #include "event_groups.h"
1、xEventGroupCreate() API函数
EventGroupHandle_t xEventGroupCreate( void );
返回参数(此返回值应当保存下来,以作为操作此队列的句柄):
2、xEventGroupWaitBits() API函数
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
const TickType_t xTicksToWait );
传入参数:
返回参数:
3、xEventGroupClearBits() API函数
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
传入参数:
返回参数:
4、xEventGroupClearBitsFromISR() API函数
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
传入参数:
返回参数(有两个可能的返回值):
5、xEventGroupSetBits() API函数
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
传入参数:
返回参数:
注意:用户通过参数 uxBitsToSet设置的标志位并不一定会保留到此函数的返回值中,返回的值可能清除有以下两种情况:
a. 调用此函数的过程中,其它高优先级的任务就绪了,并且也修改了事件标志,此函数返回的事件标志位会发生变化。
b. 调用此函数的任务是一个低优先级任务,通过此函数设置了事件标志后,让一个等待此事件标志的高优先级任务就绪了,会立即切换到高优先级任务去执行,相应的事件标志位会被函数 xEventGroupWaitBits清除掉,等从高优先级任务返回到低优先级任务后,函数 xEventGroupSetBits的返回值已经被修改。
6、xEventGroupSetBitsFromISR() API函数
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t *pxHigherPriorityTaskWoken );
传入参数:
返回参数(有两个可能的返回值):
7、xEventGroupGetBits() API函数
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );
传入参数:
返回参数:
8、xEventGroupGetBitsFromISR() API函数
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup );
传入参数:
返回参数:
9、xEventGroupDelete() API函数
void xEventGroupDelete( EventGroupHandle_t xEventGroup );
传入参数:
10、xEventGroupCreateStatic() API函数
EventGroupHandle_t xEventGroupCreateStatic( EventGroupHandle_t * pxEventGroupBuffer );
该函数是用于在静态的时候,利用该函数创建一个事件组,具体可以去看他的注释,这里就不说了
相关的实例代码及文档,参看保存在官方文件路径 FreeRTOS/Demo/Common/Minimal
下的 EventGroupsDemo.c
文件