FreeRTOS任务通知

2023-05-16

——————(正点原子FreeRTOS学习笔记)
开始学习FreeRTOS,学习参考书籍和视频来自正点原子FreeRTOS源码详解与应用开发,北京航空航天大学出版社
1    任务通知简介
        任务通知在 FreeRTOS 中是一个可选的功能,要使用任务通知的话就需要将宏 configUSE_TASK_NOTIFICATIONS 定义为 1。 FreeRTOS 的每个任务都有一个 32 位的通知值,任务控制块中的成员变量 ulNotifiedValue 就是这个通知值。任务通知是一个事件,假如某个任务通知的接收任务因为等待任务通知而阻 塞的话,向这个接收任务发送任务通知以后就会解除这个任务的阻塞状态。也可以更新接收任 务的任务通知值,任务通知可以通过如下方法更新接收任务的通知值:
● 不覆盖接收任务的通知值(如果上次发送给接收任务的通知还没被处理)。
● 覆盖接收任务的通知值。
● 更新接收任务通知值的一个或多个 bit。
● 增加接收任务的通知值。
        合理、灵活的使用上面这些更改任务通知值的方法可以在一些场合中替代队列、二值信号 量、计数型信号量和事件标志组。使用任务通知来实现二值信号量功能的时候,解除任务阻塞 的时间比直接使用二值信号量要快 45%(FreeRTOS 官方测试结果,使用 v8.1.2 版本中的二值信 号量,GCC 编译器,-O2 优化的条件下测试的,没有使能断言函数 configASSERT()),并且使用 的 RAM 更少!
        任务通知的发送使用函数 xTaskNotify()或者 xTaskNotifyGive()(还有此函数的中断版本)来 完成,这个通知值会一直被保存着,直到接收任务调用函数 xTaskNotifyWait()或者 ulTaskNotifyTake()来获取这个通知值。假如接收任务因为等待任务通知而阻塞的话那么在接收 到任务通知以后就会解除阻塞态。
        任务通知虽然可以提高速度,并且减少 RAM 的使用,但是任务通知也是有使用限制的:
● FreeRTOS 的任务通知只能有一个接收任务,其实大多数的应用都是这种情况。
● 接收任务可以因为接收任务通知而进入阻塞态,但是发送任务不会因为任务通知发送 失败而阻塞。
2     发送任务通知
            任务通知发送函数有 6 个,如表 17.2.1 所示:
1 、函数 xTaskNotify()
        此函数用于发送任务通知,此函数发送任务通知的时候带有通知值,此函数是个宏,真正 执行的函数 xTaskGenericNotify(),函数原型如下:
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,
                                        uint32_t ulValue,
                                        eNotifyAction eAction )
参数:
        xTaskToNotify : 任务句柄,指定任务通知是发送给哪个任务的。
        ulValue : 任务通知值。
        eAction : 任务通知更新的方法,eNotifyAction 是个枚举类型,在文件 task.h 中有如下
定义:
        typedef enum
        {
                eNoAction = 0,
                eSetBits, //更新指定的 bit
                eIncrement,  //通知值加一
                eSetValueWithOverwrite,  //覆写的方式更新通知值
                eSetValueWithoutOverwrite //不覆写通知值
        } eNotifyAction;
        此参数可以选择枚举类型中的任意一个,不同的应用环境其选择也不同。
返回值:
        pdFAIL:     当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有 更新成功就返回 pdFAIL。
        pdPASS:     eAction 设置为其他选项的时候统一返回 pdPASS。
2 、函数 xTaskNotifyFromISR()
        此函数用于发送任务通知,是函数 xTaskNotify()的中断版本,此函数是个宏,真正执行的 是函数 xTaskGenericNotifyFromISR(),此函数原型如下:
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,
                                                    uint32_t ulValue,
                                                    eNotifyAction eAction,
                                                    BaseType_t * pxHigherPriorityTaskWoken );
参数:
        xTaskToNotify : 任务句柄,指定任务通知是发送给哪个任务的。
        ulValue : 任务通知值。
        eAction : 任务通知更新的方法。
        pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动 设置的,用户不用进行设置,用户只需要提供一个变量来保存这
个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之 前一定要进行一次任务切换。
返回值:
        pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有 更新成功就返回 pdFAIL。
        pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。
