引言
事件组是FreeRTOS中一种独特的同步机制,它使用位操作来实现多个事件的并发管理。与信号量和队列不同,事件组允许任务等待多个条件的组合,提供了"与"、"或"逻辑的灵活同步方式。本文将深入分析事件组的实现原理和应用技巧。
1. 事件组的核心概念
1.1 事件组的本质
事件组本质上是一个位图,每个位代表一个事件的状态:
/* 事件组的基本定义 */
typedef struct EventGroupDef_t
{
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;
/* 事件位的类型定义 */
#if configUSE_16_BIT_TICKS == 1
typedef uint16_t EventBits_t;
#else
typedef uint32_t EventBits_t;
#endif
/* 可用的事件位数量 */
#define eventEVENT_BITS_CONTROL_BYTES 2
#define eventCLEAR_EVENTS_ON_EXIT_BIT 24UL
#define eventUNBLOCKED_DUE_TO_BIT_SET 25UL
#define eventWAIT_FOR_ALL_BITS 26UL
/* 实际可用的事件位 */
#if configUSE_16_BIT_TICKS == 1
#define eventEVENT_BITS_AVAILABLE ( 16 - eventEVENT_BITS_CONTROL_BYTES )
#else
#define eventEVENT_BITS_AVAILABLE ( 32 - eventEVENT_BITS_CONTROL_BYTES )
#endif
设计特点:
-
位图表示:每个位代表一个独立事件
-
高效存储:32位系统可管理24个事件
-
灵活组合:支持任意事件组合的等待条件
1.2 事件组与其他同步机制的对比
| 特性 | 事件组 | 信号量 | 队列 |
|---|---|---|---|
| 数据存储 | 位状态 | 计数值 | 任意数据 |
| 等待条件 | 多位组合 | 单一条件 | 单一消息 |
| 唤醒方式 | 广播 | 单一任务 | 单一任务 |
| 内存占用 | 固定小 | 固定小 | 可变大 |
2. 事件组的创建与删除
2.1 动态创建事件组
/* 动态创建事件组 */
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
EventGroupHandle_t xEventGroupCreate( void )
{
EventGroup_t *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
traceEVENT_GROUP_CREATE( pxEventBits );
}
else
{
traceEVENT_GROUP_CREATE_FAILED();
}
return pxEventBits;
}
#endif
2.2 静态创建事件组
/* 静态创建事件组 */
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )
{
EventGroup_t *pxEventBits;
configASSERT( pxEventGroupBuffer );
/* 使用提供的缓冲区 */
pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer;
if( pxEventBits != NULL )
{
/* 初始化事件位 */
pxEventBits->uxEventBits = 0;
/* 初始化等待列表 */
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
/* 标记为静态分配 */
pxEventBits->ucStaticallyAllocated = pdTRUE;
traceEVENT_GROUP_CREATE( pxEventBits );
}
else
{
traceEVENT_GROUP_CREATE_FAILED();
}
return pxEventBits;
}
#endif
3. 事件位的设置与清除
3.1 设置事件位
/* 设置事件位 */
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
{
ListItem_t *pxListItem, *pxNext;
ListItem_t const *pxListEnd;
List_t const *pxList;
EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;
EventGroup_t *pxEventBits = xEventGroup;
BaseType_t xMatchFound = pdFALSE;
configASSERT( xEventGroup );
configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
pxList = &( pxEventBits->xTasksWaitingForBits );
pxListEnd = listGET_END_MARKER( pxList );
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;
/* 获取控制位 */
uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;
uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;
if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 )
{
/* 等待任意位(OR逻辑) */
if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )
{
xMatchFound = pdTRUE;
}
}
else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )
{
/* 等待所有位(AND逻辑) */
xMatchFound = pdTRUE;
&nb

最低0.47元/天 解锁文章
935

被折叠的 条评论
为什么被折叠?



