一、概念
(1)FreeRTOS从V8.2.0版本开始提供任务通知
(2)每个任务都有一个32位的通知值
(3)发送任务通知的几种情况
3.1 发送通知给任务,如果有通知未读,不覆盖通知值
3.2 发送通知给任务,直接覆盖通知值
3.3 发送通知给任务,设置通知值的一个或多个位,可以当做事件组来使用
3.4 发送通知给任务,递增通知值,可以当做计数信号量来使用
(4)只能有一个任务接收通知消息
(5)只有等待通知的任务可以被阻塞
(6)无需创建,属于任务控制块中的变量,创建任务时即创建完成
(7)中断/任务均能发送通知
(8)只有任务可以等待通知,而不允许中断中等待通知
(9)相较于传统方式性能快
(10)使用时需要使能configUSE_TASK_NOTIFICATIONS宏定义
二、使用函数
(1)xTaskNotifyGive发送通知,没有通知值(信号量类型)
(2)xTaskNotify发送通知,带通知值
(3)xTaskNotifyAndQuery发送通知,带通知值,并返回原通知值
(4)ulTaskNotifyTake等待通知(信号量类型)
(5)xTaskNotifyWait等待通知
(6)vTaskNotifyGiveFromISR中断版本的xTaskNotifyGive
(7)xTaskNotifyAndQueryFromISR中断版本的xTaskNotifyAndQuery
(8)xTaskNotifyFromISR中断版本的ulTaskNotifyTake
(9)xTaskNotifyStateClear清除所有未读消息
三、代码示例
(1)任务通知代替消息队列
#include "FreeRTOS.h"
#include "task.h"
#include "led.h"
#include "limits.h"static void task1(void* param);
static void task2(void* param);static TaskHandle_t task1Handler;
static TaskHandle_t task2Handler;int main()
{led_init();portENTER_CRITICAL(); //进入临界区BaseType_t xReturn;/******创建任务1*******/xReturn = xTaskCreate(task1,"task1",128,NULL,2,&task1Handler);if(xReturn==pdTRUE){}/******创建任务2*******/xReturn = xTaskCreate(task2,"task2",128,NULL,2,&task2Handler);if(xReturn==pdTRUE){}portEXIT_CRITICAL(); //退出临界区vTaskStartScheduler(); //开启任务调度器while(1){ }
}//发送消息
void task1(void* param)
{BaseType_t xReturn = pdPASS;uint32_t value1 = 1;uint32_t value2 = 2;while(1){xReturn = xTaskNotify(task2Handler, //向哪个任务发送通知value1, //发送的值eSetValueWithOverwrite); //写入值方式if(xReturn==pdTRUE){vTaskDelay(1000);}xReturn = xTaskNotify(task2Handler, //向哪个任务发送通知value2, //发送的值eSetValueWithOverwrite); //写入值方式if(xReturn==pdTRUE){vTaskDelay(1000);}}
}//接收消息
void task2(void* param)
{BaseType_t xReturn;uint32_t recv;while(1){xReturn = xTaskNotifyWait(0x0, //进入时要清除的位ULONG_MAX, //退出时要清除的位,清除所有位&recv, //接收的值portMAX_DELAY); //等待超时时间if(recv == 1 && xReturn==pdTRUE){open();}else if(recv == 2 && xReturn==pdTRUE){close();}}
}
(2)任务通知替换二值信号量
#include "FreeRTOS.h"
#include "task.h"
#include "led.h"
#include "limits.h"static void task1(void* param);
static void task2(void* param);static TaskHandle_t task1Handler;
static TaskHandle_t task2Handler;int main()
{led_init();portENTER_CRITICAL(); //进入临界区BaseType_t xReturn;/******创建任务1*******/xReturn = xTaskCreate(task1,"task1",128,NULL,2,&task1Handler);if(xReturn==pdTRUE){}/******创建任务2*******/xReturn = xTaskCreate(task2,"task2",128,NULL,2,&task2Handler);if(xReturn==pdTRUE){}portEXIT_CRITICAL(); //退出临界区vTaskStartScheduler(); //开启任务调度器while(1){ }
}//发送消息
void task1(void* param)
{while(1){xTaskNotifyGive(task2Handler);vTaskDelay(500);}
}//接收消息
void task2(void* param)
{static int ledcnt=0;while(1){ulTaskNotifyTake(pdTRUE,portMAX_DELAY);ledcnt=!ledcnt;if(ledcnt==1){open();}else if(ledcnt==0){close();}}
}
(3)任务通知代替计数信号量
#include "FreeRTOS.h"
#include "task.h"
#include "led.h"
#include "limits.h"static void task1(void* param);
static void task2(void* param);static TaskHandle_t task1Handler;
static TaskHandle_t task2Handler;int main()
{led_init();portENTER_CRITICAL(); //进入临界区BaseType_t xReturn;/******创建任务1*******/xReturn = xTaskCreate(task1,"task1",128,NULL,2,&task1Handler);if(xReturn==pdTRUE){}/******创建任务2*******/xReturn = xTaskCreate(task2,"task2",128,NULL,2,&task2Handler);if(xReturn==pdTRUE){}portEXIT_CRITICAL(); //退出临界区vTaskStartScheduler(); //开启任务调度器while(1){ }
}//发送消息
void task1(void* param)
{while(1){xTaskNotifyGive(task2Handler);vTaskDelay(500);}
}//接收消息
void task2(void* param)
{static int ledcnt=0;uint32_t retu=0;while(1){retu = ulTaskNotifyTake(pdFALSE,0);if(retu==1) ledcnt=!ledcnt;if(ledcnt==1){open();}else if(ledcnt==0){close();}}
}
(4)任务通知替代事件组
#include "FreeRTOS.h"
#include "task.h"
#include "led.h"
#include "limits.h"static void task1(void* param);
static void task2(void* param);static TaskHandle_t task1Handler;
static TaskHandle_t task2Handler;#define EVENT1 (0x01<<1)
#define EVENT2 (0x01<<2)int main()
{led_init();portENTER_CRITICAL(); //进入临界区BaseType_t xReturn;/******创建任务1*******/xReturn = xTaskCreate(task1,"task1",128,NULL,2,&task1Handler);if(xReturn==pdTRUE){}/******创建任务2*******/xReturn = xTaskCreate(task2,"task2",128,NULL,2,&task2Handler);if(xReturn==pdTRUE){}portEXIT_CRITICAL(); //退出临界区vTaskStartScheduler(); //开启任务调度器while(1){ }
}//发送消息
void task1(void* param)
{while(1){xTaskNotify(task2Handler,EVENT1,eSetBits);//设置任务通知对应位vTaskDelay(500);xTaskNotify(task2Handler,EVENT2,eSetBits);//设置任务通知对应位vTaskDelay(1000);}
}//接收消息
void task2(void* param)
{ uint32_t recv;while(1){xTaskNotifyWait(0x0,ULONG_MAX,&recv,portMAX_DELAY);if(recv == EVENT1){//事件或open();}else if(recv == EVENT2){close();}}
}