3 、函数 xTaskNotifyGive()
        发送任务通知,相对于函数 xTaskNotify(),此函数发送任务通知的时候不带有通知值。此 函数只是将任务通知值简单的加一,此函数是个宏,真正执行的是函数 xTaskGenericNotify(), 此函数原型如下:
        BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
参数:
        xTaskToNotify : 任务句柄,指定任务通知是发送给哪个任务的。
返回值:
        pdPASS: 此函数只会返回 pdPASS。
4 、函数 vTaskNotifyGiveFromISR()
        此函数为 xTaskNotifyGive()的中断版本,用在中断服务函数中,函数原型如下:
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle,
                                                BaseType_t *  pxHigherPriorityTaskWoken );
参数:
        xTaskToNotify : 任务句柄,指定任务通知是发送给哪个任务的。
        pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动
        设置的,用户不用进行设置,用户只需要提供一个变量来保存这 个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之 前一定要进行一次任务切换。
返回值:
        无。
5 、函数 xTaskNotifyAndQuery()
        此函数和 xTaskNotify()很类似,此函数比 xTaskNotify()多一个参数,此参数用来保存更新 前的通知值。此函数是个宏,真正执行的是函数 xTaskGenericNotify(),此函数原型如下:
BaseType_t xTaskNotifyAndQuery ( TaskHandle_t xTaskToNotify,
                                                        uint32_t ulValue,
                                                        eNotifyAction eAction
                                                        uint32_t * pulPreviousNotificationValue);
参数:
        xTaskToNotify : 任务句柄,指定任务通知是发送给哪个任务的。
        ulValue : 任务通知值。
        eAction : 任务通知更新的方法。
        pulPreviousNotificationValue:用来保存更新前的任务通知值。
返回值:
        pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有 更新成功就返回 pdFAIL。
        pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。
6 、函数 xTaskNotifyAndQueryFromISR()
        此函数为 xTaskNorityAndQuery()的中断版本,用在中断服务函数中。此函数同样为宏,真 正执行的是函数 xTaskGenericNotifyFromISR(),此函数的原型如下:
        BaseType_t xTaskNotifyAndQueryFromISR ( TaskHandle_t xTaskToNotify,
                                                                            uint32_t ulValue,
                                                                            eNotifyAction eAction,
                                                                            uint32_t * pulPreviousNotificationValue
                                                                            BaseType_t *  pxHigherPriorityTaskWoken );
参数:
        xTaskToNotify : 任务句柄,指定任务通知是发送给哪个任务的。
        ulValue : 任务通知值。
        eAction : 任务通知更新的方法。
        pulPreviousNotificationValue:用来保存更新前的任务通知值。
        pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动
        设置的,用户不用进行设置,用户只需要提供一个变量来保存这 个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之 前一定要进行一次任务切换。
返回值:
        pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有 更新成功就返回 pdFAIL。
        pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。
3  任务通知通用发送函数
3.1  任务级任务通知通用发送函数
        在 17.2 小节中我们学习了 3 个任务级任务通知发送函数:xTaskNotify()、xTaskNotifyGive() 和 xTaskNotifyAndQuery(),这三个函数最终调用的都是函数 xTaskGenericNotify()!此函数在文 件 tasks.c 中有如下定义,缩减后的函数如下:
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, //任务句柄
                                                    uint32_t ulValue, //任务通知值
                                                    eNotifyAction eAction, //任务通知更新方式
                                                    uint32_t *  pulPreviousNotificationValue )//保存更新前的
