【嵌入式——FreeRTOS】任务通知
简介
任务通知:就是用来通知任务的,任务控制块中的结构体成员变量ulNotifiedValue就是这个通知值。
使用队列、信号量、事件标志组时都需另外创建一个结构体,通过中间的结构体进行间接通信。
使用任务通知时,任务结构体TCB中就包含了内部对象,可以直接接收别人发过来的通知
任务通知值的更新方式
- 不覆盖接受任务的通知值
- 覆盖接受任务的通知值
- 更新接受任务通知值的一个或多个bit
- 增加接受任务的通知值
任务通知优势
- 效率更高:使用任务通知向任务发送事件或数据比使用队列、事件标志组或信号量快的多。
- 使用内存更小:使用其他方法时都要先创建对应的结构体,使用任务通知时无需额外创建结构体
任务通知劣势
- 无法发送数据给ISR:ISR没有任务结构体,所以无法给ISR发送数据,但是ISR可以使用任务通知的功能发数据给任务
- 无法广播给多个任务:任务通知只能是被指定的一个任务接收并处理
- 无法缓存多个数据:任务通知时通过更新任务通知值来发送数据的,任务结构体中只有一个任务通知值,只能保持一个数据
- 发送受阻不支持阻塞:发送方无法进入阻塞状态等待
任务通知值和通知状态
任务都有一个结构体:任务控制块TCB,它里边包含两个结构体成员变量
typedef struct tskTaskControlBlock /* The old naming convention is used to prevent breaking kernel aware debuggers. */
{
......
#if ( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ]; //用来表示任务通知值
volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ]; //用来表示通知状态
#endif
}
#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1
任务通知值的类型
- 计数值(数值累加,类似信号量)
- 相应位置1(类似事件标志组)
- 任意数值(支持覆写和不覆写,类似队列)
typedef enum
{
eNoAction = 0, /* 无操作*/
eSetBits, /* 更新指定bit*/
eIncrement, /* 通知值加1*/
eSetValueWithOverwrite, /* 覆写的方式更新通知值*/
eSetValueWithoutOverwrite /* 不覆写通知值*/
} eNotifyAction;
任务通知状态
- 任务未等待通知:任务通知默认的初始化状态
- 任务在等待通知:接收方已经准备好了(调用了接收任务通知函数),等待发送方给个通知
- 任务在等待接收:发送方已经发送出去(调用了发送任务通知函数),等待接收方接收
#define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) /* Must be zero as it is the initialised value. */
#define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 )
#define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 )
相关API
发送通知API函数可以用于任务和中断服务函数中,接收通知API函数只能用在任务中。
发送通知相关API函数
函数 | 描述 |
---|---|
xTaskNotify() | 发送通知,带有通知值 |
xTaskNotifyAndQuery() | 发送通知,带有通知值并且保留接收任务的原通知值 |
xTaskNotifyGive() | 发送通知,不带通知值 |
xTaskNotifyFromISR() | 在中断中发送任务通知 |
xTaskNotifyAndQueryFromISR() | 在中断中发送任务通知 |
vTaskNotifyGiveFromISR() | 在中断中发送任务通知 |
//xTaskToNotify 接收任务通知的任务句柄
//tskDEFAULT_INDEX_TO_NOTIFY 任务的指定通知
//ulValue 任务通知值(任务通知相关数组成员)
//eAction 通知方式(通知值更新方式) eNotifyAction
#define xTaskNotify( xTaskToNotify, ulValue, eAction ) \
xTaskGenericNotify(
( xTaskToNotify ),
( tskDEFAULT_INDEX_TO_NOTIFY ),
( ulValue ),
( eAction ),
NULL )
//pulPreviousNotifyValue 用于保存更新前的任务通知值(为NULL则不保存)
#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue ) \
xTaskGenericNotify(
( xTaskToNotify ),
( tskDEFAULT_INDEX_TO_NOTIFY ),
( ulValue ),
( eAction ),
( pulPreviousNotifyValue ) )
#define xTaskNotifyGive( xTaskToNotify ) \
xTaskGenericNotify(
( xTaskToNotify ),
( tskDEFAULT_INDEX_TO_NOTIFY ),
( 0 ),
eIncrement,
NULL )
接收通知相关API
函数 | 描述 |
---|---|
ulTaskNotifyTake() | 获取任务通知,可以设置在退出此函数的时候将任务通知清零或者减1,当任务通知用作二值信号量或者计数信号量的时候,使用此函数来获取信号量。 |
xTaskNotifyWait() | 获取任务通知,比ulTaskNofityTake()更为复杂,可获取通知值和清除通知值的指定位 |
当任务通知用作于信号量时,使用函数获取信号量ulTaskNotifyTake。
当任务通知用作于事件标志组或队列时,使用此函数来获取xTaskNotifyWait。
//tskDEFAULT_INDEX_TO_NOTIFY 任务的指定通知(任务通知相关数组成员)
//xClearCountOnExit 指定在成功接收通知后,将通知值清零或减1 pdTRUE:清零 pdFALSE:把通知值减1
//xTicksToWait 阻塞等待任务通知值的最大时间
//返回值 0 接收失败 非0 接收成功,返回任务通知的通知值
#define ulTaskNotifyTake( xClearCountOnExit, xTicksToWait ) \
ulTaskGenericNotifyTake(
( tskDEFAULT_INDEX_TO_NOTIFY ),
( xClearCountOnExit ),
( xTicksToWait ) )
//tskDEFAULT_INDEX_TO_NOTIFY 任务的指定通知(任务通知相关数组成员)
//ulBitsToClearOnEntry 等待前清零指定任务通知值的bit位(旧值对应bit值清0)
//ulBitsToClearOnExit 成功等待后清零指定的任务通知值bit(新值对应bit清0)
//pulNotificationValue 用于取出通知值(如果不需要取出设为NULL)
//xTicksToWait 阻塞等待任务通知值的最大时间
//返回值 pdTRUE等待任务通知成功 pdFALSE等待任务通知失败
#define xTaskNotifyWait( ulBitsToClearOnEntry, ulBitsToClearOnExit, pulNotificationValue, xTicksToWait ) \
xTaskGenericNotifyWait(
tskDEFAULT_INDEX_TO_NOTIFY,
( ulBitsToClearOnEntry ),
( ulBitsToClearOnExit ),
( pulNotificationValue ),
( xTicksToWait ) )
任务通知模拟二值信号量代码示例
#include "queue.h"
#inculde "sempht.h"
TaskHandle_t task1_handler;
TaskHandle_t task2_handler;
void init(){
//创建两个任务 task1 task2
}
//发送任务通知值
void task1(){
uint8_t = key = 0;
while(1){
if(满足条件){
xTaskNotifyGive(task2_handler);
}
}
}
//接收任务通知值
void task2(){
uint32_t ret = 0;
while(1){
if(满足条件){
ret = ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
if(ret != 0){
printf("接收任务通知成功"\r\n);
}
}
}
}
任务通知模拟消息邮箱代码示例
#include "queue.h"
#inculde "sempht.h"
TaskHandle_t task1_handler;
TaskHandle_t task2_handler;
void init(){
//创建两个任务 task1 task2
}
//发送任务通知值
void task1(){
uint8_t = key = 0; //通知值
while(1){
key = key_scan(0);
if(key != 0){
xTaskNotify(task2_handler,key ,eSetValueWithOverwrite);
}
}
}
//接收任务通知值
void task2(){
uint32_t ret = 0;
uint32_t notify_val = 0; //通知值
while(1){
if(满足条件){
//0xFFFFFFFF bit位全部清零
ret = xTaskNotifyWait(0,0xFFFFFFFF,¬ify_val ,portMAX_DELAY);
switch(notify_val){
case KEY0_PRES:
printf("key0");
break;
case KEY1_PRES:
printf("key1");
break;
}
}
}
}
任务通知模拟事件标志组代码示例
#include "queue.h"
#inculde "sempht.h"
#define EVENTBIT_0 (1 << 0)
#define EVENTBIT_1 (1 << 1)
TaskHandle_t task1_handler;
TaskHandle_t task2_handler;
void init(){
//创建两个任务 task1 task2
}
//发送任务通知值
void task1(){
uint8_t = key = 0; //通知值
while(1){
key = key_scan(0);
if(key == KEY0_PRES){
//将bit0位置置1
xTaskNotify(task2_handler,EVENTBIT_0 ,eSetBits);
} else if(key == KEY1_PRES){
//将bit1位置置1
xTaskNotify(task2_handler,EVENTBIT_1 ,eSetBits);
}
}
}
//接收任务通知值
void task2(){
uint32_t event_bit = 0;
uint32_t notify_val = 0; //通知值
while(1){
//0xFFFFFFFF bit位全部清零
ret = xTaskNotifyWait(0,0xFFFFFFFF,¬ify_val ,portMAX_DELAY);
if(notify_val & EVENTBIT_0){
event_bit |= EVENTBIT_0;
}else if(notify_val & EVENTBIT_1){
event_bit |= EVENTBIT_1;
}
if(event_bit == (EVENTBIT_0|EVENTBIT_1)){
printf("任务通知模拟事件标志组接收成功\r\n");
event_bit = 0;
}
}
}
标签:task2,FreeRTOS,通知,嵌入式,发送,任务,bit,接收
From: https://blog.csdn.net/weixin_39723539/article/details/140198461