文章目錄
- 事件組結構體
- 創建事件組
- 事件組等待位
- 事件組設置位
事件組結構體
// 路徑: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 );}}