您的位置:首页 > 娱乐 > 八卦 > 幼儿园主题网络图设计 大班_企业网址下载_2021时事政治热点50条_如何拥有自己的网站

幼儿园主题网络图设计 大班_企业网址下载_2021时事政治热点50条_如何拥有自己的网站

2024/12/23 10:46:00 来源:https://blog.csdn.net/weixin_52849254/article/details/143696517  浏览:    关键词:幼儿园主题网络图设计 大班_企业网址下载_2021时事政治热点50条_如何拥有自己的网站
幼儿园主题网络图设计 大班_企业网址下载_2021时事政治热点50条_如何拥有自己的网站

FreeRTOS 提供了事件标志组的一些相关操作函数,如下表所示:

创建一个事件组

xEventGroupCreate() 动态方式创建事件标志组

xEventGroupCreate()用于创建一个事件组,并返回对应的句柄。 要想使用该函数必须
在头文件 FreeRTOSConfig.h 定义宏 configSUPPORT_DYNAMIC_ALLOCATION 为 1(在FreeRTOS.h 中默认定义为 1) 。


#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
/*** @brief 创建一个事件组。** 此函数用于创建一个新的事件组,并初始化其成员变量。* 事件组可以用来同步多个任务之间的状态。** @return 返回新创建的事件组句柄,如果内存分配失败则返回NULL。*/
EventGroupHandle_t xEventGroupCreate( void )
{EventGroup_t * pxEventBits;/* 分配事件组内存。* 偏离MISRA规则的原因如下:* pvPortMalloc() 总是确保返回的内存块符合MCU堆栈的对齐要求。* 在这种情况下,pvPortMalloc() 必须返回一个指针,该指针保证满足 EventGroup_t 结构的对齐要求* (如果跟踪下去,就是 TickType_t 类型的对齐要求,因为 EventBits_t 本身是 TickType_t 类型)。* 因此,只要堆栈对齐要求大于或等于 TickType_t 的对齐要求,转换就是安全的。* 在其他情况下,如果架构的自然字大小小于 sizeof(TickType_t),TickType_t 变量将通过两次或多次读取操作访问,* 对齐要求只是每次单独读取的对齐要求。*/pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); /*lint !e9087 !e9079 见上述注释。*/if( pxEventBits != NULL ){pxEventBits->uxEventBits = 0; // 初始化事件位为0vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); // 初始化等待事件的任务列表#if ( configSUPPORT_STATIC_ALLOCATION == 1 ){/* 如果支持静态和动态分配,则记录此事件组是动态分配的。 */pxEventBits->ucStaticallyAllocated = pdFALSE;}#endif /* configSUPPORT_STATIC_ALLOCATION */traceEVENT_GROUP_CREATE( pxEventBits ); // 调用跟踪宏记录事件组创建}else{traceEVENT_GROUP_CREATE_FAILED(); /*lint !e9063 否则分支仅用于跟踪,如果未定义跟踪宏,则不会生成代码。*/}return pxEventBits;
}#endif /* configSUPPORT_DYNAMIC_ALLOCATION */

函数 xEventGroupCreate,用于创建一个新的事件组。具体功能如下:

  1. 内存分配:使用 pvPortMalloc 分配 EventGroup_t 结构体所需的内存。

  2. 初始化

    • 将事件位 uxEventBits 初始化为 0。

    • 初始化等待事件的任务列表 xTasksWaitingForBits

    • 如果支持静态分配,记录此事件组是动态分配的。

  3. 跟踪

    • 如果内存分配成功,调用 traceEVENT_GROUP_CREATE 记录事件组创建。

    • 如果内存分配失败,调用 traceEVENT_GROUP_CREATE_FAILED 记录创建失败。

事件创建函数,顾名思义, 就是创建一个事件,与其他内核对象一样,都是需要先创
建才能使用的资源, FreeRTOS 给我们提供了一个创建事件的函数xEventGroupCreate(),当创建一个事件时, 系统会首先给我们分配事件控制块的内存空间,然后对该事件控制块进行基本的初始化,创建成功返回事件句柄;创建失败返回 NULL。

xEventGroupCreateStatic () 静态方式创建事件标志组

