当前位置: 首页 > news >正文

FreeRTOS—队列集

文章目录

  • 一、队列集简介
  • 二、队列集相关API函数
    • 2.1.创建队列集
    • 2.2.队列添加到队列集中
    • 2.3.从队列集中移除队列
    • 2.4.获取队列集中有有效消息的队列
  • 三、实验
    • 3.1.实验设计
    • 3.2.软件设计

一、队列集简介

一个队列只允许任务之间传递的消息为同一种数据类型,如果需要在任务间传递不同的数据类型的消息时,那么就可以使用队列集。 队列集的作用是用于多个队列或信号量进行监听,其中不管哪一个消息到来,都可以让任务退出阻塞状态。假设有一个接收任务,分别使用普通的接收和使用接收队列集的方法:
下面代码是使用普通的方法,它的缺点是如果接收不到队列,就无法进行下一步的获取信号量:

void receive_task()
{等待接收队列;获取信号量;
}

下面代码是使用接收队列集的方法,队列集里面有不同的数据,接收到之后进行if判断:

void receive_task()
{等待队列集中消息;if(队列还是信号量){...;}
}

二、队列集相关API函数

函数描述
xQueueCreateSet( )创建队列集
xQueueAddToSet( )队列添加到队列集中
xQueueRemoveFromSet( )从队列集中移除队列
xQueueSelectFromSet( )获取队列集中有有效消息的队列
xQueueSelectFromSetFromISR( )在中断中获取队列集中有有效消息的队列

2.1.创建队列集

此函数用于创建队列集,该函数在 queue.c 文件中有定义,函数的原型如下所示:

QueueSetHandle_t xQueueCreateSet(const UBaseType_t uxEventQueueLength); 

下面表格是它的形参和描述:

形参描述
uxEventQueueLength队列集可容纳的队列数量

下面表格是它的返回值:

返回值描述
NULL队列集创建失败
其他值队列集创建成功,返回队列集

2.2.队列添加到队列集中

此函数用于往队列集中添加队列,要注意的时,队列在被添加到队列集之前,队列中不能有有效的消息(队列里面为空),该函数在 queue.c 文件中有定义,函数的原型如下所示:

BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t  	  xQueueSet); 

下面表格是它的形参和描述:

形参描述
xQueueOrSemaphore待添加的句柄
xQueueSet队列集

下面表格是它的返回值:

返回值描述
pdPASS队列集添加队列成功
pdFAIL队列集添加队列失败

2.3.从队列集中移除队列

此函数用于从队列集中移除队列,要注意的时,队列在从队列集移除之前,必须没有有效的消息(队列里面为空),该函数在 queue.c 文件中有定义,函数的原型如下所示:

BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t  	   xQueueSet); 

下面表格是它的形参和描述:

形参描述
xQueueOrSemaphore待移除的句柄
xQueueSet队列集

下面表格是它的返回值:

返回值描述
pdPASS队列集移除队列成功
pdFAIL队列集移除队列失败

2.4.获取队列集中有有效消息的队列

此函数用于在任务中获取队列集中有有效消息的队列,该函数在 queue.c 文件中有定义,函数的原型如下所示:

QueueSetMemberHandle_t xQueueSelectFromSet(QueueSetHandle_t xQueueSet, TickType_t const xTicksToWait); 

下面表格是它的形参和描述:

形参描述
xQueueSet队列集
xTicksToWait阻塞超时时间

下面表格是它的返回值:

返回值描述
NULL获取消息失败
其他值获取到消息的队列

三、实验

3.1.实验设计

本实验将设计三个任务,其中 task2 的任务优先级最高,依此递减:

  • start_task:创建其他任务,并创建队列集,队列和信号量,将队列和信号量添加到队列集中
  • task1:用于扫描按键,当 KEY0 按下,往队列写入数据;当 KEY1 按下,释放二值信号量
  • task2:读取队列集中的消息,并打印

本次实验的流程:

  1. 启用队列集功能需要将宏configUSE_QUEUE_SETS配置为 1
  2. 创建队列集、队列、信号量
  3. 往队列集中添加队列或信号量
  4. 往队列集发送信息或释放信号量
  5. 获取队列集的消息

3.2.软件设计

在 start_task 函数里创建另外两个任务、创建队列集、队列、信号量,并将队列和信号量添加至队列集中,下面是 start_task 代码:

