一、事件标志组
前面所介绍的队列、信号量,只能实现与单个任务进行同步。而有时候某个任务可能需要与多个事件或任务进行同步,此时,事件标志组的作用就凸显出来
1.1 事件标志组简介
事件标志位:用一个位,来表示事件是否发生
事件标志组:一组事件标志位的集合, 可以简单的理解事件标志组,就是一个(16/32)整数
事件标志组是一种实现任务/中断间通信的机制,主要用于实现多任务间的同步
根据configUSE_16_BIT_TICKS 的宏定义不同,每个事件标志组的位数也就不同
虽然使用了 32 位无符号的数据类型变量来存储事件标志, 但其中的高8位用作存储事件标志组的控制信息,低24位用作存储事件标志 ,所以说一个事件组最多可以存储 24 个事件标志
可以发现,事件标志组与外设的状态寄存器SR非常类似,每一位都代表一个事件是否发生(高8位除外)
1.2 事件标志组与队列、信号量的区别
此外:设置事件组不会阻塞,等待事件标志支持阻塞
二、事件组结构体
typedef struct EventGroupDef_t
{EventBits_t uxEventBits;List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */#if ( configUSE_TRACE_FACILITY == 1 )UBaseType_t uxEventGroupNumber;#endif/* 如果事件组是静态分配,则设置为pdTURE,以确保不尝试释放内存 */#if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */#endif
} EventGroup_t;
成员 | 说明 |
uxEventBits | EventBits_t类型的变量,其中, 高八位:事件标志组的控制信息 剩余位:存储事件标志(1:发生;2:未发生) |
xTasksWaitingForBits | 链表,等待事件标志位的任务的链表 |
三、相关API
函数 | 描述 |
xEventGroupCreate() | 使用动态方式创建事件标志组 |
xEventGroupCreateStatic() | 使用静态方式创建事件标志组 |
xEventGroupClearBits() | 清零事件标志位 |
xEventGroupClearBitsFromISR() | 在中断中清零事件标志位 |
xEventGroupSetBits() | 设置事件标志位 |
xEventGroupSetBitsFromISR() | 在中断中设置事件标志位 |
xEventGroupWaitBits() | 等待事件标志位 |
xEventGroupSync() | 设置事件标志位,并等待事件标志位 |
2.1 动态创建事件组
使用条件:configSUPPORT_DYNAMIC_ALLOCATION必须在 FreeRTOSConfig.h 中设置为 1,或保留未定义状态(此时默认为 1)
EventGroupHandle_t xEventGroupCreate ( void ) ;
返回值 | 描述 |
NULL | 事件标志组创建失败 |
句柄 | 事件标志组创建成功 |
2.1.1 函数详解
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )EventGroupHandle_t xEventGroupCreate( void ){/* 创建一个事件标志组结构体指针:pxEventBits */EventGroup_t * pxEventBits;/* 申请结构体空间,并将首地址赋给指针变量:pxEventBits */pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); /* 申请成功 */if( pxEventBits != NULL ){/* 将结构体中的时间标志组变量初始化为0*/pxEventBits->uxEventBits = 0;/* 初始化等待任务链表 */vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );#if ( configSUPPORT_STATIC_ALLOCATION == 1 ){pxEventBits->ucStaticallyAllocated = pdFALSE;}#endif /* configSUPPORT_STATIC_ALLOCATION */traceEVENT_GROUP_CREATE( pxEventBits );}/* 申请失败 */else{traceEVENT_GROUP_CREATE_FAILED(); }/* 返回结构体的地址 */return pxEventBits;}
2.1.2 函数实现总结
(1)创建一个时间标志组的结构体指针变量
(2)申请内存空间
成功:将事件标志组变量初始化为0,并初始化等待事件标志任务列表
失败:定义但未实现的宏
(3)返回:事件标志组的结构体指针变量
2.2 清除事件标志位
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
形参 | 描述 |
xEventGroup | 待操作的事件标志组句柄 |
uxBitsToSet | 待清零的事件标志位 |
返回值 | 描述 |
整数 | 清零事件标志位之前事件组中事件标志位的值 |
注:要清零的事件标志位,可以是一位,也可以是多位
0x08: 清除bit3
0x09:清除bit3和bit0
2.3 设置事件标志位
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
形参 | 描述 |
xEventGroup | 待操作的事件标志组句柄 |
uxBitsToSet | 待设置的事件标志位 |
返回值 | 描述 |
整数 | 函数返回时,事件组中的事件标志位值 |
注:要设置的事件标志位,可以是一位,也可以是多位
0x08: 设置bit3
0x09:设置bit3和bit0
2.4 获取事件标志组值
2.5 等待事件标志位
等待事件标志组的某些位被设置,选择性的进入阻塞状态,中断中无法调用此函数
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,const BaseType_t xClearOnExit,const BaseType_t xWaitForAllBits,TickType_t xTicksToWait )
形参 | 描述 |
xEvenrGroup | 等待的事件标志组句柄 |
uxBitsToWaitFor | 等待的事件标志位,可以用逻辑或等待多个事件标志位 |
xClearOnExit | 成功等待到事件标志位后,清除事件组中对应的事件标志位, pdTRUE :清除uxBitsToWaitFor指定位; pdFALSE:不清除 |
xWaitForAllBits | 等待 uxBitsToWaitFor 中的所有事件标志位(逻辑与) pdTRUE:等待的位,全部为1 逻辑与 pdFALSE:等待的位,某个为1 逻辑或 |
xTicksToWait | 等待的阻塞时间 |
返回值 | 描述 |
等待的事件标志位值 | 等待事件标志位成功,返回所等待到的事件标志位置1的事件标志组的值 |
其他值 | 等待事件标志位失败,返回事件组中的事件标志位 |
2.4.1 函数详解
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,const BaseType_t xClearOnExit,const BaseType_t xWaitForAllBits,TickType_t xTicksToWait )
{/*** uxReturn:返回值(32位时间标志组变量)* uxControlBits:记录控制位信息(高八位)* xWaitConditionMet:记录等待条件是否已满足* xAlreadyYielded:记录调度器的状态*/EventGroup_t * pxEventBits = xEventGroup;EventBits_t uxReturn, uxControlBits = 0;BaseType_t xWaitConditionMet, xAlreadyYielded;BaseType_t xTimeoutOccurred = pdFALSE;/* 检查用户没有去尝试等待内核本身使用的位(高8位),并且至少请求了一个位(低24位)。*/configASSERT( xEventGroup );configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );configASSERT( uxBitsToWaitFor != 0 );#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ){configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );}#endif/* 挂起调度器 */vTaskSuspendAll();{/* 取出结构体的32位变量,赋值给uxCurrentEventBitsconst EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;/* 检查是否以满足等待条件 */xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );/* 等待条件已满足 */if( xWaitConditionMet != pdFALSE ){/* 将32变量赋给uxReturn,并将等待时间设置为0 */uxReturn = uxCurrentEventBits;xTicksToWait = ( TickType_t ) 0;/* 判断是否需要清除标志位 */if( xClearOnExit != pdFALSE ){pxEventBits->uxEventBits &= ~uxBitsToWaitFor;}else{mtCOVERAGE_TEST_MARKER();}}/* 等待条件不满足,并且未设置等待时间 */else if( xTicksToWait == ( TickType_t ) 0 ){/* 返回当前32位变量,并将超时标志置为:pdTURE */uxReturn = uxCurrentEventBits;xTimeoutOccurred = pdTRUE;}/* 等待条件不满足 */else{/* 需要清除标志位,将第25位置1 */if( xClearOnExit != pdFALSE ){uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;}else{mtCOVERAGE_TEST_MARKER();}/* 需要等待所有标志位 or 至少一个标志位,将第26位置1 */if( xWaitForAllBits != pdFALSE ){uxControlBits |= eventWAIT_FOR_ALL_BITS;}else{mtCOVERAGE_TEST_MARKER();}/* 此函数的功能:** (1)控制位 | 等待的事件标志位 的结果,赋给列表项的值(用于升序排列)** (2)将任务添加到等待事件组的列表中** (3)将任务添加到阻塞列表中,任务进入阻塞状态*/vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );/* 返回值赋为0 */uxReturn = 0;traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );}}/* 恢复调度器 */xAlreadyYielded = xTaskResumeAll();if( xTicksToWait != ( TickType_t ) 0 ){if( xAlreadyYielded == pdFALSE ){portYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}/* The task blocked to wait for its required bits to be set - at this* point either the required bits were set or the block time expired. If* the required bits were set they will have been stored in the task's* event list item, and they should now be retrieved then cleared. */uxReturn = uxTaskResetEventItemValue();if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ){taskENTER_CRITICAL();{/* The task timed out, just return the current event bit value. */uxReturn = pxEventBits->uxEventBits;/* It is possible that the event bits were updated between this* task leaving the Blocked state and running again. */if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE ){if( xClearOnExit != pdFALSE ){pxEventBits->uxEventBits &= ~uxBitsToWaitFor;}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}xTimeoutOccurred = pdTRUE;}taskEXIT_CRITICAL();}else{/* The task unblocked because the bits were set. */}/* The task blocked so control bits may have been set. */uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;}traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );/* Prevent compiler warnings when trace macros are not used. */( void ) xTimeoutOccurred;return uxReturn;
}
2.6 同步函数
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait)
形参 | 描述 |
xEventGroup | 等待事件标志所在事件组 |
uxBitsToSet | 达到同步点后,要设置的事件标志 |
uxBitsToWaitFor | 等待的事件标志 |
xTicksToWait | 等待的阻塞时间,等待uxBitsToWaitFor参数值指定的 所有位设置完成的最长时间 |
返回值 | 描述 |
等待的事件标志位值 | 等待事件标志位成功,返回等待到的事件标志位 |
其他值 | 等待事件标志位失败,返回事件组中的事件标志位 |
特点:通过设置某一位或多位(uxBitsToSet) ,等待标志位(uxBitsToWaitFor),即设置了uxBitsToSet,还需要等待uxBitsToWaitFor被设置才可以进行后续操作