#if ( configSUPPORT_STATIC_ALLOCATION == 1 )EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer ){EventGroup_t * pxEventBits;/* 必须提供一个 StaticEventGroup_t 对象。 */configASSERT( pxEventGroupBuffer );#if ( configASSERT_DEFINED == 1 ){/* 检查声明 StaticEventGroup_t 变量的结构体大小是否等于实际事件组结构体的大小。 */volatile size_t xSize = sizeof( StaticEventGroup_t );configASSERT( xSize == sizeof( EventGroup_t ) );} /*lint !e529 如果定义了 configASSERT(),则 xSize 会被引用。 */#endif /* configASSERT_DEFINED *//* 用户提供了静态分配的事件组 - 使用它。 */pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 !e9087 EventGroup_t 和 StaticEventGroup_t 故意别名化,以隐藏数据,并保证具有相同大小和对齐要求 - 通过 configASSERT() 检查。 */if( pxEventBits != NULL ){pxEventBits->uxEventBits = 0; // 初始化事件位为0vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); // 初始化等待事件的任务列表#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ){/* 如果同时支持静态和动态分配,则记录此事件组是静态创建的,以防以后删除事件组。 */pxEventBits->ucStaticallyAllocated = pdTRUE;}#endif /* configSUPPORT_DYNAMIC_ALLOCATION */traceEVENT_GROUP_CREATE( pxEventBits ); // 调用跟踪宏记录事件组创建}else{/* xEventGroupCreateStatic 应该只在 pxEventGroupBuffer 指向预分配(编译时分配)的 StaticEventGroup_t 变量时被调用。 */traceEVENT_GROUP_CREATE_FAILED(); /*lint !e9063 否则分支仅用于跟踪,如果未定义跟踪宏,则不会生成代码。*/}return pxEventBits;}#endif /* configSUPPORT_STATIC_ALLOCATION */

函数 xEventGroupCreateStatic,用于创建一个静态事件组。具体功能如下:

  1. 参数检查

    • 检查传入的 pxEventGroupBuffer 是否为 NULL,并进行断言。

    • 检查 StaticEventGroup_t 和 EventGroup_t 的大小是否一致,确保结构体的兼容性。

  2. 内存分配

    • 使用传入的 pxEventGroupBuffer 作为事件组的内存。

  3. 初始化

    • 将事件位 uxEventBits 初始化为 0。

    • 初始化等待事件的任务列表 xTasksWaitingForBits

    • 如果支持动态分配,记录此事件组是静态分配的。

  4. 跟踪

    • 如果内存分配成功,调用 traceEVENT_GROUP_CREATE 记录事件组创建。

    • 如果内存分配失败,调用 traceEVENT_GROUP_CREATE_FAILED 记录创建失败。

事件删除函数vEventGroupDelete()

在很多场合,某些事件只用一次的,就好比在事件应用场景说的危险机器的启动,假
如各项指标都达到了,并且机器启动成功了,那这个事件之后可能就没用了,那就可以进行销毁了。想要删除事件怎么办? FreeRTOS 给我们提供了一个删除事件的函数——
vEventGroupDelete(),使用它就能将事件进行删除了。当系统不再使用事件对象时,可以通过删除事件对象控制块来释放系统资源 。

void vEventGroupDelete( EventGroupHandle_t xEventGroup )
{EventGroup_t * pxEventBits = xEventGroup;const List_t * pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );vTaskSuspendAll();{traceEVENT_GROUP_DELETE( xEventGroup ); // 调用跟踪宏记录事件组删除while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 ){/* 解阻塞任务,返回0,因为事件列表正在被删除,因此不可能有任何位被设置。 */configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );vTaskRemoveFromUnorderedEventList( 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(); // 恢复所有任务
}

函数 vEventGroupDelete,用于删除一个事件组。具体功能如下:

  1. 参数解析

    • 将 EventGroupHandle_t 类型的 xEventGroup 转换为 EventGroup_t 类型的指针 pxEventBits

    • 获取等待事件的任务列表 pxTasksWaitingForBits

  2. 任务调度暂停

    • 调用 vTaskSuspendAll 暂停任务调度,确保在删除事件组时不会有任务干扰。

  3. 跟踪

    • 调用 traceEVENT_GROUP_DELETE 记录事件组删除。

  4. 解阻塞任务

    • 遍历等待事件的任务列表,逐个解阻塞任务,并返回0,因为事件列表正在被删除,因此不可能有任何位被设置。

  5. 内存释放

    • 根据配置选项 configSUPPORT_DYNAMIC_ALLOCATION 和 configSUPPORT_STATIC_ALLOCATION,决定是否释放事件组的内存:

      • 如果只支持动态分配,直接释放内存。

      • 如果同时支持静态和动态分配,检查事件组是否是动态分配的,如果是则释放内存,否则不做任何操作。

  6. 恢复任务调度

    • 调用 xTaskResumeAll 恢复任务调度。

