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

Freertos——使用队列集优化数据传输

队列集

  • 通常在实际的产品设计中,我们对硬件的原始数据队列和参与操作的软件数据队列应该是分开设计
  • 这样能保证我们的业务逻辑能更加清晰独立,并且硬件读取逻辑可以再不同产品中复用
  • 会导致一个问题,我们需要在每个硬件读取后进行相应的数据转化任务,如果硬件过多会导致任务栈占据过多的内存,且使任务切换过于频繁污染了时间片
  • 因此我们可以使用到队列集,使得写入同一个业务的软件队列的原始数据队列转换达成统一,使得任务数量减少,并且更容易修改移植我们的代码

业务逻辑

红外遥控器驱动程序里,它只应该把键值记录下来、写入某个队列,它不应该把键值转换为游戏的控制键。在红外遥控器的驱动程序里,不应该有游戏相关的代码,这样,切换使用场景时,这个驱动程序还可以继续使用。把红外遥控器的按键转换为游戏的控制键,应该在游戏的任务里实现。要支持多个输入设备时,我们需要实现一个“InputTask”,它读取各个设备的队列,得到数据后再分别转换为游戏的控制键。
队列集的本质也是队列,只不过里面存放的是“队列句柄”。使用过程如下:

  1. 创建队列A,它的长度是n1
  2. 创建队列B,它的长度是n2
  3. 创建队列集S,它的长度是“n1+n2”
  4. 把队列A、B加入队列集S
  5. 这样,写队列A的时候,会顺便把队列A的句柄写入队列集S
  6. 这样,写队列B的时候,会顺便把队列B的句柄写入队列集S
  7. InputTask先读取队列集S,它的返回值是一个队列句柄,这样就可以知道哪个队列有有数据了;然后InputTask再读取这个队列句柄得到数据。

内部机制

每当在一个队列写入数据,系统自动在这个队列在的队列集的队列中写入一个此队列句柄,当队列集读取时就会依次返回出他的队列中存放的句柄,然后再凭借返回的句柄操作对应的队列

创建队列集

QueueSetHandle_txQueueCreateSet(constUBaseType_t uxEventQueueLength)

uxQueueLength:队列集长度,可存放的队列句柄数
返回值非0:成功,返回句柄,以后使用句柄来操作队列
NULL:失败,因为内存不足

加入队列

BaseType_txQueueAddToSet(QueueSetMemberHandle_t xQueueOrSemaphore,QueueSetHandle_t xQueueSet);

xQueueOrSemaphore:队列句柄,要放入的队列
xQueueSet:队列集句柄
返回值pdTRUE:成功
pdFALSE:失败

读取非空队列

QueueSetMemberHandle_txQueueSelectFromSet(QueueSetHandle_t xQueueSet,TickType_tconstxTicksToWait);

xQueueSet:队列集句柄
xTicksToWait:如果队列集空则无法读出数据,可以让任务进入阻塞状态,如果被设为0,无法读出数据时函数会立刻返回;如果被设为portMAX_DELAY,则会一直阻塞直到有数据可写
返回值NULL:失败
队列句柄:成功

从队列集移除成员

BaseType_txQueueRemoveFromSet(QueueSetMemberHandle_t xQueueOrSemaphore,QueueSetHandle_t xQueueSet);

xQueueOrSemaphore:队列句柄,要放入的队列
xQueueSet:队列集句柄
返回值pdTRUE:失败
pdFALSE:成功

删除队列集

voidvQueueDeleteSet(QueueSetHandle_t xQueueSet);

xQueueSet:队列集句柄
注意:需先移除所有成员,否则可能导致内存泄漏!!!

简单程序示例

