首页 > 其他分享 >FreeRTOS 24:事件组EventGroup等待、清零、获取操作

FreeRTOS 24:事件组EventGroup等待、清零、获取操作

时间:2024-11-11 22:18:57浏览次数:3  
标签:24 FreeRTOS 清除 uxReturn 任务 pxEventBits 事件 xEventGroup 清零

等待事件标志位xEventGroupWaitBits()

既然标记了事件的发生,那么我怎么知道他到底有没有发生,这也是需要一个函数来获 取 事 件 是 否 已 经 发 生 , FreeRTOS 提 供 了 一 个 等 待 指 定 事 件 的 函 数 — —
xEventGroupWaitBits(),通过这个函数, 任务可以知道事件标志组中的哪些位,有什么事件发生了, 然后通过 “逻辑与”、“逻辑或”等操作对感兴趣的事件进行获取,并且这个函数实现了等待超时机制, 当且仅当任务等待的事件发生时,任务才能获取到事件信息。在这段时间中,如果事件一直没发生,该任务将保持阻塞状态以等待事件发生。当其它任务或中断服务程序往其等待的事件设置对应的标志位,该任务将自动由阻塞态转为就绪态。当任务等待的时间超过了指定的阻塞时间,即使事件还未发生,任务也会自动从阻塞态转移为就绪态。这样子很有效的体现了操作系统的实时性,如果事件正确获取(等待到) 则返回对应的事件标志位,由用户判断再做处理, 因为在事件超时的时候也会返回一个不能确定的事件值,所以需要判断任务所等待的事件是否真的发生。

EventGroupWaitBits()用于获取事件组中的一个或多个事件发生标志, 当要读取的事件标 志 位 没 有 被 置 位 时 任 务 将 进 入 阻 塞 等 待 状 态 。

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
                                 const EventBits_t uxBitsToWaitFor,
                                 const BaseType_t xClearOnExit,
                                 const BaseType_t xWaitForAllBits,
                                 TickType_t xTicksToWait )
{
    EventGroup_t * pxEventBits = 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 );
    #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();
            }
        }
        else if( xTicksToWait == ( TickType_t ) 0 )
        {
            // 等待条件未满足,但未指定阻塞时间,直接返回当前值
            uxReturn = uxCurrentEventBits;
            xTimeoutOccurred = pdTRUE;
        }
        else
        {
            // 任务将阻塞等待所需位被设置
            // 使用控制位记录此调用的行为
            if( xClearOnExit != pdFALSE )
            {
                uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }

            if( xWaitForAllBits != pdFALSE )
            {
                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();

    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( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
                {
                    if( xClearOnExit != pdFALSE )
                    {
                        pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }

                xTimeoutOccurred = pdTRUE;
            }
            taskEXIT_CRITICAL();
        }
        else
        {
            // 任务因位被设置而解除阻塞
        }

        // 任务阻塞,因此可能设置了控制位
        uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
    }

    traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );

    // 防止编译器警告
    ( void ) xTimeoutOccurred;

    return uxReturn;
}

xEventGroupWaitBits 函数用于等待事件组中的特定事件位被设置。具体功能和步骤如下:

  1. 参数检查

    • 检查传入的事件组是否有效。

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

    • 检查至少请求了一个位。

    • 如果配置了 INCLUDE_xTaskGetSchedulerState 或 configUSE_TIMERS,则检查调度器是否暂停并且等待时间不为零。

  2. 任务调度暂停

    • 暂停任务调度,防止其他任务干扰。

  3. 检查当前事件位

    • 获取当前事件位。

    • 检查等待条件是否已经满足。

      • 如果满足,直接返回当前事件位,并根据需要清除这些位。

      • 如果不满足且未指定阻塞时间,直接返回当前事件位并设置超时标志。

      • 如果不满足且指定了阻塞时间,将任务加入等待队列。

  4. 任务阻塞

    • 根据需要设置控制位,记录任务的行为。

    • 将任务加入等待队列,等待所需事件位被设置。

    • 恢复任务调度。

  5. 任务唤醒

    • 如果任务因事件位被设置而唤醒,返回当前事件位。

    • 如果任务因超时而唤醒,返回当前事件位并设置超时标志。

  6. 清除控制位

    • 返回前清除控制位,防止影响后续操作。

