文章目录
- 事件组结构体
- 创建事件组
- 事件组等待位
- 事件组设置位
事件组结构体
// 路径:Source/event_groups.c
typedef struct xEventGroupDefinition
{EventBits_t uxEventBits;List_t xTasksWaitingForBits;
} EventGroup_t;
uxEventBits 中的每一位表示某个事件是否发生。 具体事件由程序员来确定,大小为uint32_t。
xTasksWaitingForBits 为等待事件链表。 若某个事件检测到uxEventBits中所需要的位没有置位,就会将自己保存在该链表中等待。
创建事件组
使用 xEventGroupCreate 函数进行事件组创建
EventGroupHandle_t xEventGroupCreate( void )// 1、申请事件组结构体 EventGroup_t 空间-> pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) );// 2、初始化结构体中uxEventBits 事件位-> pxEventBits->uxEventBits = 0;// 3、初始化等待事件组链表vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
事件组等待位
使用xEventGroupWaitBits 函数进行事件等待,函数定义如下:
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
第一参数 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 )// 1、关闭调度器,后面有详解-> vTaskSuspendAll(); {// 2、检查等待条件是否已经满足const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );// 3、等待条件已经满足,所以没有必要阻塞if( xWaitConditionMet != pdFALSE ) {// 4、判断退出前xClearOnExit 是否清零if( xClearOnExit != pdFALSE )pxEventBits->uxEventBits &= ~uxBitsToWaitFor; // 清零}// 判断是否愿意等待else if( xTicksToWait == ( TickType_t ) 0 )uxReturn = uxCurrentEventBits; // 不愿意等待,退出else{// 记录标志位if( xClearOnExit != pdFALSE )uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;if( xWaitForAllBits != pdFALSE )uxControlBits |= eventWAIT_FOR_ALL_BITS;}// 将调用任务正在等待的比特存储在任务的事件中列表项,以便内核知道何时找到匹配项。然后进入阻塞状态vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );// 把当前任务加入xEventListItem 链表中-> listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); -> vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );// 把当前任务从就绪链表移到等待链表中-> prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );}
vTaskSuspendAll函数 功能是关闭调度器。在之前的队列操作(包含信号量和互斥量操作)中无论是读还是写操作,第一步就是关中断。而在操作事件组的时候第一步却不需要直接关闭中断,只需要关闭调度器,这两者有什么区别呢?
对于队列操作,存在两种情况:
1、多个任务同时操作队列
2、中断 过程中可以对队列进行读写操作
考虑到第一种情况,多任务之间操作队列会相互影响,可以采取关闭调度器来解决,但是不能屏蔽掉中断中对队列的读写操作。如果只关闭调度器的话,中断对队列的操作同样会对正在的任务有影响。因此任务在对队列进行操作时,第一步一定是要关闭中断。
对于事件组操作,只存在任务之间的操作,中断过程中不会对事件组进行操作,因此只需要关闭调度器就可以实现任务之间对事件组操作的互斥。
事件组设置位
使用xEventGroupSetBits 函数进行事件设置
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )-> vTaskSuspendAll(); // 关闭调度器{// 1、设置对应的位pxEventBits->uxEventBits |= uxBitsToSet;// 2、唤醒所有满足条件的任务while( pxListItem != pxListEnd ){if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 ){if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )xMatchFound = pdTRUE;else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )xMatchFound = pdTRUE;// 从链表中移除vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );}}