事件是一种实现任务间通信的机制,主要用于实现多任务间的同步,但事件通信只能是事件类型的通信,无数据传输。
与信号量不同的是,它可以实现一对多,多对多的同步。
即一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理。
也可以是多个任务同步多个事件。
每一个事件组只需要很少的 RAM 空间来保存事件组的状态。 事件组存储在一个 EventBits_t 类型的变量中,该变量在事件组结构体中定义。
事件可使用于多种场合,它能够在一定程度上替代信号量,用于任务与任务间,中断与任务间的同步。
在 FreeRTOS 事件中,每个事件获取的时候,用户可以选择感兴趣的事件,并且选择读取事件信息标记,它有三个属性,分别是逻辑与,逻辑或以及是否清除标记。
当任务等待事件同步时,可以通过任务感兴趣的事件位和事件信息标记来判断当前接收的事件是否满足要求。
如果满足则说明任务等待到对应的事件,系统将唤醒等待的任务;否则,任务会根据用户指定的阻塞超时时间继续等待下去。
事件组可以简单地认为就是一个整数:
**事件组:事件发生时,会唤醒所有符号条件的任务,简单地说它有"广播"的作用 **
每一位代表一个事件, 任务通过“逻辑与”或“逻辑或”与一个或多个事件建立关联,形成一个事件组。
事件的“逻辑或”也被称作是独立型同步,指的是任务感兴趣的所有事件任一件发生即可被唤醒;
事件“逻辑与” 则被称为是关联型同步,指的是任务感兴趣的若干事件都发生时才被唤醒,并且事件发生的时间可以不同步。
使用事件组之前,要先创建,得到一个句柄;使用事件组时,要使用句柄来表明使用哪个事件组。
有两种创建方法:动态分配内存、静态分配内存。
/* 创建一个事件组,返回它的句柄。
* 此函数内部会分配事件组结构体
* 返回值: 返回句柄,非 NULL 表示成功
*/
EventGroupHandle_t xEventGroupCreate( void );
/* 创建一个事件组,返回它的句柄。
* 此函数无需动态分配内存,所以需要先有一个 StaticEventGroup_t 结构体,并传入它的指
针
* 返回值: 返回句柄,非 NULL 表示成功
*/
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer );
对于动态创建的事件组,不再需要它们时,可以删除它们以回收内存。
/*
* xEventGroup: 事件组句柄,你要删除哪个事件组
*/
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
可以设置事件组的某个位、某些位,使用的函数有 2 个:
有一个或多个任务在等待事件,如果这些事件符合这些任务的期望,那么任务还会被唤醒。
/* 设置事件组中的位
* 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-有, pdFA
LSE-没有
* 返回值: pdPASS-成功, pdFALSE-失败
*/
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t * pxHi
gherPriorityTaskWoken );
使用 xEventGroupWaitBits ()来等待事件,可以等待某一位、某些位中的任意一个,也可以等待多位;等到期望的事件后,还可以清除某些位。
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait );
参数说明:
参数 | 说明 |
---|---|
xEventGroup | 等待哪个事件组? |
uxBitsToWaitFor | 等待哪些位?哪些位要被测试? |
xWaitForAllBits | 怎么测试?是"AND"还是"OR"? pdTRUE: 等待的位,全部为 1; pdFALSE: 等待的位,某一个为 1 即可 |
xClearOnExit | 函数提出前是否要清除事件? pdTRUE: 清除 uxBitsToWaitFor 指定的位 pdFALSE: 不清除 |
xTicksToWait | 如果期待的事件未发生,阻塞多久。 可以设置为 0:判断后即刻返回; 可设置为 portMAX_DELAY:一定等到成功才返回; 可以设置为期望的 Tick Count,一般用 pdMS_TO_TICKS()把 ms 转换为 Tick Count |
返回值 | 返回的是事件值, 如果期待的事件发生了,返回的是"非阻塞条件成立"时的事件值; 如果是超时退出,返回的是超时时刻的事件值。 |
可 以 使 用 xEventGroupWaitBits() 等 待 期 望 的 事 件 , 它 发 生 之 后 再 使 用xEventGroupClearBits()来清除。但是这两个函数之间,有可能被其他任务或中断抢占,它们可能会修改事件组。
可 以 使 用 设 置 xClearOnExit 为 pdTRUE , 使 得 对 事 件 组 的 测 试 、 清 零 都 在xEventGroupWaitBits()函数内部完成,这是一个原子操作。
使用 xEventGroupSync() 函数可以同步多个任务:
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
const EventBits_t uxBitsToWaitFor,
TickType_t xTicksToWait );
参数列表:
参数 | 说明 |
---|---|
xEventGroup | 哪个事件组? |
uxBitsToSet | 要设置哪些事件?我完成了哪些事件? 比如 0x05(二进制为 0101)会导致事件组的 bit0,bit2 被设置为 1 |
uxBitsToWaitFor | 等待那个位、哪些位? 比如 0x15(二级制 10101),表示要等待 bit0,bit2,bit4 都为 1 |
xTicksToWait | 如果期待的事件未发生,阻塞多久。 可以设置为 0:判断后即刻返回; 可设置为 portMAX_DELAY:一定等到成功才返回; 可以设置为期望的 Tick Count,一般用 pdMS_TO_TICKS()把 ms 转换为 Tick Count |
返回值 | 返回的是事件值, 如果期待的事件发生了,返回的是"非阻塞条件成立"时的事件值; 如果是超时退出,返回的是超时时刻的事件值。 |
要使用事件组,代码中要有如下操作:
/* 1. 工程中添加 event_groups.c */
/* 2. 源码中包含头文件 */
##include "event_groups.h"