清零事件标志位

xEventGroupClearBits()与 xEventGroupClearBitsFromISR()都是用于清除事件组指定的位, 如果在获取事件的时候没有将对应的标志位清除, 那么就需要用这个函数来进行显式清除, xEventGroupClearBits()函数不能在中断中使用,而是由具有中断保护功能 的xEventGroupClearBitsFromISR() 来代替,中断清除事件标志位的操作在守护任务(也叫定时 器 服 务 任 务 ) 里 面 完 成 。 守 护 进 程 的 优 先 级 由 FreeRTOSConfig.h 中 的 宏configTIMER_TASK_PRIORITY 来 定 义 。

xEventGroupClearBits()清零事件标志位

EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
                                 const EventBits_t uxBitsToClear )
{
    EventGroup_t * pxEventBits = 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;
}

函数 xEventGroupClearBits,用于清除事件组中的指定位。

  1. 参数检查

    • configASSERT( xEventGroup );:检查事件组句柄是否有效。
    • configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );:确保要清除的位不包含内核保留的位。
  2. 进入临界区

    • taskENTER_CRITICAL();:进入临界区,防止多任务环境下的并发问题。
  3. 记录当前事件组值

    • uxReturn = pxEventBits->uxEventBits;:在清除位之前,记录当前事件组的值。
  4. 清除指定位

    • pxEventBits->uxEventBits &= ~uxBitsToClear;:通过按位与操作清除指定的位。
  5. 退出临界区

    • taskEXIT_CRITICAL();:退出临界区。
  6. 返回结果

    • return uxReturn;:返回清除位之前的事件组值。

xEventGroupClearBitsFromISR()在中断中清零事件标志位

#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )

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 ); /*lint !e9087 无法避免将指针强制转换为 void*,因为这是一个通用的回调函数,不是特定于此用例的。回调会将指针重新转换为原始类型,因此是安全的。 */

    // 返回挂起结果
    return xReturn;
}

#endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */

函数 xEventGroupClearBitsFromISR,用于在中断服务例程(ISR)中清除事件组中的指定位。具体功能如下:

  1. 参数检查:无显式的参数检查,但通过调用 xTimerPendFunctionCallFromISR 来确保安全。

  2. 记录事件:记录从中断服务例程清除事件组位的操作。

  3. 挂起函数调用:使用 xTimerPendFunctionCallFromISR 将清除位的操作挂起到调度器,以便在合适的时机执行。

  4. 返回结果:返回 xTimerPendFunctionCallFromISR 的结果,指示是否成功挂起函数调用。

获取事件组中各事件标志位的值xEventGroupGetBits()

EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
{
    UBaseType_t uxSavedInterruptStatus;
    EventGroup_t const * const pxEventBits = xEventGroup;
    EventBits_t uxReturn;

    // 保存当前的中断状态,防止中断嵌套
    uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
    {
        // 从事件组中读取当前的位值
        uxReturn = pxEventBits->uxEventBits;
    }
    // 恢复中断状态
    portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

    // 返回事件组的当前位值
    return uxReturn;
} /*lint !e818 EventGroupHandle_t 是一个在其他函数中使用的 typedef,因此不能是指向常量的指针。*//*lint !e818 EventGroupHandle_t is a typedef used in other functions to so can't be pointer to const. */

函数 xEventGroupGetBitsFromISR,用于在中断服务例程(ISR)中获取事件组的当前位。具体功能如下:

  1. 保存中断状态:使用 portSET_INTERRUPT_MASK_FROM_ISR 保存当前的中断状态,防止中断嵌套。

  2. 获取事件组位:从事件组中读取当前的位值。

  3. 恢复中断状态:使用 portCLEAR_INTERRUPT_MASK_FROM_ISR 恢复中断状态。

标签:24,FreeRTOS,清除,uxReturn,任务,pxEventBits,事件,xEventGroup,清零
From: https://blog.csdn.net/weixin_52849254/article/details/143696968

