前言
任务通知和信号量、队列、事件等用法相同,在任务之间进行数据传输或者事件传输对比队列和信号量等效率更高,因为任务通知的变量是跟随任务创建时创建的无需像队列事件一样创建结构体可以更节省内存;
发送任务通知
发送通知,带有通知值并且不保留接收任务原通知值;
BaseType_t xTaskNotify(TaskHandle_t xTaskToNotify, uint32_t ulValue eNotifyAction eAction)
TaskHandle_t xTaskToNotify:指定发送的任务句柄
uint32_t ulValue:任务通知值
eNotifyAction eAction:任务通知更新类型
typedef enum { eNoAction=0, eSetBits, //更新指定的bit eIncrement, //通知值加一 eSetValueWithOverwrite, //覆写的方式更新通知值 eSetValueWithoutOverwrite //不覆写通知值 }eNotifyAction;
发送通知,不带通知值并且不保留接收任务的通知值,此函数会将接收任务的通知值加一;
BaseType_txTaskNotifyGive(TaskHandle_t xTaskToNotify);
发送通知,带有通知值并且保留接收任务的原通知值;
BaseType_txTaskNotifyAndQuery(TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t*pulPreviousNotificationValue);
TaskHandle_t xTaskToNotify:指定发送的任务句柄
uint32_t ulValue:任务通知值
eNotifyAction eAction:任务通知更新类型
uint32_t*pulPreviousNotificationValue:用来保存更新前的通知值
上述的三个函数都是在任务之间使用的,他们的中断版本分别是xTaskNotifyFromISR()、vTaskNotifyGiveFromISR()、XTaskNotiryAndQueryFromISR() ;
获取任务通知
获取任务通知,可以设置在退出此函数的时候将任务通知值清零或者减一。当任务通知用作二值信号量或者计数信号量的时候使用此函数来获取信号量。
uint32_tulTaskNotifyTake(BaseType_t xClearCountOnExit, TickType_t xTicksToWait);
BaseType_t xClearCountOnExit:参数为pdFALSE的话在退出函数ulTaskNotifyTake()的时候任务通知值减一,类似计数型信号量。当此参数为pdTRUE的话在退出函数的时候任务任务通知值清零,类似二值信号量。
TickType_t xTicksToWait:可设置为portMAX_DELAY:一定等到成功才返回,可以设置为期望的Tick Count,一般用pdMS_TO_TICKS()把ms转换为Tick Count
返回值:任务通知值减少或者清零之前的值
此函数也是用来获取任务通知的,不过此函数比ulTaskNotifyTake()更为强大,不管任务通知用作二值信号量、计数型信号量、队列和事件标志组中的哪一种,都可以使用此函数来获取任务通知。但是当任务通知用作二值信号量和计数型信号量的时候推荐使用函数ulTaskNotifyTake()。此函数原型如下:
BaseType_txTaskNotifyWait(uint32_tulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t*pulNotificationValue, TickType_t xTicksToWait); • 1
uint32_tulBitsToClearOnEntry:当没有接收到任务通知的时候将任务通知值与此参数的取反值进行按位与运算,当此参数为0xffffffff或者ULONG_MAX的时候就会将任务通知值清零。
uint32_t ulBitsToClearOnExit:如果接收到了任务通知,在做完相应的处理退出函数之前将任务通知值与此参数的取反值进行按位与运算,当此参数为0xffffffff或者ULONG_MAX的时候就会将任务通知值清零。
uint32_t*pulNotificationValue:此参数用来保存任务通知值。
返回值:pdTRUE:获取到了任务通知。pdFALSE:任务通知获取失败。
示例
FreeRTOSConfig文件中对应配置宏configUSE_TASK_NOTIFICATIONS
static TaskHandle_t send_task_handle = NULL; static TaskHandle_t revc_task_handle = NULL; #define NOTIFICATIONS1 0 /* 模拟二进制信号量 */ #define NOTIFICATIONS2 0 /* 模拟计数信号量 */ #define NOTIFICATIONS3 0 /* 模拟邮箱 */ #define NOTIFICATIONS4 1 /* 模拟事件组 */ #define NOTIFICATION_EVENT1 (1 << 0) /* 事件1 */ #define NOTIFICATION_EVENT2 (1 << 1) /* 事件2 */ #define NOTIFICATION_EVENT3 (1 << 2) /* 事件3 */ static void send_task(void *par) { uint8_t count = 0; while(1) { #if(NOTIFICATIONS1 == 1) xTaskNotifyGive(revc_task_handle); vTaskDelay(200); /* 延时200个tick */ #elif(NOTIFICATIONS2 == 1) if(count++ <= 100) { xTaskNotifyGive(revc_task_handle); } vTaskDelay(200); /* 延时200个tick */ #elif(NOTIFICATIONS3 == 1) xTaskNotify(revc_task_handle,count++,eSetValueWithOverwrite); vTaskDelay(200); /* 延时200个tick */ #elif(NOTIFICATIONS4 == 1) if(count++ == 5) { // 因为是模拟事件标志组的,所以这里发送的值就是将任务通知值的 bit 置 1。 xTaskNotify((TaskHandle_t )revc_task_handle,NOTIFICATION_EVENT1,eSetBits); } if(count == 10) { xTaskNotify((TaskHandle_t )revc_task_handle,NOTIFICATION_EVENT2,eSetBits); } if(count == 20) { xTaskNotify((TaskHandle_t )revc_task_handle,NOTIFICATION_EVENT3,eSetBits); } vTaskDelay(100); #endif } } static void revc_task(void *par) { uint32_t notify_count = 0; while(1) { #if(NOTIFICATIONS1 == 1) //其中,为pdTRUE的话就是每获取take一次notify,value值复位到0相当于二值信号量 notify_count = ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // 第一次打印是第一次通知,当时值为一, 然后进入阻塞态1000tick那send任务发送五个通知所以下次打印清零前的通知5 printf("receive notify! notify_count:%d \r\n",notify_count); vTaskDelay(1000); // 等待发送一些通知 #elif(NOTIFICATIONS2 == 1) //其中,为pdTRUE的话就是每获取take一次notify,value值-1相当于计数信号量 notify_count = ulTaskNotifyTake(pdFALSE, portMAX_DELAY); // 打印的是当前剩余的通知数量 printf("receive notify! notify_count:%d \r\n",notify_count-1); // 如果任务二阻塞时间比任务一短则当前值永远为0,如果执行比任务一慢则任务值递增 // 这里任务2运行一次通知-1,任务一运行两次通知+2,所以notify_count每次+1 vTaskDelay(400); #elif(NOTIFICATIONS3 == 1) xTaskNotifyWait(0, // 进入函数前不清空 0xffffffff, // 退出函数后清空所有位 ¬ify_count, // 得到notify portMAX_DELAY); // 永远等待 printf("receive notify! notify_count:%d \r\n",notify_count); #elif(NOTIFICATIONS4 == 1) xTaskNotifyWait(0, // 进入函数前不清空 0xffffffff, // 退出函数后清空所有位 ¬ify_count, // 得到notify portMAX_DELAY); // 永远等待 if((notify_count & NOTIFICATION_EVENT1) != 0) { printf("事件1执行!\r\n"); } else if((notify_count & NOTIFICATION_EVENT2) != 0) { printf("事件2执行!\r\n"); } else if((notify_count & NOTIFICATION_EVENT3) != 0) { printf("事件3执行!\r\n"); } #endif } }
模拟事件
模拟邮箱发送值
模拟计数型信号量
模拟二进制信号量
结尾
我是凉开水白菜,我们下文见~