使用 F r e e R T O S FreeRTOS FreeRTOS的应用都被组织成一个个独立的任务,这些任务之间有可能需要相互通信来实现更复杂的系统功能。前面我们介绍过的 队列 队列 队列, 事件组 事件组 事件组, 二进制信号量 二进制信号量 二进制信号量以及 计数信号量 计数信号量 计数信号量等都可以用来实现任务之间的通信,这里我们介绍的任务通知也可以用来实现任务之间的通信,任务通知和前面我们介绍过的实现任务之间的通信的方法最大的区别是,在使用任务通知之前不需要创建某个对象,但是对于 队列 队列 队列, 事件组 事件组 事件组, 二进制信号量 二进制信号量 二进制信号量以及 计数信号量 计数信号量 计数信号量等在使用之前必须建立相应的对象。创建的对象相当于是任务之间通信的一个桥梁,如图1所示。而对于任务通知的话,就不需要这个桥梁而是可以在任务间直接通信,如图2所示。
为什么使用任务通知不需要创建对象,那是因为任务通知相关的东西就包含在任务控制块中,只要任务创建了,这些相关的东西就自然存在了(需要将宏 c o n f i g U S E _ T A S K _ N O T I F I C A T I O N S configUSE\_TASK\_NOTIFICATIONS configUSE_TASK_NOTIFICATIONS定义为1),如图3所示。图3中的那两个和任务通知相关的数组都默认只有一个元素,其中 u c N o t i f y S t a t e ucNotifyState ucNotifyState表示任务通知的状态,收到或者没有收到任务通知, u l N o t i f i e d V a l u e ulNotifiedValue ulNotifiedValue表示任务通知的值。任务通知可以实现我们前面介绍过的那些实现任务之间的通信的方法实现的功能,只不过相对的是一个轻量化的版本,不能完全取代,它们各有优缺点
任务通知相对我们前面介绍过的那些实现任务之间的通信的方法的优点有:
- 速度更快
- 需要的 R A M RAM RAM空间更少
任务通知相对我们前面介绍过的那些实现任务之间的通信的方法的局限性有:
- 任务通知只能是任务发送给任务或中断发送给任务而不能是任务发送给中断
- 任务通知只能发送给一个任务而不能是多个任务
- 相比起队列任务通知能够存储的数据有限
- 任务通知的发送操作不可以用发送等待延时,如果要发送的任务刚刚已经接收了任务通知。
任务通知常用的发送 A P I API API接口是 x T a s k N o t i f y G i v e xTaskNotifyGive xTaskNotifyGive(功能更强大的版本是 x T a s k N o t i f y xTaskNotify xTaskNotify),常用的接收 A P I API API接口是 u l T a s k N o t i f y T a k e ulTaskNotifyTake ulTaskNotifyTake(功能更强大的版本是 x T a s k N o t i f y W a i t xTaskNotifyWait xTaskNotifyWait)。至于其它接口大家可以自己去看一下 F r e e R T O S FreeRTOS FreeRTOS的官方接口参考手册,如图4所示。
下面我们来跑一个简单的例子,(工程代码在)这里),这个例子创建了两个任务,一个任务用来接收任务通知,另一个任务用来发送任务通知。接收通知的任务如果没有接收到任务通知的话就一直处于等待状态,发送任务通知的任务检测到按键按下就发送任务通知给接收任务通知的任务。这里的场景相当于是任务通知实现了二进制信号量的功能,至于任务通知实现 队列 队列 队列, 事件组 事件组 事件组以及 计数信号量 计数信号量 计数信号量等场景大家可以参考以下野火和 F r e e R T O S FreeRTOS FreeRTOS的官方文档。
#include "usart.h"
#include "key.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"
#include "projdefs.h"
static TaskHandle_t Receiver_Task_Handle = NULL;
static void Receiver_Task( void *pvParameters )
{
while(1)
{
ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
printf("Task notifications have arrived\r\n");
}
}
static void Sender_Task( void *pvParameters )
{
while(1)
{
if(Key_Scan(1)==KEY0_PRES)
{
printf("Give receiver task a notification.\r\n");
xTaskNotifyGive(Receiver_Task_Handle);
}
vTaskDelay(50);
}
}
int main( void )
{
TimerHandle_t xAutoReloadTimer, xOneShotTimer;
BaseType_t xTimer1Started, xTimer2Started;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
KEY_Init();
uart_init(115200);
printf("Task notifications demo start.\r\n");
xTaskCreate( Sender_Task, "Sender", 1000, NULL, 2, NULL );
xTaskCreate( Receiver_Task, "Receiver", 1000, NULL, 1, (TaskHandle_t *)(&Receiver_Task_Handle) );
/* Start the scheduler so the created tasks start executing. */
vTaskStartScheduler();
/* As always, this line should not be reached. */
for( ;; );
}