Skip to content

任务通知

使用之前的彼变量的时候我们并不知道对方是谁, 使用任务通知的时候可以明确指定, 通知哪一个任务

使用任务东芝的时候不需要单独创建一个结构体, TCB里面包含有这一个对象

image-20231119202528802

image-20231119202546285

c
    #if ( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];//通知的状态
    #endif

TCB里面使用这两个值进行信息的传递

c
    #define configTASK_NOTIFICATION_ARRAY_ENTRIES    1

其他任务向里面放入数据的时候不会进入阻塞, 只有成功和失败, 但是读取的时候可以进入等待

状态有三种

  • taskNOT_WAITING_NOTIFICATION:任务没有在等
  • taskWAITING_NOTIFICATION:任务在等待通知
  • taskNOTIFICATION_RECEIVED:任务接收到了通知,也被称为pending(有数据了,待处理)
c
#define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) /* 也是初始
状态 */
#define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 )
#define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 )

在写入数据的时候会顺带更改状态的值

函数

image-20231119203447988

  • 发送数据和接收
c
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t
*pxHigherPriorityTaskWoken );
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait
);

使用give会使得任务的通知值加一, 状态变为taskNOTIFICATION_RECEIVED

接收的时候通知值为0则阻塞, 通知大于零时候接收, 设置第一个参数为pdTRUE返回之前会清理把通知值清零, 设置为为pdFALSE的时候会把它减一, 返回的是值没有变化之前的通知值

**总结: **相当于一个轻量级信号量

  • 高级函数
c
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, 
                       uint32_t ulValue,
                       eNotifyAction eAction );
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,
                        uint32_t ulValue,
                        eNotifyAction eAction,
                        BaseType_t *pxHigherPriorityTaskWoken );

Notify的参数1是要通知的任务, 参数二是设置的值, 参数三设置怎么使用

image-20231119204527429

image-20231119204605510

image-20231119204620528

c
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
                        uint32_t ulBitsToClearOnExit,
                        uint32_t *pulNotificationValue,
                        TickType_t xTicksToWait );

image-20231119205104287

FreeRTOS实现

c
typedef struct tskTaskControlBlock
{
	...

	#if( configUSE_TASK_NOTIFICATIONS == 1 )
		volatile uint32_t ulNotifiedValue;	//记录任务通知的值
		volatile uint8_t ucNotifyState;		//记录任务是不是在等待任务通知
	#endif

	...

} tskTCB;
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 )
        {
            *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
        }
        //获取当前的状态
        ucOriginalNotifyState = pxTCB->ucNotifyState;

        pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
        //判断需要的操作
        switch( eAction )
        {
            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
                {
                    /* The value could not be written to the task. */
                    xReturn = pdFAIL;
                }
                break;

            case eNoAction:
                /* The task is being notified without its notify value being
					updated. */
                break;
        }
        /* 检查一下是不是在等待一个通知 */
        if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
        {
            ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
            prvAddTaskToReadyList( pxTCB );

            if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
            {
                /* The notified task has a priority above the currently
					executing task so a yield is required. */
                taskYIELD_IF_USING_PREEMPTION();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    taskEXIT_CRITICAL();

    return xReturn;
}