相关文章

  • 2024-11-11-Linux学习-基础篇(1)(鸟哥的LINUX私房菜 第四章)
    Linux的学习,也是一本大厚书,学起来。文章目录一、前言二、知识点2.1开始执行命令2.2日期与时间2.3日历2.4计算器2.4重要的热键2.4.1[TAB]2.4.2[Ctrl]-c2.4.3[Ctrl]-d2.4.4[Shift]+{[PageUP]l[PageDown]}按键小结一、前言  Linux命令学习,开始。二、......
  • CSP2024总结(学术版)
    J组T4一道/赛上觉得很难/下来也听说很难/但听老师一讲也觉得只有中位绿/的题。题目传送门,首先想到\(r=1\)时的做法,不难看出可以使用一个标记数组来存储,然后依次寻找离他最近的\(1\)看是否满足要求,标记即可。\(5\)pts拿到手。然后发现可以扩展出一种类似递推的思想,设\(f_......
  • CSP-J2024 复赛T1(洛谷P11227)题解
    前传作者初赛没过。坐标sd,79分过不了已经适应了。话说这次泄题事件闹得沸沸扬扬,都说各省分数线要降,最后sd降了8分,80。挺逆天的,感觉sd再这样下去一点OIer都要没了。思路桶排思想,用二维数组模拟一整副牌,本来做的时候是怕有重复牌才这样做,事实上不会。ACCode#include<bits/......
  • 2024.11.11总结
    John的农场是一张N*N的方格图,贝茜住在左上角(1,1),John住在右下角(N,N)。现在贝茜要去拜访John,每次都只能往四周与之相邻的方格走,并且每走一步消耗时间T。同时贝茜每走三步就要停下来在当前方格吃草,在每个方格吃草的用时是固定的,为H[i][j]。John想知道贝茜最少要多久才能到达Joh......
  • NOIP2024模拟赛#18 总结
    头要炸了。T1题面很好懂,手玩了一下发现答案最小是\((m-1)\timesn\)。可能会多出来一个长度为\(k\)的部分,会发现如果多出来一个长度为\(k\)的部分且合法,那么单个串\(1\simk\)位与\(n-k+1\simn\)位一定相同,\(k+1\simn\)位与\(1\simn-k\)一定相同。Hash判一下即......
  • 24/11/11 算法笔记<视觉> 换脸,人脸特征点检测
    先介绍一下换脸的简单步骤1、提取两张图片的脸部特征点2、为两张图片创建mask3、进行映射变换使得人脸对齐4、使用opencv的泊松融合将两张图片合成我们直接上代码1.导入代码包importmediapipeasmpfrommediapipe.tasksimportpythonfrommediapipe.tasks.pythoni......
  • ICPC2024 杭州
    省流:麻。Day\(-\infin\)今年一共分到两个ICPC名额。第一场ICPC,好耶。有两个神仙队友和一个采集,分别记为\(I,J,K\)。其中\(I\)是队长。期望不高,有个牌子就行。Day-1周五下午出发。出发前有一节体育课。体育老师:这个周日中午的体测啊,你们就.....我:?????(事后发现更......
  • 2024/11/11日工作总结
    完成数据结构pta实验题:6-3链表逆置:本题要求实现一个函数,将给定单向链表逆置,即表头置为表尾,表尾置为表头。链表结点定义如下:structListNode{intdata;structListNode*next;};函数接口定义:structListNode*reverse(structListNode*head);其中head是用户传入的链......
  • CSP-S 2024 游记
    前情提要:初赛\(54.5\),比去年还低\(2.5\),但是过了。考点在七中高新,在红杏酒家吃的午饭,在旁边酒店小睡了一会儿。进考场,机子还是一如既往地牛,但感觉键盘有点难用,是放在抽屉里的,但我强行拉到了桌子上。起初一直打不开代码回收系统,过后不知道怎么回事就打开了。看T1,一眼没读懂,......
  • 『模拟赛』NOIP2024加赛4
    Rank给我唐完了,又名,【MX-S5】梦熊NOIP2024模拟赛1。A.王国边缘好像简单倍增就做完了。由于昨天T5在我脑海中留下了挥之不去的印象,今天一上来看到这题就发现是一个内向基环树森林。然后被硬控硬控硬控,最后一个小点加一点优化就能过没调出来,挂30pts,菜菜菜菜菜。注......