//任务通知值
{
    TCB_t * pxTCB;
    BaseType_t xReturn = pdPASS;
    uint8_t ucOriginalNotifyState;
    configASSERT( xTaskToNotify );
    pxTCB = ( TCB_t * ) xTaskToNotify;
    taskENTER_CRITICAL();
    {
        if( pulPreviousNotificationValue != NULL ) (1)
        {
            *pulPreviousNotificationValue = pxTCB->ulNotifiedValue; (2)
        }
        ucOriginalNotifyState = pxTCB->ucNotifyState; (3)
        pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;  (4)
        switch( eAction )
        {
            case eSetBits :  (5)
            pxTCB->ulNotifiedValue |= ulValue;
            break;
            case eIncrement : (6)
            ( pxTCB->ulNotifiedValue )++;
            break;
            case eSetValueWithOverwrite :  (7)
            pxTCB->ulNotifiedValue = ulValue;
            break;
            case eSetValueWithoutOverwrite : (8)
            if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
            {
                pxTCB->ulNotifiedValue = ulValue;
            }
            else
            {
                xReturn = pdFAIL;
            }
            break;
            case eNoAction:
            break;
        }
        traceTASK_NOTIFY();
//如果任务因为等待任务通知而进入阻塞态的话就需要解除阻塞
        if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) (9)
        {
                ( void ) uxListRemove( &( pxTCB->xStateListItem ) );  (10)
                prvAddTaskToReadyList( pxTCB );  (11)
/********************省略相关的条件编译代码************************/
                if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) (12)
                {
                    //解除阻塞的任务优先级比当前运行的任务优先级高,所以需要进行
                    //任务切换。
                    taskYIELD_IF_USING_PREEMPTION();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    taskEXIT_CRITICAL();
    return xReturn;  (13)
}
(1)、判断参数 pulPreviousNotificationValue 是否有效,因为此参数用来保存更新前的任务通 知值。
(2)、如果参数 pulPreviousNotificationValue 有效的话就用此参数保存更新前的任务通知值。
(3)、保存任务通知状态,因为下面会修改这个状态,后面我们要根据这个状态来确定是否 将任务从阻塞态解除。
(4)、更新任务通知状态为 taskNOTIFICATION_RECEIVED。
(5)、根据不同的更新方式做不同的处理,如果为 eSetBits 的话就将指定的 bit 置 1。也就是 更新接收任务通知值的一个或多个 bit。
(6)、如果更新方式为 eIncrement 的话就将任务通知值加一。
(7)、如果更新方式为 eSetValueWithOverwrite 的话就直接覆写原来的任务通知值。
(8)、如果更新方式为 eSetValueWithoutOverwrite 的话就需要判断原来的任务通知值是否被 处理,如果已经被处理了就更新为任务通知值。如果此前的任务通知值话没有被处理的话就标 记 xReturn 为 pdFAIL,后面会返回这个值。
(9)、根据(3)中保存的接收任务之前的状态值来判断是否有任务需要解除阻塞,如果在任务 通知值被更新前任务处于 taskWAITING_NOTIFICATION 状态的话就说明有任务因为等待任务 通知值而进入了阻塞态。
(10)、将任务从状态列表中移除。
(11)、将任务重新添加到就绪列表中。
(12)、判断刚刚解除阻塞的任务优先级是否比当前正在运行的任务优先级高,如果是的话需 要进行一次任务切换。
(13)、返回 xReturn 的值,pdFAIL 或 pdPASS。
3.2  中断级任务通知发送函数
        中 断 级 任 务 通 知 发 送 函 数 也 有 三 个 , 分 别 为 : xTaskNotifyFromISR() 、 xTaskNotifyAndQueryFromISR()和 vTaskNotifyGiveFromISR()。其中函数 xTaskNotifyFromISR() 和 xTaskNotifyAndQueryFromISR()最终调用的都是函数 xTaskGenericNotifyFromISR(),此函数 的原型如下:
BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify,
                                                                uint32_t ulValue,
                                                                eNotifyAction eAction,
                                                                uint32_t *  pulPreviousNotificationValue,
                                                                BaseType_t * pxHigherPriorityTaskWoken )
参数:
        xTaskToNotify : 任务句柄,指定任务通知是发送给哪个任务的。
        ulValue : 任务通知值。
        eAction : 任务通知更新的方法。
        pulPreviousNotificationValue:用来保存更新前的任务通知值。
        pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动 设置的,用户不用进行设置,用户只需要提供一个变量来保存这 个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之 前一定要进行一次任务切换。
返回值:
        pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有 更新成功就返回 pdFAIL。
        pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。
        函数 xTaskGenericNotifyFromISR()在文件 tasks.c 中有定义,函数源码如下:
BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify,
                                                                uint32_t ulValue,
                                                                eNotifyAction eAction,
                                                                uint32_t *  pulPreviousNotificationValue,
                                                                BaseType_t * pxHigherPriorityTaskWoken )
{
        TCB_t * pxTCB;
        uint8_t ucOriginalNotifyState;
        BaseType_t xReturn = pdPASS;
        UBaseType_t uxSavedInterruptStatus;
        configASSERT( xTaskToNotify );
        portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
        pxTCB = ( TCB_t * ) xTaskToNotify;
        uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
        {
                if( pulPreviousNotificationValue != NULL ) (1)
                {
                    *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
                }
                ucOriginalNotifyState = pxTCB->ucNotifyState; (2)
                pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;  (3)
                switch( eAction )  (4)
                {
                    case eSetBits :
                    pxTCB->ulNotifiedValue |= ulValue;
                    break;
                    case eIncrement  :
                    ( pxTCB->ulNotifiedValue )++;
                    break;
                    case eSetValueWithOverwrite :
                    pxTCB->ulNotifiedValue = ulValue;
                    break;
                    case eSetValueWithoutOverwrite :
                            if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
                            {
                                pxTCB->ulNotifiedValue = ulValue;
                            }
                            else
                            {
                                xReturn = pdFAIL;
                            }
                            break;
                    case eNoAction :
                            break;
                }
                traceTASK_NOTIFY_FROM_ISR();
                //如果任务因为等待任务通知而进入阻塞态的话就需要解除阻塞
                if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) (5)
                {
                    configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
                    if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) (6)
                    {
                            ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
                            prvAddTaskToReadyList( pxTCB );
                    }
                    else (7)
                    {
                        vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
                    }
                    if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) (8)
                    {
                        //解除阻塞的任务优先级比当前运行任务的优先级高,所以需要标记
                        //在退出中断服务函数的时候需要做任务切换。
                        if( pxHigherPriorityTaskWoken != NULL )
                        {
                                *pxHigherPriorityTaskWoken = pdTRUE;
                        }
                        else
                        {
                            xYieldPending = pdTRUE;
                        }
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
        }
        portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
        return xReturn;
 }
(1)、判断参数 pulPreviousNotificationValue 是否有效,因为此参数用来保存更新前的任务通 知值。如果参数 pulPreviousNotificationValue 有效的话就用此参数保存更新前的任务通知值。
(2)、保存任务通知状态,因为下面会修改这个状态,后面我们要根据这个状态来确定是否 将任务解除阻塞态。
(3)、更新任务通知状态 taskNOTIFICATION_RECEIVED。
(4)、根据不同的通知值更新方式来做不同的处理,与函数 xTaskGenericNotify()的处理过程 一样。
(5)、根据(2)中保存的接收任务之前的状态值来判断是否有任务需要解除阻塞,如果在任务 通知值被更新前任务处于 taskWAITING_NOTIFICATION 状态的话就说明有任务因为等待任务 通知值而进入了阻塞态。
(6)、判断任务调度器是否上锁,如果调度器没有上锁的话就将任务从状态列表中移除,然 后重新将任务添加到就绪列表中。
(7)、如果任务调度器上锁了的话就将任务添加到列表 xPendingReadyList 中。
(8)、判断任务解除阻塞的任务优先级是否比当前任务优先级高,如果是的话就将 pxHigherPriorityTaskWoken 标记 pdTRUE。如果参数 pxHigherPriorityTaskWoken 无效的话就将 全局变量 xYieldPending 标记为 pdTRUE。 还有另外一个用于中断服务函数的任务通知发送函数 vTaskNotifyGiveFromISR(),此函数 和xTaskGenericNotifyFromISR()极其类似。此函数用于将任务通知值加一,大家可以自行分析 一下此函数。
4  获取任务通知
        获取任务通知的函数有两个,如表 17.4.1 所示:
1 、函数 ulTaskNotifyTake()
        此函数为获取任务通知函数,当任务通知用作二值信号量或者计数型信号量的时候可以使 用此函数来获取信号量,函数原型如下:
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit,
                                            TickType_t xTicksToWait );
参数:
        xClearCountOnExit : 参数为 pdFALSE 的话在退出函数 ulTaskNotifyTake()的时候任务通知值 减一,类似计数型信号量。当此参数为 pdTRUE 的话在退出函数的时候 任务任务通知值清零,类似二值信号量。