vEventGroupDelete()用于删除由函数 xEventGroupCreate()创建的事件组, 只有被创建成功的事件才能被删除,但是需要注意的是该函数不允许在中断里面使用。 当事件组被删除之后,阻塞在该事件组上的任务都会被解锁,并向等待事件的任务返回事件组的值为 0。

事件组置位函数

xEventGroupSetBits()事件组置位函数

xEventGroupSetBits()用于置位事件组中指定的位, 当位被置位之后,阻塞在该位上的任务将会被解锁。 使用该函数接口时,通过参数指定的事件标志来设定事件的标志位,然后遍历等待在事件对象上的事件等待列表,判断是否有任务的事件激活要求与当前事件对象标志值匹配,如果有,则唤醒该任务。简单来说,就是设置我们自己定义的事件标志位为 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 ); /* lint !e826 !e740 !e9087 使用 mini list 结构作为列表结束标志,以节省 RAM。这是有效的。 */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 ){/* 只查找单个位被设置。 */if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 ){xMatchFound = pdTRUE;}else{mtCOVERAGE_TEST_MARKER(); // 覆盖测试标记}}else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor ){/* 所有位都被设置。 */xMatchFound = pdTRUE;}else{/* 需要所有位都被设置,但并非所有位都被设置。 */}if( xMatchFound != pdFALSE ){/* 位匹配。退出时是否应清除这些位? */if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 ){uxBitsToClear |= uxBitsWaitedFor;}else{mtCOVERAGE_TEST_MARKER(); // 覆盖测试标记}/* 在从事件列表中移除任务之前,将实际的事件标志值存储在任务的事件列表项中。设置 eventUNBLOCKED_DUE_TO_BIT_SET 位,以便任务知道它是由于所需的位匹配而解除阻塞,而不是因为超时。 */vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );}/* 移动到下一个列表项。注意这里不使用 pxListItem->pxNext,因为列表项可能已被从事件列表中移除并插入到就绪/待读取列表中。 */pxListItem = pxNext;}/* 清除当控制字中的 eventCLEAR_EVENTS_ON_EXIT_BIT 位被设置时匹配的位。 */pxEventBits->uxEventBits &= ~uxBitsToClear;}( void ) xTaskResumeAll(); // 恢复所有任务return pxEventBits->uxEventBits; // 返回当前的事件位
}

函数 xEventGroupSetBits,用于设置事件组中的位。具体功能如下:

  1. 参数解析

    • 将 EventGroupHandle_t 类型的 xEventGroup 转换为 EventGroup_t 类型的指针 pxEventBits

    • 获取等待事件的任务列表 pxList 和列表结束标志 pxListEnd

  2. 2参数检查

    • 检查 xEventGroup 是否为 NULL

    • 检查 uxBitsToSet 是否包含内核自身使用的位。

  3. 任务调度暂停

    • 调用 vTaskSuspendAll 暂停任务调度,确保在设置事件位时不会有任务干扰。

  4. 跟踪

    • 调用 traceEVENT_GROUP_SET_BITS 记录设置事件位。

  5. 设置位

    • 将 uxBitsToSet 设置到事件组的 uxEventBits 中。

  6. 检查任务

    • 遍历等待事件的任务列表,逐个检查任务等待的位是否与新设置的位匹配。

    • 如果匹配,根据控制位决定是否清除这些位,并解除任务的阻塞。

  7. 清除位

    • 清除当控制字中的 eventCLEAR_EVENTS_ON_EXIT_BIT 位被设置时匹配的位。

  8. 恢复任务调度

    • 调用 xTaskResumeAll 恢复任务调度。

  9. 返回结果

    • 返回当前的事件位。

xEventGroupSetBitsFromISR() 事件组中断置位函数

#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet,BaseType_t * pxHigherPriorityTaskWoken ){BaseType_t xReturn;/* 记录从中断服务例程设置事件位的操作。 */traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet );/* 调用 xTimerPendFunctionCallFromISR 函数,将设置事件位的操作挂起到一个定时器回调函数中执行。参数包括回调函数指针、事件组句柄、要设置的位以及一个指向更高优先级任务唤醒标志的指针。注意:lint 工具警告可以忽略,因为强制转换为 void* 是安全的,回调函数会将其转换回原始类型。 */xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */return xReturn;}#endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */

函数 xEventGroupSetBitsFromISR,用于从中断服务例程(ISR)中设置事件组中的位。具体功能如下:

  1. 条件编译

    • 只有在 configUSE_TRACE_FACILITYINCLUDE_xTimerPendFunctionCall 和 configUSE_TIMERS 均为 1 的情况下,才会编译这段代码。

  2. 函数声明

    • BaseType_t xEventGroupSetBitsFromISR(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t * pxHigherPriorityTaskWoken)

      • xEventGroup:事件组句柄。

      • uxBitsToSet:要设置的位。

      • pxHigherPriorityTaskWoken:指向一个标志的指针,用于指示是否有更高优先级的任务被唤醒。

  3. 记录操作

    • traceEVENT_GROUP_SET_BITS_FROM_ISR(xEventGroup, uxBitsToSet):调用跟踪宏记录从 ISR 设置事件位的操作。

  4. 调用定时器回调函数

    • xTimerPendFunctionCallFromISR(vEventGroupSetBitsCallback, (void *) xEventGroup, (uint32_t) uxBitsToSet, pxHigherPriorityTaskWoken)

      • vEventGroupSetBitsCallback:回调函数指针,用于实际设置事件位。

      • (void *) xEventGroup:事件组句柄,强制转换为 void * 类型。

      • (uint32_t) uxBitsToSet:要设置的位,强制转换为 uint32_t 类型。

      • pxHigherPriorityTaskWoken:指向一个标志的指针,用于指示是否有更高优先级的任务被唤醒。

      • 注意:lint 工具警告可以忽略,因为强制转换为 void * 是安全的,回调函数会将其转换回原始类型。

  5. 返回结果

    • 返回 xTimerPendFunctionCallFromISR 的结果,表示操作是否成功。

#if ( INCLUDE_xTimerPendFunctionCall == 1 )BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend,void * pvParameter1,uint32_t ulParameter2,BaseType_t * pxHigherPriorityTaskWoken ){DaemonTaskMessage_t xMessage;BaseType_t xReturn;/* 完成消息并将其发送到守护任务。 */xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR; // 设置消息 IDxMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend; // 设置回调函数xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1; // 设置第一个参数xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2; // 设置第二个参数/* 从中断服务例程向队列发送消息。 */xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );/* 记录从中断服务例程挂起函数调用的操作。 */tracePEND_FUNC_CALL_FROM_ISR( xFunctionToPend, pvParameter1, ulParameter2, xReturn );return xReturn;}#endif /* INCLUDE_xTimerPendFunctionCall */

函数 xTimerPendFunctionCallFromISR,用于从中断服务例程(ISR)中挂起一个函数调用。具体功能如下:

  1. 条件编译

    • 只有在 INCLUDE_xTimerPendFunctionCall 为 1 的情况下,才会编译这段代码。

  2. 函数声明

    • BaseType_t xTimerPendFunctionCallFromISR(PendedFunction_t xFunctionToPend, void * pvParameter1, uint32_t ulParameter2, BaseType_t * pxHigherPriorityTaskWoken)

      • xFunctionToPend:要挂起的回调函数指针。

      • pvParameter1:传递给回调函数的第一个参数。

      • ulParameter2:传递给回调函数的第二个参数。

      • pxHigherPriorityTaskWoken:指向一个标志的指针,用于指示是否有更高优先级的任务被唤醒。

  3. 消息初始化

    • 创建一个 DaemonTaskMessage_t 类型的消息结构体 xMessage

    • 设置消息的 xMessageID 为 tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR,表示这是一个从中断服务例程执行回调函数的命令。

    • 设置消息的回调函数、第一个参数和第二个参数。

  4. 发送消息

    • 调用 xQueueSendFromISR 函数,将消息发送到定时器队列 xTimerQueue

    • xQueueSendFromISR 函数的第三个参数 pxHigherPriorityTaskWoken 用于指示是否有更高优先级的任务被唤醒。

  5. 记录操作

    • 调用 tracePEND_FUNC_CALL_FROM_ISR 宏记录从中断服务例程挂起函数调用的操作。

  6. 返回结果

    • 返回 xQueueSendFromISR 的结果,表示操作是否成功。

xEventGroupSync()设置事件标志位,并等待事件标志位

此函数一般用于多任务同步,其中每个任务都必须等待其他任务达到同步点,然后才能继续执行。

