1.任务通知的简介
任务通知:用来通知任务的,任务控制块中的结构体成员变量 ulNotifiedValue就是这个通知值。
- 使用队列、信号量、事件标志组时都需另外创建一个结构体,通过中间的结构体进行间接通信!
- 使用任务通知时,任务结构体TCB中就包含了内部对象,可以直接接收别人发过来的"通知"
任务通知值的更新方式
- 不覆盖接受任务的通知值【类似队列不覆写】
- 覆盖接受任务的通知值【类似队列覆写】
- 更新接受任务通知值的一个或多个bit【类似任务标志组】
- 增加接受任务的通知值【类似信号量】
- 只要合理,灵活的利用任务通知的特点,可以在一些场合中替代队列、信号量、事件标志组!
任务通知的优势及劣势
- 效率更高(快):使用任务通知向任务发送事件或数据比使用队列、事件标志组或信号量快得多
- 使用内存更小:使用其他方法时都要先创建对应的结构体,使用任务通知时无需额外创建结构体
- 无法发送数据给ISR:ISR没有任务结构体,所以无法给ISR发送数据。但是ISR可以使用任务通知的功能,发数据给任务
- 无法广播给多个任务:任务通知只能是被指定的一个任务接收并处理
- 无法缓存多个数据:任务通知是通过更新任务通知值来发送数据的,任务结构体中只有一个任务通知值,只能保持一个数据
- 发送受阻不支持阻塞:发送方无法进入阻塞状态等待
任务通知有速度快、内存小的优势,但是中断不能收数据,只能一对一,只有一个数据量,发送不支持阻塞。多用于一对一通知
2.任务通知值和通知状态
任务都有一个结构体:任务控制块TCB,它里边有两个结构体成员变量:
typedef struct tskTaskControlBlock
{
//… …
#if ( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue [ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
volatile uint8_t ucNotifyState [ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
endif
//… …
} tskTCB;
#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1 /* 定义任务通知数组的大小, 默认: 1 */
ulNotifiedValue是 uint32_t 类型,用来表示通知值
ucNotifyState是 uint8_t 类型,用来表示通知状态
任务通知值的更新方式有多种类型
- 计数值(数值累加,类似信号量)
- 相应位置一(类似事件标志组)
- 任意数值(支持覆写和不覆写,类似队列)
任务通知状态共有3种取值:
#define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) /* 任务未等待通知 */
#define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 ) /* 任务在等待通知 */
#define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 ) /* 任务在等待接收 */
- 任务未等待通知 :任务通知默认的初始化状态
- 等待通知:接收方已经准备好了(调用了接收任务通知函数),等待发送方给个通知
- 等待接收:发送方已经发送出去(调用了发送任务通知函数),等待接收方接收
3.任务通知相关API函数介绍
任务通知API函数主要有两类:①发送通知 ,②接收通知。
【注意】发送通知API函数可以用于任务和中断服务函数中;接收通知API函数只能用在任务中。
- xTaskNotify():发送任务通知,带有通知值
- xTaskNotifyAndQuery():发送任务通知,带有通知值,保留接收任务原通知值
- xTaskNotifyGive():发送任务通知,不带通知值
- xTaskNotifyFromISR():在中断中发送任务通知
- xTaskNotifyAndQueryFromISR():在中断中发送任务通知
- vTaskNotifyGiveFromISR():在中断中发送任务通知
- ulTaskNotifyTake():获取任务通知,可以设置在退出此函数的时候将任务通知值清零或者减一。
- xTaskNotifyWait():获取任务通知,比 ulTaskNotifyTak()更为复杂,可获取通知值和清除通知值的指定位。
xTaskNotifyAndQuery()和xTaskNotify()常用于模拟写队列/设置标志位,ulTaskNotifyTake()常用于读队列/清除标志位
xTaskNotifyGive()常用于模拟信号量释放,ulTaskNotifyTake()常用于模拟信号量获取
下方的函数和上述的函数基本一致,只不过可以操作下表不为0的元素操作(不常用)
3.1.发送任务通知
#define xTaskNotifyAndQuery(xTaskToNotify, ulValue , eAction , pulPreviousNotifyValue )
xTaskGenericNotify((xTaskToNotify), (tskDEFAULT_INDEX_TO_NOTIFY), (ulValue), (eAction), (pulPreviousNotifyValue ))
#define xTaskNotify(xTaskToNotify , ulValue , eAction )
xTaskGenericNotify((xTaskToNotify), (tskDEFAULT_INDEX_TO_NOTIFY), (ulValue), (eAction), NULL)
#define xTaskNotifyGive( xTaskToNotify )
xTaskGenericNotify((xTaskToNotify), (tskDEFAULT_INDEX_TO_NOTIFY), (0), eIncrement, NULL)
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify,
UBaseType_t uxIndexToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t * pulPreviousNotificationValue )
typedef enum
{
eNoAction = 0, /* 无操作 */
eSetBits /* 更新指定bit */
eIncrement /* 通知值加一 */
eSetValueWithOverwrite /* 覆写的方式更新通知值 */
eSetValueWithoutOverwrite /* 不覆写通知值 */
} eNotifyAction;
- 形参xTaskIaNatify:接收任务通知的任务句柄
- 形参uxIndexToNotify:任务的指定通知(任务通知相关数组成员,第0个元素)
- 形参ulValue:任务通知值
- 形参eAction:通知方式(通知值更新方式)
- 形参pulPreviousNotificationValue:用于保存更新前的任务通知值(为NULL则不保存)
3.2.发送任务通知底层函数xTaskGenericNotify( )解析
3.3.获取任务通知
#define ulTaskNotifyTake( xClearCountOnExit , xTicksToWait )
ulTaskGenericNotifyTake ( ( tskDEFAULT_INDEX_TO_NOTIFY ),//任务的指定通知
( xClearCountOnExit ),
( xTicksToWait ) )
- 形参uxlndexToWaitQn:任务的指定通知(任务通知相关数组成员)
- 形参xClearCountOnExit:指定在成功接收通知后,将通知值清零或减1,pdTRUE:把通知值清零;pdEAL.SE:把通知值减一
- 形参xTicksToWait:阻塞等待任务通知值的最大时间
- 返回值:0,接收失败;非0,接收成功,返回任务通知的通知值
#define xTaskNotifyWait( ulBitsToClearOnEntry,
ulBitsToClearOnExit,
pulNotificationValue,
xTicksToWait)
xTaskGenericNotifyWait( tskDEFAULT_INDEX_TO_NOTIFY,
( ulBitsToClearOnEntry ),
( ulBitsToClearOnExit ),
( pulNotificationValue ),
( xTicksToWait ))
BaseType_t xTaskGenericNotifyWait( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait);
- 形参uxlndexToWaitOn:任务的指定通知(任务通知相关数组成员)
- 形参ulBitesToClearOnEntry:等待前清零指定任务通知值的比特位(旧值对应bit清0)
- 形参ulBitesToClearOnExit:成功等待后清零指定的任务通知值比特位(新值对应bit清0)
- 形参pulNotificationValue:用来取出通知值(如果不需要取出,可设为NULL)
- 形参xTicksToWait:阻塞等待任务通知值的最大时间
- 返回值:pdTRUE,等待任务通知成功;pdFALSE,等待任务通知失败
3.4.ulTaskNotifyTake( )与xTaskNotifyWait( )函数解析
- ulTaskNotifyTake( )
- ulTaskNotifyTake( )
4.任务通知模拟信号量实验
- 实验目的:学习使用 FreeRTOS 中的任务通知功能模拟二值信号量和计数型信号量
- 实验设计:将设计三个任务:start_task、task1、task2
start_task用来创建task1和task2任务
task1用于按键扫描,当检测到按键KEY0被按下时,将发送任务通知
task2用于接收任务通知,并打印相关提示信息
5.任务通知模拟消息邮箱实验
- 实验目的:学习使用 FreeRTOS 中的任务通知功能模拟消息邮箱
- 实验设计:将设计三个任务:start_task、task1、task2
start_task用来创建task1和task2任务
task1用于按键扫描,将按下的按键键值通过任务通知发送给指定任务
task2用于接收任务通知,并根据接收到的数据做相应动作
6.任务通知模拟事件标志组实验
- 实验目的:学习使用 FreeRTOS 中的任务通知功能模拟事件标志组
- 实验设计:将设计三个任务:start_task、task1、task2
start_task用来创建task1和task2任务
task1用于按键扫描,当检测到按键按下时,发送任务通知设置不同标志位
task2用于接收任务通知,并打印相关提示信息