文章目录
1、基本概念(核心是关中断)
任务通知,即通知任务,可以实现任务间的数据传输,同时也和前面的内核对象一眼具备休眠唤醒功能。
2、使用场景:一个任务唤醒另一个任务(即任务间的数据传输)
这时候的数据传输有限,即一次只能传输一个数据
3、休眠唤醒功能与前面说到的内核对象的区别
任务通知与前面队列、信号量、互斥量和事件组相比,其休眠与唤醒功能不需要使用像前面使用的链表来记录,任务通知可以明确指定通知哪个任务。
而且这个休眠唤醒功能只有等待通知的任务才具备的。
即在这里没有链表来记录等待读或写的任务了,在提供的API函数中可以直接指定通知(唤醒)哪个任务。
为什么不需要这个链表来维持呢?
主要是因为任务结构体TCB中包含了内部对象,即任务的结构体里面有用于存储通知状态的变量和通知值的变量。
typedef struct tskTaskControlBlock
{
......
/* configTASK_NOTIFICATION_ARRAY_ENTRIES = 1 */
volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];//用于表示通知的值
volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];//用于显示通知的状态
......
} tskTCB;
即在队列、信号量、互斥量和事件组时,我们需要事先创建对应的结构体(队列等),双方通过这个创建的中间体来进行通信,即如下所示:
而这个任务通知是直接进行通信的:
4、优势及限制
优势:
1)效率更高:直接通信,不需要中间体来进行中继通信。
2)更节省内存:创建任务时自带内存,无须开辟新的内存来进行存储。
限制:
1)只能任务间进行通信,任务和中断间不可通信。即不能给中断发送数据。
2)数据只能该指定的任务独享:任务通知明确了通信的对象,通知的数据只能被目标对象一个使用。
3)可以传输的数据量小:即一次只能传输一个数据,不像队列等可以缓存多个数据。
4)无法进行广播:因为是直接通信,一次只能通知一个任务,不像事件组可以给多个任务同时发送事件。
5)发送方无法进行阻塞状态:即像前面说到的休眠唤醒功能只有等待通知方才具备,发送方进行任务通知的时候当对方呜啊接收数据的时候,只能立刻返回错误,不能阻塞等待。
5、通知的三种状态
前面说到的任务结构体里面的存储通知状态的变量只有三个值,即三种状态:
1)taskNOT_WAITING_NOTIFICATION:任务没有在等待通知
2)taskWAITING_NOTIFICATION:任务在等待通知
3)taskNOTIFICATION_RECEIVED:任务接收到了通知,也被称为 pending(有数据了,待处理)
##define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) /* 也是初始状态*/
##define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 )
##define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 )
6、任务通知的两套函数(最好还是使用专业板的)
(1)API内部原理(发出和通知函数内部原理)
注意只有等待通知的任务才具备休眠唤醒功能。
(2)专业版
1)发出通知——xTaskNotify
需要发送的通知需要预先使用一个变量存放好,即调用这个函数的时候需要把存放了要发通知的变量作为实参。
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
2)取出通知——xTaskNotifyWait
取出的通知放到预先定义好的变量内,即调用这个函数需要预先定义好存放通知的变量并在函数调用的时候把这个变量的地址作为实参。
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t *pulNotificationValue,
TickType_t xTicksToWait );
(3)简化版
1)发出通知——xTaskNotifyGive
调用这个函数的时候需要把发送的通知预先放入唤醒缓冲区。
例如:
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
2)取出通知——ulTaskNotifyTake
返回值就是去取出的通知。即通知值
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
7、等待通知的任务休眠唤醒功能的原理
例如下面图中的两个例子:
1)左边发送方先发了数据,接收方是在已经接收到数据的前提下直接取出了数据。
2)右边是接收方在等待数据(即此时发送方还没开始发送),直到发送方进行任务通知后接收方就被唤醒然后取出通知。
记住成功取出数据后会将通知状态值复位。