任务通知可以替代二进制信号量、计数信号量、事件组,可以替代长度为1的队列(可以保存一个32位整数或指针值),并且任务通知速度更快、使用的RAM更少。
先看一下任务TCB
/* 任务TCB */
typedef struct tskTaskControlBlock
{
volatile StackType_t *pxTopOfStack; /* 栈顶地址 */
ListItem_t xStateListItem; /* 状态列表项:运行、就绪、挂起、阻塞 */
ListItem_t xEventListItem; /* 事件列表项 */
UBaseType_t uxPriority; /* 优先级 */
StackType_t *pxStack; /* 栈指针 */
char pcTaskName[configMAX_TASK_NAME_LEN]; /* 任务名 */
......
#if (configUSE_MUTEXES == 1)
UBaseType_t uxBasePriority; /* 任务基础优先级 */
UBaseType_t uxMutexesHeld; /* 互斥锁持有数量 */
#endif
......
#if (configUSE_TASK_NOTIFICATIONS == 1)
volatile uint32_t ulNotifiedValue; /* 任务通知值 */
volatile uint8_t ucNotifyState; /* 任务通知状态 */
#endif
......
}tskTCB;
typedef tskTCB TCB_t;
任务通知有三种状态:taskNOT_WAITING_NOTIFICATION(非等待)、taskWAITING_NOTIFICATION(等待态)、taskNOTIFICATION_RECEIVED(接收态)
#define taskNOT_WAITING_NOTIFICATION ((uint8_t)0)
#define taskWAITING_NOTIFICATION ((uint8_t)1)
#define taskNOTIFICATION_RECEIVED ((uint8_t)2)
在任务初始化的时候,初始化任务通知值和任务通知状态
/* 初始化新任务TCB */
static void prvInitialiseNewTask(TaskFunction_t pxTaskCode, const char *const pcName, const uint32_t ulStackDepth,
void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pxCreatedTask,
TCB_t *pxNewTCB, const MemoryRegion_t *const xRegions)
{
......
#if (configUSE_TASK_NOTIFICATIONS == 1)
{
/* 任务通知值初始化为0 */
pxNewTCB->ulNotifiedValue = 0;
/* 任务通知状态初始化为不等待 */
pxNewTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
}
#endif
......
}
任务通知有四种通信方式:任务通知相关位置位、任务通知值加一、设置任务通知值(覆盖型)、设置任务通知值(非覆盖型)
/* 发送任务通知 */
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 = 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
{
xReturn = pdFAIL;
}
break;
/* 无操作 */
case eNoAction:
break;
default:
configASSERT(pxTCB->ulNotifiedValue == ~0UL);
break;
}
traceTASK_NOTIFY();
/* 任务原先处于等待态 */
if(ucOriginalNotifyState == taskWAITING_NOTIFICATION)
{
/* 将任务从延时列表中移除 */
(void)uxListRemove(&(pxTCB->xStateListItem));
/* 将任务重新插入就绪列表 */
prvAddTaskToReadyList(pxTCB);
configASSERT(listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) == NULL);
#if (configUSE_TICKLESS_IDLE != 0)
{
prvResetNextTaskUnblockTime();
}
#endif
/* 任务优先级高于当前任务优先级 */
if(pxTCB->uxPriority > pxCurrentTCB->uxPriority)
{
/* 请求切换任务 */
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* 退出临界区 */
taskEXIT_CRITICAL();
return xReturn;
}
进入之前先将ulBitsToClearOnEntry指定的任务通知值相关位清空,退出之前将ulBitsToClearOnExit指定的任务通知值相关位清空。
/* 接收任务通知值 */
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)
{
/* 在进入的时候将相关位清0 */
pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;
/* 将任务通知状态设置为等待态 */
pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;
/* 等待时间大于0 */
if(xTicksToWait > (TickType_t)0)
{
/* 将任务挂接到延时列表 */
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)
{
*pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
}
/* 任务通知状态不为可以接收态,说明超时 */
if(pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED)
{
xReturn = pdFALSE;
}
/* 说明成功接收到通知值 */
else
{
/* 退出之前清除相关位 */
pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
xReturn = pdTRUE;
}
/* 将任务通知状态设置为非等待态 */
pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
}
/* 退出临界区 */
taskEXIT_CRITICAL();
return xReturn;
}
ulBitsToClearOnExit为真则在退出之前将任务通知值清空,为假则在退出之前将任务通知值减一。
/* 接收任务通知(减一或清零) */
uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit, TickType_t xTicksToWait)
{
uint32_t ulReturn;
/* 进入临界区 */
taskENTER_CRITICAL();
{
/* 当前任务通知值为0 */
if(pxCurrentTCB->ulNotifiedValue == 0UL)
{
/* 任务通知设为等待态 */
pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;
/* 等待时间大于0 */
if(xTicksToWait > (TickType_t)0)
{
/* 将当前任务挂接到延时列表 */
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;
/* 任务通知值不为0 */
if(ulReturn != 0UL)
{
/* 在退出之前将任务通知值清除 */
if(xClearCountOnExit != pdFALSE)
{
pxCurrentTCB->ulNotifiedValue = 0UL;
}
/* 将任务通知值减1 */
else
{
pxCurrentTCB->ulNotifiedValue = ulReturn - (uint32_t)1;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 将任务通知状态设置为非等待态 */
pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
}
/* 退出临界区 */
taskEXIT_CRITICAL();
return ulReturn;
}