xTickToWait:  阻塞时间。
返回值:
        任何值  : 任务通知值减少或者清零之前的值。
        此函数在文件 tasks.c 中有定义,代码如下:
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
{
    uint32_t ulReturn;
    taskENTER_CRITICAL();
    {
        if( pxCurrentTCB->ulNotifiedValue == 0UL )  (1)
        {
            pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; (2)
            if( xTicksToWait > ( TickType_t ) 0 )  (3)
            {
                prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
                traceTASK_NOTIFY_TAKE_BLOCK();
                portYIELD_WITHIN_API();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    taskEXIT_CRITICAL();
    taskENTER_CRITICAL();
    {
        traceTASK_NOTIFY_TAKE();
        ulReturn = pxCurrentTCB->ulNotifiedValue;  (4)
        if( ulReturn != 0UL )  (5)
        {
            if( xClearCountOnExit != pdFALSE ) (6)
            {
                pxCurrentTCB->ulNotifiedValue = 0UL;
            }
            else
            {
                pxCurrentTCB->ulNotifiedValue = ulReturn - 1; (7)
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
        pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; (8)
    }
        taskEXIT_CRITICAL();
        return ulReturn;
}
(1)、判断任务通知值是否为 0,如果为 0 的话说明还没有接收到任务通知。
(2)、修改任务通知状态为 taskWAITING_NOTIFICATION。
(3)、如果阻塞时间不为 0 的话就将任务添加到延时列表中,并且进行一次任务调度。
(4)、如果任务通知值不为 0 的话就先获取任务通知值。
(5)、任务通知值大于 0。
(6)、参数 xClearCountOnExit 不为 pdFALSE,那就将任务通知值清零。
(7)、如果参数 xClearCountOnExit 为 pdFALSE 的话那就将任务通知值减一。
(8)、更新任务通知状态为 taskNOT_WAITING_NOTIFICATION。
2 、函数 xTaskNotifyWait()
        此函数也是用来获取任务通知的,不过此函数比 ulTaskNotifyTake()更为强大,不管任务通 知用作二值信号量、计数型信号量、队列和事件标志组中的哪一种,都可以使用此函数来获取 任务通知。但是当任务通知用作位置信号量和计数型信号量的时候推荐使用函数 ulTaskNotifyTake()。此函数原型如下:
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
                                            uint32_t ulBitsToClearOnExit,
                                            uint32_t * pulNotificationValue,
                                            TickType_t xTicksToWait );
参数:
    ulBitsToClearOnEntry: :当没有接收到任务通知的时候将任务通知值与此参数的取反值进行按 位与运算,当此参数为 0xffffffff 或者 ULONG_MAX 的时候就会将任务
通知值清零。
    ulBitsToClearOnExit: :如果接收到了任务通知,在做完相应的处理退出函数之前将任务通知值 与此参数的取反值进行按位与运算,当此参数为 0xffffffff 或者 ULONG_MAX 的时候就会将任务通知值清零。
    pulNotificationValue :此参数用来保存任务通知值。
    xTickToWait:  阻塞时间。
返回值:
    pdTRUE : 获取到了任务通知。
    pdFALSE : 任务通知获取失败。
    此函数在文件 tasks.c 中有定义,代码如下:
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
                                                uint32_t ulBitsToClearOnExit,
                                                uint32_t * pulNotificationValue,
                                                TickType_t xTicksToWait )
{
    BaseType_t xReturn;
    taskENTER_CRITICAL();
    {
        if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED ) (1)
        {
            pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry; (2)
            pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; (3)
            if( xTicksToWait > ( TickType_t ) 0 )  (4)
            {
                prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
                traceTASK_NOTIFY_WAIT_BLOCK();
                portYIELD_WITHIN_API();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    taskEXIT_CRITICAL();
    taskENTER_CRITICAL();
    {
        traceTASK_NOTIFY_WAIT();
        if( pulNotificationValue != NULL )  (5)
        {
            *pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
        }
        if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION ) (6)
        {
            xReturn = pdFALSE;
        }
        else
        {
            pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;  (7)
            xReturn = pdTRUE;
        }
        pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; (8)
    }
    taskEXIT_CRITICAL();
    return xReturn;
}
(1)、任务同通状态不为 taskNOTIFICATION_RECEIVED。
(2)、将任务通知值与参数 ulBitsToClearOnEntry 的取反值进行按位与运算。
(3)、任务通知状态改为 taskWAITING_NOTIFICATION。
(4)、如果阻塞时间大于 0 的话就要将任务添加到延时列表中,并且进行一次任务切换。
(5)、如果任务通知状态为 taskNOTIFICATION_RECEIVED,并且参数 pulNotificationValue 有效的话就保存任务通知值。
(6)、如果任务通知的状态又变为 taskWAITING_NOTIFICATION 的话就标记 xRetur 为 pdFALSE。
(7)、如果任务通知的状态一直为 taskNOTIFICATION_RECEIVED 的话就将任务通知的值 与参数 ulBitsToClearOnExit 的取反值进行按位与运算,并且标记 xReturn 为 pdTRUE,表示获 取任务通知成功。
(8)、标记任务通知的状态为 taskNOT_WAITING_NOTIFICATION。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS任务通知 的相关文章

  • FreeRTOS记录(七、FreeRTOS信号量、事件标志组、邮箱和消息队列、任务通知的关系)

    我们在前面单独介绍过FreeRTOS的任务通知和消息队列 但是在FreeRTOS中任务间的通讯还有信号量 邮箱 事件组标志等可以使用 这篇文章就这些成员与消息队列和任务通知的关系进行说明分析 增加邮箱部分 任务通知发送消息 Demo 202
  • 一文教你学会keil软件仿真

    仿真在我们调试代码中是非常重要的 通过仿真 我们可以快速定位到错误代码 或者错误逻辑的地方 这里我就以上一篇博客为例 教大家如何软件仿真 软件仿真不需要单片机 直接通过keil软件进行代码调试 一 打开工具 二 选择软件仿真 三 开始仿真
  • 【FreeRTOS】多任务创建

    作者主页 凉开水白菜 作者简介 共同学习 互相监督 热于分享 多加讨论 一起进步 专栏资料 https pan baidu com s 1nc1rfyLiMyw6ZhxiZ1Cumg pwd free 点赞 收藏 再看 养成习惯 订阅的粉丝
  • Freertos中vTaskDelay()是怎么用的

    1 常见的使用场景 void vLED Task void pvParameters while 1 Heartbeat LED vTaskDelay 1000 portTICK RATE MS 说明 上面这段代码的意思是 led翻转后经过
  • 【FreeRTOS】队列的使用

    作者主页 凉开水白菜 作者简介 共同学习 互相监督 热于分享 多加讨论 一起进步 专栏资料 https pan baidu com s 1nc1rfyLiMyw6ZhxiZ1Cumg pwd free 点赞 收藏 再看 养成习惯 订阅的粉丝
  • FreeRTOS打印任务对CPU的占有率

    1 配置RTOS 1 打开RTOS Config Parameter 找到Run Time And Task States gathering related definitions 使能GENERATE RUN TIME STATS US
  • FreeRTOS记录(九、一个裸机工程转FreeRTOS的实例)

    记录一下一个实际项目由裸机程序改成FreeRTOS 以前产品的平台还是C8051单片机上面的程序 硬件平台改成了STM32L051 同时使用STM32CubeMX生成的工程 使用FreeRTOS系统 EEPROM数据存储读取函数修改更新 2
  • freeRTOS使用uxTaskGetStackHighWaterMark函数查看任务堆栈空间的使用情况

    摘要 每个任务都有自己的堆栈 堆栈的总大小在创建任务的时候就确定了 此函数用于检查任务从创建好到现在的历史剩余最小值 这个值越小说明任务堆栈溢出的可能性就越大 FreeRTOS 把这个历史剩余最小值叫做 高水位线 此函数相对来说会多耗费一点
  • FreeRTOS临界段和开关中断

    http blog sina com cn s blog 98ee3a930102wg5u html 本章教程为大家讲解两个重要的概念 FreeRTOS的临界段和开关中断 本章教程配套的例子含Cortex M3内核的STM32F103和Co
  • stm32f103zet6移植标准库的sdio驱动

    sdio移植 st官网给的标准库有给一个用于st出的评估板的sdio外设实现 但一是文件结构有点复杂 二是相比于国内正点原子和野火的板子也有点不同 因此还是需要移植下才能使用 当然也可以直接使用正点原子或野火提供的实例 但为了熟悉下sdio
  • FreeRTOS之软件定时器

    FreeRTOS之软件定时器 声明 本人按照正点原子的FreeRTOS例程进行学习的 欢迎各位大佬指责和批评 谢谢 include sys h include delay h include usart h include led h in
  • 啊哈C的简单使用

    打开啊哈C 新建一个程序输出hello world include
  • Arduino IDE将FreeRTOS用于STM32

    介绍 适用于STM32F103C8的FreeRTOS STM32F103C是一种能够使用FreeRTOS的ARM Cortex M3处理器 我们直接在Arduino IDE中开始使用STM32F103C8的FreeRTOS 我们也可以使用K
  • FreeRTOS实时操作系统(三)任务挂起与恢复

    系列文章 FreeRTOS实时操作系统 一 RTOS的基本概念 FreeRTOS实时操作系统 二 任务创建与任务删除 HAL库 FreeRTOS实时操作系统 三 任务挂起与恢复 FreeRTOS实时操作系统 四 中断任务管理 FreeRTO
  • FreeRTOS 配置TICK_RATE_HZ

    我使用的是带有 5 4 版 FreeRTOS 的 MSP430f5438 我有一个有趣的问题 我无法弄清楚 基本上 当我将 configTICK RATE HZ 设置为不同的值时 LED 闪烁得更快或更慢 它应该保持相同的速率 我将 con
  • 当一个任务写入变量而其他任务读取该变量时,我们是否需要信号量?

    我正在研究 freeRtos 并且我有一个名为 x 的变量 现在 每秒只有一个任务正在写入该变量 而其他任务正在读取该变量值 我需要用互斥锁来保护变量吗 如果变量为 32 位或更小 并且其值是独立的并且不与任何其他变量一起解释 则不需要互斥
  • 如何将 void* 转换为函数指针?

    我在 FreeRTOS 中使用 xTaskCreate 其第四个参数 void const 是传递给新线程调用的函数的参数 void connect to foo void const task params void on connect
  • FreeRTOS 匈牙利表示法 [重复]

    这个问题在这里已经有答案了 我是 RTOS 和 C 编程的新手 而且我仍在习惯 C 的良好实践 因此 我打开了一个使用 FreeRTOS 的项目 我注意到操作系统文件使用匈牙利表示法 我知道一点符号 但面临一些新的 标准 FreeRTOS
  • GNU Arm Cortex m4 上的 C++ 异常处理程序与 freertos

    2016 年 12 月更新现在还有一个关于此行为的最小示例 https community nxp com message 862676 https community nxp com message 862676 我正在使用带有 free
  • 小型 ARM 微控制器的 RTOS 内核之间的可量化差异 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 有许多不同的 RTOS 可用于微控制器 我专门寻找支持 ARM Cortex M 处理器的 RTOS 另外 我对闭源解决方案不感兴趣 试图从网站

随机推荐

  • 树苺派TF卡备份/还原镜像

    树苺派TF卡备份 还原镜像 TF卡备份TF卡还原 备份和还原树莓派TF卡镜像推荐在Linux下进行 TF卡备份 在Ubuntu下插入装有Raspbian的TF卡会直接挂载 xff0c 挂载后的盘在 dev下显示为 34 dev sdx 34
  • 通过dockerfile 创建镜像以及更新镜像

    制作Docker镜像 1 安装 Docker Docker 要求 CentOS 系统的内核版本高于 3 10 查看当前系统的版本 uname r 安装 Docker 软件包和依赖包 yum y install docker 安装完成 从远程
  • RT-Thread 线程同步及通信 -- 信号量、互斥量、事件、邮箱、消息队列

    目录 一 RT Thread 信号量 二 RT Thread 互斥量 三 RT Thread 事件标志组 四 RT Thread 邮箱 五 RT Thread 消息队列 一 RT Thread 信号量 1 信号量相关函数 创建信号量 64
  • Fiddler抓不到浏览器包的常见原因

    代理未设置成功 fiddler 之所以能抓包 xff0c 本质上是因为浏览器 App 软件设置了代理为 fiddler 一旦遇到抓不到包的情况 xff0c 首先应排查浏览器代理是否设置正确 以 Chrome 为例 xff0c 代理设置为 x
  • 经典 SQL 数据库笔试题及答案整理

    马上又是金三银四啦 xff0c 有蛮多小伙伴在跳槽找工作 xff0c 但对于年限稍短的软件测试工程师 xff0c 难免会需要进行笔试 xff0c 而在笔试中 xff0c 基本都会碰到一道关于数据库的大题 xff0c 今天这篇文章呢 xff0
  • 软件测试项目实战(web+app+h5+小程序)

    没有实战经验 xff0c 简历不好编写 xff0c 而且也不好就业 今天给大家分享一个非常适合练手的软件测试项目 xff0c 此项目涵盖web端 app端 h5端 小程序端 xff0c 可以说非常之全面 获取方式在文末 项目介绍 项目名 x
  • 基础软件照搬开源不可取,自力更生才是正途

    最近有关开源软件的话题始终牢牢占据着IT界的新闻头条 xff0c Log4j开源软件的惊天漏洞 Fake js的作者也惊天删库跑路了 xff0c CurL的作者怒怼苹果只会白嫖开源却不出力 xff0c Linux的祖师爷Linus也不知所云
  • ADB 命令知多少?详细 ADB 命令大全来啦

    一 ADB 简介 1 什么是 ADB ADB 全称为 Android Debug Bridge xff0c 起到调试桥的作用 xff0c 是一个客户端 服务器端程序 其中客户端是用来操作的电脑 xff0c 服务端是 Android 设备 A
  • 软测面试如何介绍项目?要做哪些技术准备?

    测试人员在找工作中 xff0c 基本都会碰到让介绍项目的这种面试题 xff0c 如何正确介绍自己的项目 xff1f 需要做哪些技术准备 xff1f 今天这篇文章 xff0c 围绕这些问题 xff0c 跟大家一起聊一聊 Q 关于介绍自己的项目
  • 看完即会,抓取微信小程序数据包教程

    在给学员答疑的时候 xff0c 有很多小伙伴问到能不能抓取到微信小程序数据呢 xff1f 答案当然是肯定的 xff0c 通过Fiddler或者Charles这些主流的抓包工具都可以抓得到 xff0c 在IOS平台抓取微信小程序和https请
  • 金三银四必备软件测试刷题神器,刷完还怕面试不过吗?

    小编热衷于收集整理资源 xff0c 记录踩坑到爬坑的过程 希望能把自己所学 xff0c 实际工作中使用的技术 学习方法 心得及踩过的一些坑 xff0c 记录下来 也希望想做软件测试的你一样 xff0c 通过我的分享可以少走一些弯路 xff0
  • 今天面了一个来阿里要求月薪23K,明显感觉他背了很多面试题...

    最近有朋友去阿里面试 xff0c 面试前后进行了20天左右 xff0c 包含4轮电话面试 1轮笔试 1轮主管视频面试 1轮hr视频面试 据他所说 xff0c 80 的人都会栽在第一轮面试 xff0c 要不是他面试前做足准备 xff0c 估计
  • 转行软件测试,亲身经历的面试题

    写的有点多 xff0c 耐心看完哦 xff5e 这些都是我每次面试完记录了 xff0c 一共面了五家公司的真实面试 43 2次旁听 43 1次电话面试 xff0c 有的写的不全 xff0c 仅作为参考 xff0c 题目有的是我提炼出来的面试
  • 从字节出来的测试总监,让我们用这份《测试用例规范》,再也没加班过

    经常看到无论是刚入职场的新人 xff0c 还是工作了一段时间的老人 xff0c 都会对编写测试用例感到困扰 xff1f 例如 xff1a 固然 xff0c 编写一份好的测试用例需要 xff1a 充分的需求分析能力 43 理论及经验加持 xf
  • 软件测试之边界值三点分析法

    一 定义 边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法 通常边界值分析法是作为对等价类划分法的补充 xff0c 这种情况下 xff0c 其测试用例来自等价类的边界 边界值分析法是对等价类划分法做补充的一种黑盒测试设计方法
  • 因果图与判定表法

    1 什么是因果图及判定表法 xff1f 因果图是用图解的方法表示输入的各种组合关系 xff0c 依据因果图写出判定表 xff0c 从而设计相应的测试用例 它适合于检查程序输入条件的各种组合情况 例约束关系 组合关系 2 因果图之4种因果关系
  • Linux系统远程服务器没有图形化界面怎么解决?本地浏览器打开远程服务器jupyter notebook

    linux系统远程服务器没有图形化界面 xff0c 也无法安装浏览器 xff0c 直接打开jupyter notebook会出现下面的提示 No web browser found could not locate runnable bro
  • 时代落在英伟达身上的是粒什么沙,国产GPU的机会又在哪?

    天道好轮回 xff0c 苍天饶过谁 近日英伟达称 xff0c 他们被要求停止向中国出口两种用于数据中心的GPU A100和H100 xff0c AMD也表示 xff0c 已经收到新的要求 xff0c MI250出口到中国将会受限 A100
  • 【日常·闲谈】芯片外围电路如何设计?

    听从你心 xff0c 无问西东 开了一个新系列 xff0c 很多时候想分享一些很有趣的内容 xff0c 但又不想为此花大量的时间去做语言梳理和技术资料查找 xff0c 久而久之就想不起来要写这个博客了 于是就想到了用闲谈的方法 xff0c
  • FreeRTOS任务通知

    xff08 正点原子FreeRTOS学习笔记 xff09 开始学习FreeRTOS 学习参考书籍和视频来自正点原子FreeRTOS源码详解与应用开发 xff0c 北京航空航天大学出版社 1 任务通知简介 任务通知在 FreeRTOS 中是一