函数 | 描述 |
---|---|
xEventGroupCreate() | 使用动态方式创建事件标志组 |
xEventGroupCreateStatic() | 使用静态方式创建事件标志组 |
vEventGroupDelete() | 删除事件标志组 |
xEventGroupSetBits() | 将指定的事件位置1, 用于任务中 |
xEventGroupSetBitsFromISR() | 将指定的事件位置1,用于中断服务函数 |
xEventGroupClearBits() | 将指定的事件位清零, 用于任务 |
xEventGroupClearBitsFromISR() | 将指定的事件位清零,用于中断服务函数 |
xEventGroupGetBits | 获取当前事件标志组的值(各个事件位的值),用在任务中 |
xEventGroupGetBitsFromISR() | 获取当前事件标志组的值, 用在中断服务中 |
xEventGroupWaitBits() | 事件组等待位 |
xEventGroupSync() | 事件组同步函数 |
事件标志组中其它重要的API函数:
函数 | 描述 |
---|---|
xTaskRemoveFromUnorderedEventList() | 将阻塞的任务从事件列表中移除,并添加到就绪列表中 |
vTaskPlaceOnUnorderedEventList() | 将任务添加到事件列表中 |
prvTestWaitCondition() | 判断当前事件位是否匹配当前等待的事件 |
事件标志组是实现多任务同步的有效机制之一。
事件标志组数据类型:
typedef struct xEventGroupDefinition
{
/* 储存事件标志组中的事件位 */
EventBits_t uxEventBits;
/* 事件标志组列表 */
List_t xTasksWaitingForBits;
/* 启用可视化跟踪调试 */
#if( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxEventGroupNumber;
#endif
/* 用于标记事件标志组申请内存的方式 */
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
uint8_t ucStaticallyAllocated;
#endif
} EventGroup_t;
时间标志组中的事件位储存在EventBits_t类型变量中,其中:
typedef TickType_t EventBits_t;
又:
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
#define portTICK_TYPE_IS_ATOMIC 1
#endif
可以看出,当configUSE_16_BIT_TICKS为1时,EventBits_t是16位的数据类型,为0时,EventBits_t是32位的数据类型。
当EventBits_t是16位的数据类型,只储存8个事件位,当EventBits_t是32位的数据类型,只储存24个事件位,其高8位用于其他用途。
高8位用途:
#if configUSE_16_BIT_TICKS == 1
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x0100U
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x0200U
#define eventWAIT_FOR_ALL_BITS 0x0400U
#define eventEVENT_BITS_CONTROL_BYTES 0xff00U
#else
/* 表示事件退出时,是否需要删除事件位 */
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x01000000UL
/* 标记该任务事件位设置了,已解除阻塞 */
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x02000000UL
/* 表示设置的所有事件位都为1才有效 */
#define eventWAIT_FOR_ALL_BITS 0x04000000UL
#define eventEVENT_BITS_CONTROL_BYTES 0xff000000UL
#endif
#define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL
函数 | 描述 |
---|---|
xEventGroupCreate() | 动态方式创建事件标志组 |
xEventGroupCreateStatic() | 静态方式创建事件标志组 |
使用动态方式创建事件标志组,需要将configSUPPORT_DYNAMIC_ALLOCATION设置为1。
函数原型如下:
/********************************************************
参数:无
返回:事件标志组的句柄
*********************************************************/
EventGroupHandle_t xEventGroupCreate( void )
EventGroupHandle_t是新定义的类型:
typedef void * EventGroupHandle_t;
函数源代码如下:
EventGroupHandle_t xEventGroupCreate( void )
{
EventGroup_t *pxEventBits;
/* 为事件标志组申请内存 */
pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) );
if( pxEventBits != NULL )
{
pxEventBits->uxEventBits = 0; /* 初始化事件位都为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 ( EventGroupHandle_t ) pxEventBits; /* 返回事件标志组的句柄 */
}
使用静态方式创建事件标志组,需要将configSUPPORT_STATIC_ALLOCATION设置为1。
函数原型如下:
/********************************************************
参数:pxEventGroupBuffer:指向一个StaticEventGroup_t类型变量的指针
用来保存事件标志组结构体
返回:事件标志组的句柄
*********************************************************/
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )
函数源代码如下:
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )
{
EventGroup_t *pxEventBits;
configASSERT( pxEventGroupBuffer );
/* 获取事件标志组的句柄 */
pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer;
if( pxEventBits != NULL )
{
pxEventBits->uxEventBits = 0; /* 初始化事件位 */
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); /* 初始化事件标志列表 */
/* 如果使能动态创建方式 */
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
/* 标记是使用静态方式创建 */
pxEventBits->ucStaticallyAllocated = pdTRUE;
}
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
traceEVENT_GROUP_CREATE( pxEventBits );
}
else
{
traceEVENT_GROUP_CREATE_FAILED();
}
return ( EventGroupHandle_t ) pxEventBits;
}
事件标志组删除使用函数vEventGroupDelete()。
函数原型如下:
/********************************************************
参数:xEventGroup :事件标志组句柄
返回:无
*********************************************************/
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
函数源代码如下:
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
{
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
vTaskSuspendAll(); /* 挂起调度器 */
{
traceEVENT_GROUP_DELETE( xEventGroup );
/* 当事件列表中存在列表项,即存在阻塞的任务 */
while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
{
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
/* 将任务从事件列表中移除,添加到就绪列表中 */
( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
}
/* 如果使能动态申请方式,没有使能静态申请方式 */
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
{
vPortFree( pxEventBits );
}
/* 如果使能了动态申请方式和静态申请方式 */
#elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
{
/* 如果不是使用静态方式创建时间标志组 */
if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
{
vPortFree( pxEventBits );
}
/* 如果使用静态方式创建事件标志组,则需要用户手动释放内存 */
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
}
( void ) xTaskResumeAll(); /* 恢复调度器 */
}
该函数将阻塞的任务从事件列表中移除,并添加到就绪列表中,如果恢复的任务优先级比当前运行任务的优先级高,则标记需要进行任务切换。
函数原型如下:
/********************************************************
参数:pxEventListItem:某任务的事件列表项
xItemValue:时间列表项的项值
返回: pdTRUE:可进行任务切换
pdFALSE:不需要进行任务切换
*********************************************************/
BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )
函数源代码如下:
BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )
{
TCB_t *pxUnblockedTCB;
BaseType_t xReturn;
configASSERT( uxSchedulerSuspended != pdFALSE );
/*
* taskEVENT_LIST_ITEM_VALUE_IN_USE为0x80000000UL
* xItemValue等于eventUNBLOCKED_DUE_TO_BIT_SET,即为0x02000000UL
*/
listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );
/* 获取因该事件而阻塞任务的TCB */
pxUnblockedTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxEventListItem );
configASSERT( pxUnblockedTCB );
( void ) uxListRemove( pxEventListItem ); /* 将该事件从事件列表中删除 */
( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) ); /* 删除任务的状态信息,如阻塞态 */
prvAddTaskToReadyList( pxUnblockedTCB ); /* 将任务添加到就绪列表中 */
/* 当前阻塞的任务优先级大于当前运行的任务 */
if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
{
xReturn = pdTRUE;
xYieldPending = pdTRUE; /* 标记调度器挂起 */
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
函数 | 描述 |
---|---|
xEventGroupSetBits() | 将指定的事件位置1, 用在任务中 |
xEventGroupSetBitsFromISR() | 将指定的事件位置1,用在中断服务函数中 |
函数原型如下:
/********************************************************
参数:xEventGroup:事件标志组的句柄
uxBitsToSet:需要设置的事件位
返回:EventBits_t:事件位
*********************************************************/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet )
函数源代码如下:
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
{
ListItem_t *pxListItem, *pxNext;
ListItem_t const *pxListEnd;
List_t *pxList;
EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
BaseType_t xMatchFound = pdFALSE;
configASSERT( xEventGroup );
configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
pxList = &( pxEventBits->xTasksWaitingForBits ); /* 获取事件标志组对应的事件列表 */
pxListEnd = listGET_END_MARKER( pxList ); /* 获取列表中最后一个列表项,即Mini列表项 */
vTaskSuspendAll(); /* 挂起任务调度器 */
{
traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );
pxListItem = listGET_HEAD_ENTRY( pxList ); /* 得到第一个列表项,即第一个因事件而阻塞的任务 */
pxEventBits->uxEventBits |= uxBitsToSet; /* 设置事件位 */
/* 如果事件列表中有列表项,即有阻塞任务,则进入循环中 */
while( pxListItem != pxListEnd )
{
pxNext = listGET_NEXT( pxListItem ); /* 获取下一个任务 */
uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem ); /* 获取对应任务的项值 */
xMatchFound = pdFALSE;
/*
* eventEVENT_BITS_CONTROL_BYTES为0xff000000UL
* 将高8位和事件位分别存在uxControlBits和uxBitsWaitedFor
*/
uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;
uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;
/* 如果不要等待所有的事件位都为1才有效 */
if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 )
{
/*
* 每个任务的事件位和控制位(高8位)存在任务的项值中,即uxBitsWaitedFor
* pxEventBits->uxEventBits表示用户设置了某事件位,存在事件标志组中
*/
if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )
{
xMatchFound = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* 需要等待所有的事件位,通过eventWAIT_FOR_ALL_BITS决定 */
else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )
{
/* 所有的事件位都设置了 */
xMatchFound = pdTRUE;
}
else
{
/* 运行到这里,表示需要等待所有的事件位,但其中有事件位不存在 */
}
/* 如果匹配成功 */
if( xMatchFound != pdFALSE )
{
/*
* eventCLEAR_EVENTS_ON_EXIT_BIT为0x01000000UL
* 表示事件退出时,是否需要删除事件位
*/
if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 )
{
uxBitsToClear |= uxBitsWaitedFor; /* 获取要删除的位 */
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 将任务从事件列表中移除,添加到就绪列表中 */
( void ) xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
}
pxListItem = pxNext; /* 指向下一个阻塞的任务 */
}
pxEventBits->uxEventBits &= ~uxBitsToClear; /* 删除事件位 */
}
( void ) xTaskResumeAll(); /* 恢复调度器 */
return pxEventBits->uxEventBits; /* 返回事件位 */
}
该函数是中断版的事件位设置,用于中断函数。
函数原型如下:
/********************************************************
参数:xEventGroup:事件标志组的句柄
返回:EventBits_t:事件位
*********************************************************/
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
函数源代码如下:
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
{
UBaseType_t uxSavedInterruptStatus;
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn;
/* 关闭中断,进入临界区 */
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
{
uxReturn = pxEventBits->uxEventBits;
}
/* 开启中断,退出临界区 */
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
return uxReturn;
}
函数 | 描述 |
---|---|
xEventGroupClearBits() | 将指定的事件位清零, 用在任务中 |
xEventGroupClearBitsFromISR() | 将指定的事件位清零,用在中断服务函数中 |
函数原型如下:
/********************************************************
参数:xEventGroup:事件标志组的句柄
uxBitsToClear:需要清除的事件位
返回:EventBits_t:事件位
*********************************************************/
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
函数源代码如下:
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
{
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn;
configASSERT( xEventGroup );
configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
taskENTER_CRITICAL(); /* 进入临界区 */
{
traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear );
/* 获取事件标志位 */
uxReturn = pxEventBits->uxEventBits;
/* 清除事件标志位 */
pxEventBits->uxEventBits &= ~uxBitsToClear;
}
taskEXIT_CRITICAL(); /* 退出临界区 */
return uxReturn;
}
清除事件标志组中事件位的中断版本,用于中断函数中。
函数原型如下:
/********************************************************
参数:xEventGroup:事件标志组的句柄
uxBitsToClear:需要清除的事件位
返回:BaseType_t:事件位
*********************************************************/
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
函数源代码如下:
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
{
BaseType_t xReturn;
traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear );
xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL );
return xReturn;
}
函数 | 描述 |
---|---|
xEventGroupGetBits | 获取当前事件标志组的值(各个事件位的值),用在任务中 |
xEventGroupGetBitsFromISR() | 获取当前事件标志组的值, 用在中断服务中 |
函数通过宏定义,其调用函数xEventGroupClearBits(),如下:
#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )
通过函数xEventGroupClearBits(),可以返回当前事件位,同时设置清除的事件位为0,即不清除事件位。
通过函数xEventGroupGetBits(),并不会阻塞函数,而是通过其返回值判断来执行相应的程序。
该函数获取事件位,用于中断服务函数中。
函数原型如下:
/********************************************************
参数:xEventGroup:事件标志组的句柄
返回:EventBits_t:事件位
*********************************************************/
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
函数源代码如下:
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
{
UBaseType_t uxSavedInterruptStatus;
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn;
/* 进入临界区 */
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
{
uxReturn = pxEventBits->uxEventBits;
}
/* 退出临界区 */
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
return uxReturn;
}
函数xEventGroupWaitBits()可以在阻塞状态下等待事件组中一个或者多个事件。
函数原型如下:
/********************************************************
参数:
xEventGroup:事件标志组的句柄
uxBitsToWaitFor:需要等待的事件位
xClearOnExit:若为pdTURE,退出时,所有事件位删除
若为pdFALSE,退出时,事件位不删除
xWaitForAllBits:若为pdTURE,所有事件位都为1或阻塞时间到,则有效
若为pdFALSE,任意其中一个为1或阻塞时间到,则有效
xTicksToWait:设置阻塞事件,单位为节拍数
返回:EventBits_t:事件位
*********************************************************/
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait )
函数源代码如下:
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
{
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn, uxControlBits = 0;
BaseType_t xWaitConditionMet, xAlreadyYielded;
BaseType_t xTimeoutOccurred = pdFALSE;
configASSERT( xEventGroup );
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
configASSERT( uxBitsToWaitFor != 0 );
/* 如果使能函数xTaskGetSchedulerState()或启动软件定时器功能 */
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
vTaskSuspendAll(); /* 挂起任务调度器 */
{
const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;
/* 判断当前事件位是否匹配 */
xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );
/* 如果当前事件位符合要求 */
if( xWaitConditionMet != pdFALSE )
{
uxReturn = uxCurrentEventBits;
xTicksToWait = ( TickType_t ) 0;
/* 如果退出时,需要删除事件位,则进入 */
if( xClearOnExit != pdFALSE )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* 如果设置阻塞时间为0 */
else if( xTicksToWait == ( TickType_t ) 0 )
{
uxReturn = uxCurrentEventBits;
}
else
{
/* 如果退出时,需要删除事件位,则进入 */
if( xClearOnExit != pdFALSE )
{
/* 设置相应的控制位,高8位中 */
uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 如果需要等待所有的事件位为1,则有效 */
if( xWaitForAllBits != pdFALSE )
{
/* 设置相应的控制位,在高8位中 */
uxControlBits |= eventWAIT_FOR_ALL_BITS;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 将任务添加到相应的事件列表中 */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );
uxReturn = 0;
traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
}
}
xAlreadyYielded = xTaskResumeAll(); /* 恢复任务调度器,可能会执行任务切换 */
/* 如果设置的阻塞时钟节拍数不为0 */
if( xTicksToWait != ( TickType_t ) 0 )
{
/* 恢复调度器时没有进行任务切换 */
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API(); /* 执行任务切换 */
}
else
{
mtCOVERAGE_TEST_MARKER();
}
uxReturn = uxTaskResetEventItemValue(); /* 获取事件列表项的项值 */
/* eventUNBLOCKED_DUE_TO_BIT_SET用来表示任务已经解挂 */
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
{
taskENTER_CRITICAL(); /* 进入临界区 */
{
uxReturn = pxEventBits->uxEventBits;
/* 如果事件位符合匹配 */
if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
{
/* 如果设置事件退出时清除事件位 */
if( xClearOnExit != pdFALSE )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL(); /* 退出临界区 */
xTimeoutOccurred = pdFALSE;
}
else
{
/* 执行到这里,表示任务已经解除阻塞态 */
}
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; /* 清除控制位 */
}
traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );
return uxReturn;
}
函数原型如下:
/********************************************************
参数:
xEventGroup:事件标志组的句柄
uxBitsToWaitFor:需要等待的事件位
xClearOnExit:若为pdTURE,退出时,所有事件位删除
若为pdFALSE,退出时,事件位不删除
xWaitForAllBits:若为pdTURE,所有事件位都为1或阻塞时间到,则有效
若为pdFALSE,任意其中一个为1或阻塞时间到,则有效
xTicksToWait:设置阻塞事件,单位为节拍数
返回:EventBits_t:事件位
*********************************************************/
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits )
函数源代码如下:
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits )
{
BaseType_t xWaitConditionMet = pdFALSE;
/* 如果某个事件位为1,则有效 */
if( xWaitForAllBits == pdFALSE )
{
/* 如果匹配到某个事件位 */
if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( EventBits_t ) 0 )
{
xWaitConditionMet = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else /* 要全部设置的事件位为1,则有效 */
{
/* 如果所有的事件位都为1 */
if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor )
{
xWaitConditionMet = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
return xWaitConditionMet;
}
void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait )
{
configASSERT( pxEventList );
configASSERT( uxSchedulerSuspended != 0 );
/* 设置相应的列表项中的项值 */
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );
/* 将任务插入到事件列表中 */
vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );
/* 添加当前任务到延时列表中 */
prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
}
函数xEventGroupSync()能使多个任务彼此之间同步。
函数原型如下:
/********************************************************
参数:
xEventGroup:事件标志组的句柄
uxBitsToSet:设置事件位
uxBitsToWaitFor:需要等待的事件位
xTicksToWait:设置阻塞事件,单位为节拍数
返回:EventBits_t:事件位
*********************************************************/
EventBits_t xEventGroupSync(EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
const EventBits_t uxBitsToWaitFor,
TickType_t xTicksToWait )
函数源代码如下:
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait )
{
EventBits_t uxOriginalBitValue, uxReturn;
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
BaseType_t xAlreadyYielded;
BaseType_t xTimeoutOccurred = pdFALSE;
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
configASSERT( uxBitsToWaitFor != 0 );
/* 如果使能函数xTaskGetSchedulerState()或启动软件定时器功能 */
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
vTaskSuspendAll(); /* 挂起调度器 */
{
uxOriginalBitValue = pxEventBits->uxEventBits; /* 记录原有事件位 */
( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet );
/* 如果所有事件位都为1 */
if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor )
{
uxReturn = ( uxOriginalBitValue | uxBitsToSet );
pxEventBits->uxEventBits &= ~uxBitsToWaitFor; /* 清除事件位 */
xTicksToWait = 0;
}
else
{
/* 如果设置阻塞时间xTicksToWait不为0 */
if( xTicksToWait != ( TickType_t ) 0 )
{
traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor );
/* 将任务添加到相应的事件列表中 */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait );
uxReturn = 0;
}
else
{
uxReturn = pxEventBits->uxEventBits;
}
}
}
xAlreadyYielded = xTaskResumeAll(); /* 恢复调度器,有可能进行任务切换 */
/* 如果设置阻塞时间xTicksToWait不为0 */
if( xTicksToWait != ( TickType_t ) 0 )
{
/* 如果没有进行任务切换 */
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 获取事件列表项的项值 */
uxReturn = uxTaskResetEventItemValue();
/* eventUNBLOCKED_DUE_TO_BIT_SET用来任务已经解挂 */
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
{
/* 进入临界区 */
taskENTER_CRITICAL();
{
uxReturn = pxEventBits->uxEventBits;
/* 如果设置事件退出时清除事件位 */
if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL(); /* 退出临界区 */
xTimeoutOccurred = pdTRUE;
}
else
{
/* 执行到这里,表示任务已经解除阻塞态 */
}
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; /* 清除高8位的控制位 */
}
traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred );
return uxReturn;
}
当使用事件组进行任务同步时,有:
假设有任务A、任务B、任务C三个任务。任务A的执行是需要任务B、任务C同步后才进行下一步。我们不能使用函数xEventGroupSetBits()和函数xEventGroupWaitBits()。
而对于函数xEventGroupSync()即使任务B和任务C事件位被删除,但记录了原有的事件位uxOriginalBitValue,通过变量uxOriginalBitValue判断达到任务A同步。