/*** @brief 事件组同步函数* * 该函数用于在多个任务之间进行同步。它会设置指定的事件位,并等待指定的事件位被设置。* 如果在指定的超时时间内没有完成同步,则返回当前的事件位值。* * @param xEventGroup 事件组句柄* @param uxBitsToSet 要设置的事件位* @param uxBitsToWaitFor 要等待的事件位* @param xTicksToWait 等待的最长时间(ticks)* @return EventBits_t 返回当前的事件位值*/
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet,const EventBits_t uxBitsToWaitFor,TickType_t xTicksToWait )
{EventBits_t uxOriginalBitValue, uxReturn;EventGroup_t * pxEventBits = xEventGroup;BaseType_t xAlreadyYielded;BaseType_t xTimeoutOccurred = pdFALSE;// 断言检查:确保等待的事件位不包含控制字节,并且等待的事件位不为0configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );configASSERT( uxBitsToWaitFor != 0 );// 如果配置了调度器状态检查或定时器支持,则进一步检查调度器是否挂起#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ){configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );}#endif// 暂停所有任务调度vTaskSuspendAll();{// 获取当前的事件位值uxOriginalBitValue = pxEventBits->uxEventBits;// 设置指定的事件位( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet );// 检查设置后的事件位是否满足等待的条件if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor ){// 所有需要的事件位都已设置,无需阻塞uxReturn = ( uxOriginalBitValue | uxBitsToSet );// 清除已经设置的事件位pxEventBits->uxEventBits &= ~uxBitsToWaitFor;// 设置等待时间为0,表示不需要阻塞xTicksToWait = 0;}else{// 如果设置了等待时间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;xTimeoutOccurred = pdTRUE;}}}// 恢复任务调度xAlreadyYielded = xTaskResumeAll();// 如果设置了等待时间if( xTicksToWait != ( TickType_t ) 0 ){if( xAlreadyYielded == pdFALSE ){// 如果没有发生上下文切换,手动进行一次上下文切换portYIELD_WITHIN_API();}else{// 覆盖测试标记mtCOVERAGE_TEST_MARKER();}// 任务阻塞等待所需的事件位被设置uxReturn = uxTaskResetEventItemValue();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;}// 记录事件组同步结束traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred );// 防止编译器警告( void ) xTimeoutOccurred;return uxReturn;
}
  1. 参数检查

    • 使用 configASSERT 宏检查 uxBitsToWaitFor 是否包含控制字节,并且不为0。

    • 如果配置了调度器状态检查或定时器支持,则进一步检查调度器是否挂起。

  2. 暂停任务调度

    • 调用 vTaskSuspendAll() 暂停所有任务调度,确保在修改事件组时不会发生竞态条件。

  3. 获取当前事件位值

    • 从 pxEventBits->uxEventBits 获取当前的事件位值。

  4. 设置指定的事件位

    • 调用 xEventGroupSetBits(xEventGroup, uxBitsToSet) 设置指定的事件位。

  5. 检查设置后的事件位是否满足等待条件

    • 如果 ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor,则所有需要的事件位都已设置,无需阻塞。

    • 清除已经设置的事件位。

    • 设置等待时间为0,表示不需要阻塞。

    • 返回当前的事件位值。

  6. 处理未满足条件的情况

    • 如果设置了等待时间 (xTicksToWait != 0):

      • 记录事件组同步阻塞。

      • 将任务添加到等待事件位的列表中,并进入阻塞状态。

      • 初始化返回值,避免编译器警告。

    • 如果没有设置等待时间 (xTicksToWait == 0):

      • 直接返回当前事件位值,并设置超时标志。

  7. 恢复任务调度

    • 调用 xTaskResumeAll() 恢复任务调度。

    • 检查是否发生了上下文切换,如果没有,手动进行一次上下文切换。

  8. 处理任务阻塞等待

    • 如果设置了等待时间:

      • 任务阻塞等待所需的事件位被设置。

      • 如果任务因事件位被设置而解除阻塞,返回当前事件位值。

      • 如果任务超时,返回当前事件位值,并清除已经设置的事件位。

  9. 清除控制字节

    • 清除返回值中的控制字节。

  10. 记录事件组同步结束

    • 记录事件组同步结束。

  11. 防止编译器警告

    • 使用 (void) xTimeoutOccurred 防止编译器警告。

  12. 返回结果

    • 返回当前的事件位值。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com