FreeRTOS学习笔记(八)事件
文章目录
- 前言
- 一、事件
- 1.1 事件的引入
- 1.2 事件位和事件组
- 二、事件的实现
- 2.1 相关API函数
- 2.2 实现流程
前言
本章我们将展开事件的学习,着重比对和信号量的异同及优劣。
一、事件
1.1 事件的引入
前面我们学习了使用信号量来完成同步,但是使用信号量来同步的话任务只能与单个的事件或任务进行同步。有时候某个任务可能会需要与多个事件或任务进行同步,此时信号量就无能为力了。
事件是一种实现任务间通信的机制,多用于实现多任务之间的同步,但只能进行事件类型的通信,不能通过数据。它可以实现一对多,多对多的通信,即一个任务可以等待一(多)个事件发生;也可以是一(多)个事件都发生后唤醒任务。事件无排队性,多次向任务设置同一事件等同于只设置一次,且支持等待超时机制。
每个事件在获取的时候,用户可以选择感兴趣的事件,并选择读取事件信息标记,它有三个属性“逻辑与”“逻辑或”以及“是否清楚标记”。当任务等待事件同步时,可以通过任务感兴趣的事件位和信息标记位去判断事件是否符合要求,若满足则任务等待到对应事件去,反之任务会感觉超时时间继续等待。
1.2 事件位和事件组
在FreeRTOS中,事件位(Event bits)用来表明某个事件是否发生,事件位通常用作事件标志。32位的每一位都可以单独表示一个事件,例如,第1位代表某个特定的事件,第2位代表另一个事件。任务可以通过设置、清除或者等待某个(或多个)特定的事件标志来实现同步。
事件标志组(Event Groups)是一种轻量级的任务间同步机制,允许多个任务通过事件标志进行通信或协调。事件标志组提供了一种可以通过多个标志位表示任务状态或事件发生情况的方式,任务可以等待一个或多个标志位被设置。它也是一个 32 位的整数,[23:0]位的每一个位可以单独作为一个标志位,每个标志位可以是 0 或 1,分别代表某个事件未发生或已发生。
二、事件的实现
2.1 相关API函数
FreeRTOS提供了一组API函数来操作事件标志组,主要包括:
xEventGroupCreate( )
此函数用于创建一个事件标志组,所需要的内存通过动态内存管理方法分配。事件标志组可用的 bit 数和最大延时值portMAX_DELAY取决于event_groups的configUSE_16_BIT_TICKS宏定义 ,具体如下:
- 1:16 位模式下,事件标志组有8个可用的位[7:0],最大延时为 0xffff,即 65535;
- 0:32 位模式下,事件标志组有 24 个可用的位[23:0],最大延时为 0xffffffff,即 4,294,967,295。
// 创建事件标志组
EventGroupHandle_t xEventGroupCreate( void );
xEventGroupWaitBits( )
某个任务可能需要与多个事件进行同步,那么这个任务就需要等待并判断多个事件位(标志),使用函数 xEventGroupWaitBits()可以完成这个功能。调用函数以后如果任务要等待的事件位还没有准备好(置 1 或清零)的话任务就会进入阻塞态,直到阻塞时间到达或者所等待的事件位准备好。
// 用于等待特定的事件标志被设置
EventBits_t xEventGroupWaitBits(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait );
- 参数说明:
- xEventGroup:标志组句柄
- uxBitsToWaitFor:等待的标志位
- xClearOnExit:是否在退出时清除等待的标志位
- xWaitForAllBits:等待所有指定的标志位都被设置,还是只等待任意一个标志位被设置
- xTicksToWait:等待时间
xEventGroupSetBits( ) 和xEventGroupSetBitsFromISR( )
这两个函数的作用都是设置指定的事件位为 1,但xEventGroupSetBits( )函数只能用在任务中,xEventGroupSetBitsFromISR( )用于中断服务函数,此函数原型如
下:
// 设置指定的标志位,通常用于通知任务某个事件发生
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
- 参数:
- xEventGroup: 要操作的事件标志组的句柄
- uxBitsToClear: 指定要置 1 的事件位,比如要将 bit3 值 1 的话就设置为 0X08,如设置为 0X09 的话就是同时将 bit3 和 bit0 置 1
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet, BaseType_t * pxHigherPriorityTaskWoken );
- 参数:
- xEventGroup: 要操作的事件标志组的句柄
- uxBitsToClear: 指定要置 1 的事件位
- pxHigherPriorityTaskWoken:标记退出此函数以后是否进行任务切换
- 返回值:
- 成功:pdPASS
- 失败:pdFALSE
值得注意的是,我们还可以使用类似#define EVENT (0x01<<X)
的宏定义进行置位,这种方式与使用 xEventGroupSetBits() 函数是配合使用的。通过宏定义事件位可以方便地指定要在事件标志组中设置的位,当调用 xEventGroupSetBits() 时,可以使用这些宏来明确需要设置哪些事件位。
xEventGroupClearBits( )和xEventGroupClearBitsFromISR( )
将事件标志组中的指定事件位清零,和置1的两个函数一样分别用于任务和中断。
// 清除指定的标志位,常用于复位某个事件状态
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
- 参数:
- xEventGroup: 要操作的事件标志组的句柄
- uxBitsToClear: 要清零的事件位
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet );
- 参数:
- xEventGroup: 要操作的事件标志组的句柄
- uxBitsToClear: 指定要置 1 的事件位
- 返回值:
- 成功:pdPASS
- 失败:pdFALSE
xEventGroupGetBits( )和xEventGroupGetBitsFromISR( )
我们可以通过 FreeRTOS 提供的 API 函数来查询事件标准组值,FreeRTOS 一共提供了两个这样的 API 函数:
// 用于任务获取当前事件标志组的值
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup )
- 参数:
- xEventGroup: 要获取的事件标志组的句柄
// 用于中断获取当前事件标志组的值
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
- 参数:
- xEventGroup: 要获取的事件标志组的句柄。
2.2 实现流程
- 宏定义的设置:事件标志组的实现过程中有一些关键的宏定义,这些定义用于配置事件标志组和任务调度相关的操作。
EventBits_t: 表示事件标志的存储类型,实际上是 TickType_t 类型,由configUSE_16_BIT_TICKS 设置(前面提到过),具体定义如下:
typedef TickType_t EventBits_t;
xEventGroupSetBits: 用于设置事件标志的宏,用于触发指定的事件位:
// 这里 uxBitsToSet 是需要设置的事件位。
#define xEventGroupSetBits( xEventGroup, uxBitsToSet ) \
xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, NULL )
- 创建事件标志组:创建一个事件标志组使用 xEventGroupCreate() 函数。此函数会在内存中分配一个事件标志组的数据结构,并初始化为全 0 的事件位。
- 设置事件位:要设置某些事件位,可以使用 xEventGroupSetBits() 函数。此函数将指定的事件位设置为 1,同时检查是否有任何任务正等待这些位,并唤醒它们。
- 等待事件位:任务可以通过 xEventGroupWaitBits() 函数等待某些事件位被设置。该函数会将调用任务置为阻塞状态,直到指定的事件位发生变化。
- 清除事件位:利用xEventGroupClearBits() 函数用于手动清除某些事件位。
免责声明:本文参考了网上公开资料,仅用于学习交流,若有错误或侵权请联系笔者。