13. FreeRTOS任务通知
1. 任务通知的简介
-
简介:
FreeRTOS内核
V8.2.0
版本新增了任务通知功能,任务通知也是用于任务间进行同步和通讯的一种机制,但是相对于前面的信号量、队列、事件标志组等而言,任务通知在内存占用和效率方面都有很大的优势。在FreeRTOS中,每一个任务都有两个用于任务通知功能的数组,分别为任务通知数组和任务通知状态数组。其中任务通知数组中的每一个元素都是一个32位无符号类型的通知值;而任务通知状态数组中的元素则表示与之对应的任务通知的状态。
任务通知数组中的32位无符号通知值,用于任务到任务或中断到任务发送通知的“媒介”。当通知值为0时,表示没有任务通知;当通知值不为0时,表示有任务通知,并且通知值就是通知的内容。
任务通知状态数组中的元素,用于标记任务通知数组中通知的状态,任务通知有三种状态,分别为未等待通知状态、等待通知状态和等待接收通知状态。其中未等待通知状态为任务通知的复位状态;当任务在没有通知的时候接收通知时,在任务阻塞等待任务通知的这段时间内,任务所等待的任务通知就处于等待通知状态;当有其他任务向任务发送通知,但任务还未接收这一通知的这段期间内,任务通知就处于等待接收通知状态。
-
任务通知的优点和缺点:
2. 任务通知值和通知状态
-
任务通知值:
-
任务通知状态:
3. 任务通知相关API函数
任务通知API函数主要有两类:①发送通知 ,②接收通知。发送通知API函数可以用于任务和中断服务函数中;接收通知API函数只能用在任务中。
①发送通知相关API函数:
xTaskGenericNotify()
函数
②接收通知相关API函数:
-
ulTaskNotifyTake()
函数 -
xTaskNotifyWait()
函数
4. 任务通知模拟信号量实验
-
创建任务:
-
任务一:发送任务通知值
/*任务一:发送任务通知值*/ void task1(void* pvParamter) { while(1) { switch(key_scan(0)) { case KEY0_PRES: printf("任务通知模拟二值信号量释放\r\n"); xTaskNotifyGive(task2_task_handler); break; case KEY1_PRES: printf("任务通知模拟计数型信号量释放\r\n"); xTaskNotifyGive(task3_task_handler); break; default: break; } vTaskDelay(20); } }
-
任务二:接收二值信号量任务通知值
/*任务二:接收二值信号量任务通知值*/ void task2(void* pvParamter) { uint32_t rec = 0; while(1) { rec = ulTaskNotifyTake(pdTRUE, portMAX_DELAY); if(rec != 0) { printf("接收任务通知成功,模拟二值信号量!\r\n"); } } }
-
任务三:接收计数型信号量任务通知值
void task3(void* pvParamter) { uint32_t rec = 0; while(1) { rec = ulTaskNotifyTake(pdFALSE, portMAX_DELAY); if(rec != 0) { printf("接收任务通知成功,模拟计数型信信号量为%d!\r\n",rec); } vTaskDelay(1000); } }
-
实验结果:
5. 任务通知模拟消息邮箱和事件标志组实验
-
创建任务:
-
相关变量定义:
//定义事件标志组的位0和位1 #define EVENTBIT_0 (1 << 0) #define EVENTBIT_1 (1 << 1
-
任务一:发送任务通知值
void task1(void* pvParamter) { uint8_t key = 0; while(1) { key = key_scan(0); if((key == KEY0_PRES || key == KEY1_PRES) && (task2_task_handler != NULL)) { printf("任务通知模拟消息邮箱,发送的键值为:%d\r\n",key); xTaskNotify(task2_task_handler, key, eSetValueWithOverwrite); } else if(key == KEY2_PRES) { printf("将bit0位置1\r\n"); xTaskNotify(task3_task_handler, EVENTBIT_0, eSetBits); } else if(key == WKUP_PRES) { printf("将bit1位置1\r\n"); xTaskNotify(task3_task_handler, EVENTBIT_1, eSetBits); } vTaskDelay(10); } }
-
任务二:接收消息邮箱任务通知值:
void task2(void* pvParamter) { uint32_t noyify_val = 0; while(1) { xTaskNotifyWait(0, 0xFFFFFFFF, &noyify_val, portMAX_DELAY); switch(noyify_val) { case KEY0_PRES: { printf("接收到的通知值为:%d\r\n",noyify_val); break; } case KEY1_PRES: { printf("接收到的通知值为:%d\r\n",noyify_val); break; } default: break; } vTaskDelay(10); } }
-
任务三:接收事件标志组任务通知值:
void task3(void* pvParamter) { uint32_t noyify_val = 0; uint32_t event_bit = 0; while(1) { xTaskNotifyWait(0, 0xFFFFFFFF, &noyify_val, portMAX_DELAY); if(noyify_val & EVENTBIT_0) { event_bit |= EVENTBIT_0; } if(noyify_val & EVENTBIT_1) { event_bit |= EVENTBIT_1; } if(event_bit == (EVENTBIT_0 | EVENTBIT_1)) { printf("任务通知模拟事件标志组接收成功!\r\n"); event_bit = 0; } vTaskDelay(10); } }
-
实验结果: