任务通知
任务通知是一种任务间通信的手段,比使用信号量更节省资源,解除阻塞时间更快
- 无需创建队列
- 更节省RAM空间
- 发送通知任务几种模式:通知未读,不覆盖通知值;直接覆盖通知值;设置通知位的一个或多位,当作事件组;递增通知值,当做计数信号量。
- 由于必须指定接收通知的任务,只能有一个任务接收通知。
- 只有等待通知的任务可以被阻塞,发送通知的任务不会因为发送失败进入阻塞态。
任务通知运行机制
1 2
| #define configUSE_TASK_NOTIFICATIONS 1
|
- 随任务创建而初始化
- 任务通知和队列消息的运行机制一致
任务通知常见函数
xTaskGenericNotify()
发送任务通知,是任务通知的原型
xTaskNotifyGive()
调用任务通知,并将任务通知值加1,可以作为二值信号量和计数信号量的低配版,更加轻量化,原型xTaskNotify()
xTaskNotifyGiveFromISR()
中断调用任务通知
xTaskNotify()
用于任务直接向另一个任务发送一个事件
xTaskNotifyFromISR()
中断中使用,原型为xTaskGenericNotifyFromISR()
xTaskGenericNotifyFromISR()
通用中断发送任务通知
xTaskNotifyAndQuery()
和xTaskNotify()
功能类似,附加了回传接收任务的通知值,若不需要回传则等同于xTaskNotify()
xTaskNotifyAndQueryFromISR()
中断用
ulTaskNotifyTake()
可作为轻量级获取二值信号量和计数信号量的实现,用于自身句柄的调用
xTaskNotifyWait()
可以用于实现全功能的等待任务通知,更轻量化
代替消息队列
设计3个任务,2个任务接收消息通知来控制LED
,1个任务通过2个按钮来发送消息通知
接收、发送通知句柄,创建一个引用,并不是创建一个真实的消息通知
1 2 3 4 5 6
| static TaskHandle_t Receive1_Task_Handle = NULL; static TaskHandle_t Receive2_Task_Handle = NULL; static TaskHandle_t Send_Task_Handle = NULL;
#define USE_CHAR 0
|
创建一个真实的句柄
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| xReturn =xTaskCreate(Receive1_Task,"Receive1_Task",512,NULL,2,(TaskHandle_t *)&Receive1_Task_Handle); if (xReturn==pdPASS) { printf("创建Receive1_Task任务成功\r\n"); }
xReturn = xTaskCreate(Receive2_Task,"Receive2_Task",512,NULL,3,(TaskHandle_t *)&Receive2_Task_Handle); if (xReturn==pdPASS) { printf("创建Receive2_Task任务成功\r\n"); }
xReturn = xTaskCreate(Send_Task,"Send_Task",512,NULL,4,(TaskHandle_t *)&Send_Task_Handle); if (xReturn==pdPASS) { printf("创建Send_Task任务成功\r\n"); }
|
接收通知任务1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| static void Receive1_Task(void *paramter) { BaseType_t xReturn = pdTRUE; #if USE_CHAR char *r_char; #else uint32_t r_num; #endif while (1) { xReturn = xTaskNotifyWait(0x0, ULONG_MAX, #if USE_CHAR (uint32_t *)&r_char, #else &r_num, #endif portMAX_DELAY); if(xReturn==pdTRUE) #if USE_CHAR printf("Receive1_Task 任务通知%s \r\n",r_char); #else printf("Receive1_Task 任务通知%d \r\n",r_num); #endif LED0_Turn(); } }
|
接收通知任务2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| static void Receive2_Task(void *paramter) { BaseType_t xReturn = pdTRUE; #if USE_CHAR char *r_char; #else uint32_t r_num; #endif while (1) { xReturn = xTaskNotifyWait(0x0, ULONG_MAX, #if USE_CHAR (uint32_t *)&r_char, #else &r_num, #endif portMAX_DELAY);
if(xReturn == pdTRUE) { #if USE_CHAR printf("Receive2_Task 任务通知%s \r\n",r_char); #else printf("Receive2_Task 任务通知%d \r\n",r_num); #endif LED7_Turn(); } } }
|
发送通知任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| static void Send_Task(void *paramter) { BaseType_t xReturn=pdTRUE; #if USE_CHAR char test_str1[]="this is mail test 1"; char test_str1[]="this is mail test 2"; #else uint32_t send1=1; uint32_t send2=2; #endif while (1) { if (Key_BTN(BTN1)==KEY_ON) { xReturn = xTaskNotify(Receive1_Task_Handle, #if USE_CHAR (uint32_t)&test_str1, #else send1, #endif eSetValueWithOverwrite);
if(xReturn==pdTRUE) { printf("Receive1_Task_Handle 任务通知释放成功\r\n"); } }
if (Key_BTN(BTN2)==KEY_ON) { xReturn = xTaskNotify(Receive2_Task_Handle, #if USE_CHAR (uint32_t)&test_str2, #else send2, #endif eSetValueWithOverwrite); if (xReturn==pdTRUE) { printf("Receive2_Task_Handle 任务通知释放成功\r\n"); } } vTaskDelay(20); } }
|
按下BTN1
后,通信接收任务1,LED0
亮,按下BTN2
后,通信接收任务2,LED7
亮
代替二值信号量
设计3个任务,2个任务接收消息通知来控制LED
,1个任务通过2个按钮来发送消息通知,按钮控制释放信号量句柄,注意ulTaskNotifyTake
的使用,在自身句柄对应的Task
中调用
前置和代替消息队列相同
接收通知任务1
1 2 3 4 5 6 7 8 9 10
| static void Receive1_Task(void *paramter) { while (1) { ulTaskNotifyTake(pdTRUE,portMAX_DELAY); printf("Receive1_Task 任务通知获取成功\r\n"); LED0_Turn(); } }
|
接收通知任务2
1 2 3 4 5 6 7 8 9
| static void Receive2_Task(void *paramter) { while (1) { ulTaskNotifyTake(pdTRUE,portMAX_DELAY); printf("Receive2_Task 任务通知获取成功\r\n"); LED7_Turn(); } }
|
发送通知任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| static void Send_Task(void *paramter) { BaseType_t xReturn=pdPASS; while (1) { if (Key_BTN(BTN1)==KEY_ON) { xReturn = xTaskNotifyGive(Receive1_Task_Handle); if (xReturn==pdTRUE) { printf("Receive1_Task 任务释放成功\r\n"); } } if (Key_BTN(BTN2)==KEY_ON) { xReturn = xTaskNotifyGive(Receive2_Task_Handle); if (xReturn == pdTRUE) { printf("Receive2_Task 任务释放成功\r\n"); } } vTaskDelay(20); }
}
|
按下BTN1
后,通信接收任务1,LED0
亮,按下BTN2
后,通信接收任务2,LED7
亮
代替计数信号量
创建2个任务,1个用于等待通知,申请车位。另一个用于释放信号量,释放车位。
接收、发送通知句柄,创建一个引用,并不是创建一个真实的消息通知
1 2 3
| static TaskHandle_t Take_Task_Handle=NULL; static TaskHandle_t Give_Task_Handle=NULL;
|
申请车位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| static void Take_Task(void *paramter) { uint32_t take_num=pdPASS; while (1) { if(Key_BTN(BTN1)==KEY_ON) { take_num=ulTaskNotifyTake(pdFALSE,0); if (take_num>0) { printf("成功申请到车位,当前车位%d\r\n",take_num-1); }else { printf("KEY1按下,无多余车位。请按下KEY2释放车位\r\n"); } } } }
|
释放车位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| static void Give_Task(void *paramter) { BaseType_t xReturn = pdPASS; while (1) { if (Key_BTN(BTN2)==KEY_ON) { xReturn = xTaskNotifyGive(Take_Task_Handle); if (xReturn==pdPASS) { printf("KEY2按下,释放一个车位\r\n"); } } vTaskDelay(20);
} }
|
按下KEY1
,无车位;按下KEY2
2次释放2个车位,再按下KEY1
申请2个车位
代替事件组
创建2个任务,一个任务用于监听事件,一个任务用于控制BTN1
和BTN2
来触发事件
事件组句柄,创建一个引用,并不是创建一个真实的事件组
1 2 3 4 5 6 7 8
| static TaskHandle_t LED7_Task_Handle=NULL; static TaskHandle_t KEY_Task_Handle=NULL;
static EventGroupHandle_t Event_Handle=NULL;
#define KEY1_EVENT (0x01 << 0)
|
创建一个真实的事件组
1 2 3 4 5
| Event_Handle = xEventGroupCreate(); if (Event_Handle!=NULL) { printf("事件组句柄创建成功\r\n"); }
|
LED灯任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| static void LED7_Task(void *paramter) { uint32_t r_event=0; uint32_t last_event=0; BaseType_t xReturn=pdPASS; while(1) { xReturn = xTaskNotifyWait(0x0, ULONG_MAX, &r_event, portMAX_DELAY); if (xReturn == pdPASS) { last_event |= r_event; if (last_event == (KEY1_EVENT|KEY2_EVENT)) { last_event=0; printf("KEY1和KEY2都按下\r\n"); LED7_Turn(); }else { last_event=r_event; } } } }
|
KEY任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| static void KEY_Task(void *paramter) { while(1) { if( Key_BTN(BTN1) == 0 ) { printf("K1 被按下\r\n"); xTaskNotify(LED7_Task_Handle, KEY1_EVENT, eSetBits); } if( Key_BTN(BTN2) == 0 ) { printf("K2 被按下\r\n"); xTaskNotify(LED7_Task_Handle, KEY2_EVENT, eSetBits); } vTaskDelay(20); } }
|
按下BTN1
,设置事件1,按下BTN2
,设置事件2,触发LED
事件