目录
队列集
在使用队列进行任务之间的“沟通交流”时,一个队列只允许任务间传递的消息为同一种数据类型,如果需要在任务间传递不同数据类型的消息时,那么就可以使用队列集。FreeRTOS提供的队列集功能可以对多个队列进行“监听”,只要被监听的队列中有一个队列有有效的消息,那么队列集的读取任务都可以读取到消息,如果读取任务因读取队列集而被阻塞,那么队列集将解除读取任务的阻塞。使用队列集的好处在于,队列集可以是的任务可以读取多个队列中的消息,而无需遍历所有待读取的队列,以确定具体读取哪一个队列。
使用队列集功能,需要在 FreeRTOSConfig.h 文件中将配置项 configUSE_QUEUE_SETS 配
置为 1,来启用队列集功能。
队列集常用API函数
函数
|
描述
|
xQueueCreateSet()
|
创建队列集
|
xQueueAddToSet()
|
队列添加到队列集中
|
xQueueRemoveFromSet()
|
从队列集中移除队列
|
xQueueSelectFromSet()
|
获取队列集中有有效消息的队列
|
xQueueSelectFromSetFromISR()
|
在中断中获取队列集中有有效消息的队列
|
使用方法
1.创建队列集
QueueSetHandle_t xQueueSet;//队列集
xQueueSet = xQueueCreateSet(3); //队列集中容纳3个队列或信号量
2.向队列集添加
TestQueue1 = xQueueCreate(3, sizeof(uint8_t));//创建队列
TestQueue2 = xQueueCreate(3, sizeof(uint8_t));//创建队列
xSemaphore = xSemaphoreCreateBinary();//创建二值信号量
xQueueAddToSet(TestQueue1,xQueueSet);
xQueueAddToSet(TestQueue2,xQueueSet);
xQueueAddToSet(xSemaphore,xQueueSet); //加入集合
!需要注意的是队列集既可以向里面添加队列也可以添加信号量(毕竟信号量本质也是队列)
3.激活响应的队列/信号
和正常激活一样
xQueueSend(TestQueue1,&key,portMAX_DELAY);
xQueueSend(TestQueue2,&key,portMAX_DELAY);
xSemaphoreGive(xSemaphore);
4.响应
//接收任务
void Task2(void *pvParameters)
{
QueueSetMemberHandle_t activate_member = NULL;//创建队列集获取变量
uint8_t queue_recv;
while(1)
{
activate_member = xQueueSelectFromSet(xQueueSet, portMAX_DELAY);
if(activate_member==TestQueue1){
xQueueReceive(TestQueue1, &queue_recv, portMAX_DELAY);
printf("接收到TestQueue1 %d\r\n",queue_recv);
}
else if(activate_member==TestQueue2){
xQueueReceive(TestQueue2, &queue_recv, portMAX_DELAY);
printf("接收到TestQueue2 %d\r\n",queue_recv);
}
else if(activate_member==xSemaphore){
xSemaphoreTake(activate_member, portMAX_DELAY);
printf("获取到二值信号量: xSemaphore\r\n");
}
}
}
这样就可以做到使用队列集使得单个任务响应多个队列/信号量的效果
任务通知
任务通知的优势
使用任务通知向任务发送事件或数据比使用队列、事件标志组或信号量快得多;并且使用
任务通知代替队列、事件标志组或信号量,可以节省大量的内存,这是因为每个通讯对象在使
用之前都需要被创建,而任务通知功能中的每个通知只需要在每个任务中占用固定的 5 字节内
存。
任务通知的缺点
虽然任务通知功能相比通讯对象,有着更快、占用内存少的优点,但是任务通知功能并不
能适用于所有情况,例如以下列出的几种情况:
1. 无法发送事件或数据到中断
通讯对象可以发送事件或数据从中断到任务,或从任务到中断,但是由于任务通知依赖于任务控制块中的两个成员变量,并且中断不是任务,因此任务通知功能并不适用于从任务往中断发送事件或数据的这种情况,但是任务通知功能可以在任务之间或从中断到任务发送事件或数据。
2.无法存在多个接收任务
通讯对象可以被已知通讯对象句柄的任意多个任务或中断访问(发送或接收),但任务通知
是直接发送事件或数据到指定接收任务的,因传输的事件或数据只能由接收任务处理。然而在实际中很少受到这种情况的限制,因为,虽然多个任务和中断发送事件或数据到一个通讯对象是很常见的,但很少出现多个任务或中断接收同一个通讯对象的情况。
3. 无法缓冲多个数据项
通讯对象中的队列是可以一次性保存多个已经被发送到队列,但还未被接收的事件或数据
的,也就是说,通讯对象有着一定的缓冲多个数据的能力,但是任务通知是通过更新任务通知
值来发送事件或数据的,一个任务通知值只能保存一次。
4. 广播到多个任务
通讯对象中的事件标志组是可以将一个事件同时发送到多个任务中的,但任务通知只能是被指定的一个接收任务接收并处理。
5. 阻塞等待接收任务
当通讯对象处于暂时无法写入的状态(例如队列已满,此时无法再向队列写入消息)时,发送任务是可以选择阻塞等待接收任务接收,但是任务因尝试发送任务通知到已有任务通知但还未处理的任务而进行阻塞等待的。但是任务通知也很少在实际情况中收到这种情况的限制。
使用方法
在需要下次任务切换的时候切换到需要运行的任务,简单粗暴
xTaskNotifyGive((TaskHandle_t)Task3_Handler);//任务通知
在需要等待任务通知的任务中
//接收通知任务
void Task3(void *pvParameters)
{
while (1){
uint32_t notify_val = ulTaskNotifyTake( (BaseType_t )pdTRUE,(TickType_t )portMAX_DELAY);
if (notify_val != 0){
printf("接收到任务通知\r\n");
}
}
}
任务通知常用API函数
这是最常用的简单的通知,类似于二值信号量
函数
|
描述
|
xTaskNotify()
|
发送任务通知
|
xTaskNotifyAndQuery()
| |
xTaskNotifyGive()
| |
xTaskNotifyFromISR()
|
在中断中发送任务通知
|
xTaskNotifyAndQueryFromISR()
| |
vTaskNotifyGiveFromISR()
| |
ulTaskNotifyTake()
|
接收任务通知
|
xTaskNotifyWait()
|