// 1. 创建队列和队列集QueueHandle_t xKeyQueue=xQueueCreate(5,sizeof(uint8_t));// 按键队列QueueHandle_t xUartQueue=xQueueCreate(3,sizeof(char));// 串口队列QueueSetHandle_t xInputSet=xQueueCreateSet(5+3);// 队列集// 2. 将队列加入队列集xQueueAddToSet(xKeyQueue,xInputSet);xQueueAddToSet(xUartQueue,xInputSet);// 3. 数据写入任务(例如:按键中断、串口中断)voidvWriteTask(void*pvParameters){uint8_tkey=0x01;xQueueSend(xKeyQueue,&key,0);// 写入按键队列,自动触发队列集}// 4. InputTask:统一处理voidvInputTask(void*pvParameters){QueueSetMemberHandle_t xActivatedMember;uint8_tkeyData;charuartData;while(1){// 等待队列集有数据xActivatedMember=xQueueSelectFromSet(xInputSet,portMAX_DELAY);// 判断是哪个队列有数据if(xActivatedMember==xKeyQueue){xQueueReceive(xKeyQueue,&keyData,0);// 处理按键数据(如转换为游戏控制键)}elseif(xActivatedMember==xUartQueue){xQueueReceive(xUartQueue,&uartData,0);// 处理串口数据}}}

注意事项

  1. 队列集长度的设置
    队列集长度需 ≥ 所有成员队列的总长度(或信号量的最大计数值之和)。例如:队列 A 长度为 5,队列 B 长度为 3,则队列集长度应 ≥ 8,最坏情况下,两个队列同时满,队列集需存放 8 个句柄
  2. 成员的 “独占性”
    队列 / 信号量加入队列集后,不应再直接读写,否则会导致队列集状态不同步。需通过队列集机制间接访问,先xQueueSelectFromSet() 获取句柄,再读写对应队列,这个函数类似于xQueueReceive()的阻塞机制
  3. 中断中使用队列集
    若在中断中操作队列集成员,需使用中断安全的队列读取函数( xQueueSendFromISR())
http://www.jsqmd.com/news/730129/

相关文章:

  • 树结构提取与搜索优化技术实战
  • 2026年轴承公司实力推荐/61908薄壁轴承厂家,61806薄壁轴承供应企业,柔性轴承供应企业 - 品牌策略师
  • 在.NET 6.0中使用Serilog实现ElasticSearch日志定制
  • 基于MCP协议构建AI Agent与SQLite数据库的安全交互桥梁
  • WHAT - GitLens supercharged 插件
  • Ledger 官方回应“后门”传闻:秘语盾技术支持可信度分析
  • 基于Flutter的跨平台AI语音助手:实时交互、多协议与MCP扩展实战
  • 2026年计算机本科就业实录:是“天坑”还是“金矿”?普通本科生的破局指南
  • 3Dmax建模避坑指南:用‘桥’和‘推拉’做圆孔,如何避免布线混乱和破面?
  • 【Cursor 工程rules实际感悟】
  • Chapter 5:深度章 - AI 编程思维转变
  • 2026年Q2成都婚纱摄影套餐选型及价格维度技术解析 - 优质品牌商家
  • 中国加密货币投资者必备:Ledger 硬件钱包选购指南
  • Postman/Apifox 实测通关:5分钟搞定微信小程序 auth.code2Session 接口调试与参数获取
  • 改进SMOTE类不平衡故障诊断【附代码】
  • Twitter自动化工具怎么选?实测3种运营方式效果对比(附真实思路)
  • PureThermal 3热成像开发板硬件解析与应用指南
  • 双USB车载充电器设计方案与实现
  • MMD Tools:如何让Blender成为MMD创作者的专业工作站?
  • Java SFTP递归下载踩坑实录:Hutool 5.8.16版本下处理空文件夹和符号链接
  • TongWeb8.0默认 开启 了JNDI缓存导致应用卡
  • Taotoken透明计费与详细账单如何帮助个人开发者控制预算
  • 新手开发者首次接入大模型API可能遇到的常见问题与排查思路
  • 乐山当地人认可的钵钵鸡店排行 附真实消费参考 - 优质品牌商家
  • MySql(高级操作符--高级操作符练习(2))
  • 【ML】K均值聚类及Python手写实现(详细)
  • 3分钟掌握完整网页截图:告别零碎片段,拥抱完整内容保存
  • 冰雪传奇点卡版官方网站:三端互通全解析,随时随地畅玩
  • W55MH32 芯片 MicroPython 实战 (2):GPIO 通用输入输出
  • 中文乱码 ubuntu autodl