QueueSetHandle_t queueSet_handle;	//定义队列集的句柄
QueueHandle_t queue_handle;			//定义队列的句柄
QueueHandle_t semaphore_handle;		//定义二值信号量的句柄void start_task(void *pvParameters)
{taskENTER_CRITICAL();   BaseType_t err1 = 0;BaseType_t err2 = 0;queueSet_handle = xQueueCreateSet(2);if(queueSet_handle != NULL){printf("队列集创建成功\r\n");}queue_handle = xQueueCreate(1, sizeof(uint8_t));if(queue_handle != NULL){printf("队列创建成功\r\n");}semaphore_handle = xSemaphoreCreateBinary();if(queue_handle != NULL){printf("二值信号量创建成功\r\n");}err1 = xQueueAddToSet(queue_handle, queueSet_handle);if(err1 == pdPASS){printf("队列已添加至队列集中\r\n");}err2 = xQueueAddToSet(semaphore_handle, queueSet_handle);if(err2 == pdPASS){printf("信号量已添加至队列集中\r\n");}xTaskCreate((TaskFunction_t)    task1,	(char*)             "task1",(uint16_t)          TASK1_STACK_SIZE,(void*)             NULL,(UBaseType_t)       TASK1_PRIO,(TaskHandle_t*)     &task1_handler);xTaskCreate((TaskFunction_t)    task2,	(char*)             "task2",(uint16_t)          TASK2_STACK_SIZE,(void*)             NULL,(UBaseType_t)       TASK2_PRIO,(TaskHandle_t*)     &task2_handler);vTaskDelete(NULL);	taskEXIT_CRITICAL();            
}

下面是 task1 的代码实现,task1 的任务优先级为 2:

void task1(void *pvParameters)
{uint8_t key = 0;BaseType_t err1 = 0;BaseType_t err2 = 0;while(1){key = key_scan(0);if(key == KEY0_PRES){err1 = xQueueSend(queue_handle, &key, portMAX_DELAY);if(err1 == pdTRUE){printf("数据写入成功\r\n");}}else if(key == KEY1_PRES){err2 = xSemaphoreGive(semaphore_handle);if(err2 == pdTRUE){printf("信号量释放成功\r\n");}}}
}

下面是 task2 的代码实现,task2 的任务优先级为 3:

void task2(void *pvParameters)
{QueueSetMemberHandle_t member_handle; uint8_t key = 0;while(1){member_handle = xQueueSelectFromSet(queueSet_handle, portMAX_DELAY);if(member_handle == queue_handle){xQueueReceive(member_handle, &key, portMAX_DELAY);printf("获取到的队列数据为:%d\r\n",key);}else if(member_handle == semaphore_handle){xSemaphoreTake(member_handle, portMAX_DELAY);printf("信号量获取成功\r\n");}}
}

下图是运行的结果图:

在这里插入图片描述

为什么按下按键之后,打印出来的信息顺序的倒过来的呢?这是因为 task2 的任务优先级高于 task1 的任务优先级;开始的时候所有的东西创建完毕之后,task2 获取不到有内容的队列或信号量,因此 task2 进入阻塞状态,如果按下 KEY0,数据就被写入队列,task2 就立刻抢占 task1,进行 task2 的打印,task2 的打印结束之后,又进入阻塞状态,这个时候才会运行 task1 的打印结果,按下 KEY1 也同理。

http://www.lryc.cn/news/601798.html

相关文章:

  • 【Web APIs】JavaScript 节点操作 ⑩ ( 节点操作综合案例 - 动态生成表格案例 )
  • add新增管理员功能、BaseController类的简介--------示例OJ
  • 链表算法综合——重排链表
  • Webpack 和 Vite 的关键区别
  • 01人工智能中优雅草商业实战项目视频字幕翻译以及声音转译之底层处理逻辑阐述-卓伊凡|莉莉
  • J2EE模式---服务层模式
  • WAIC 2025 热点解读:如何构建 AI 时代的“视频神经中枢”?
  • Java面试题及详细答案120道之(081-100)
  • 零基础学习性能测试第五章:JVM性能分析与调优-多线程机制与运行原理
  • 【RAG技术权威指南】从原理到企业级应用实践
  • 蓝奏云网盘API 2.0
  • HCIE学习之路:路由引入
  • 比特币运行机制全解析:区块链、共识算法与数字黄金的未来挑战
  • 【代码问题】【包安装】MMCV
  • Item15:在资源管理类中提供对原始资源的访问
  • C语言(长期更新)第6讲:函数
  • 20250727-1-Kubernetes 网络-Ingress介绍,部署Ingres_笔记
  • rename系统调用及示例
  • 虚拟机ubuntu20.04共享安装文件夹
  • 【笔记】系统
  • ADB Shell 命令
  • 安装redis
  • 2025.7.22总结-幸福的力量
  • 《汇编语言:基于X86处理器》第10章 结构和宏(1)
  • 数据库连接操作详解:左连接、右连接、全连接与内连接
  • LeetCode 239:滑动窗口最大值
  • LeetCode第350题_两个数组的交集II
  • NVMe高速传输之摆脱XDMA设计17:队列管理控制设计(下)
  • 金字塔降低采样
  • 企业IT管理——突发病毒事件应急处理预案模板