使用消息队列 queue 实现数据通信
概述
如前所述:使用全局变量传递数据的方式存在一些限制,如读写时的数据保护与同步问题、数据缓存的问题(新数据会覆盖旧数据)。
使用队列则可以自动解决上述问题。队列在实现上已经添加了一定的读写保护、并具备一定的存储长度,来缓存一定的数据。当发送数据的一方速度快于使用数据的一方,或者多个数据发送方的情况下,这种缓存机制可以缓解使用数据的一方的一定的处理压力。
此外,队列实现的延时发送机制(发送失败的情况下,若延时时间不为0,可以等待一段时间再发送数据)也可以改善通信双方的速率差异。
xQueueSend(xQueue, // 要发送数据的队列
pvItemToQueue, // 要发送到队列的条目(item)
xTicksToWait) // 队列满时,延时等待的时间
在用邮箱实现多事件的单向同步章节中,已经介绍了队列的基本使用方法和注意事项,这里仅从数据通信的角度给出一些示例。
需求及功能解析
队列适合每次传输的数据长度固定的情况,并且可以应用在数据传输中有多个发送方、多个接收方的的场景。
实际的项目中,产生数据的一方可能多次生产数据,然后将数据发送到另一个任务进行处理。比如,数据采集设备中会多次采集数据,然后将数据发送到另一个任务进行计算、显示到屏幕上等。
示例给出了这样的示例:任务1每生产五个数据,就通过队列发送到任务2。
示例解析
示例输出:
This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, Minimum free heap size: 295348 bytes
TASK2: The buffer data is as follows:00 00 00 00 00
TASK2: The buffer data is as follows:00 01 02 03 04
TASK2: The buffer data is as follows:05 06 07 08 09
TASK2: The buffer data is as follows:0a 0b 0c 0d 0e
讨论
对多次产生数据,集中处理一次的应用场景,使用队列时,存在以下的限制:
1)队列要求每次产生的条目的长度是一样的,如示例中创建的队列的元素类型为 int array[5],则每次最大发送5个数据,超过5个数据的情况下,无法使用该队列进行传输。
2)多次采集单次触发发送的机制需要自己在应用层进行实现。示例中发送方任务1通过计数,来控制这种逻辑:
if(remainder == 0) {
if (xQueueSendToFront(custom_queue, (void *)&data_send, 0) != pdTRUE) { // 每五次发送一个数据
printf("%s: failed send\n", TASK1_TAG); // 检查是否发送失败
}
}
在后续的学习中,我们将介绍具备发送不固定长度的数据、满足一定数量后自动触发接收的通信组件,它们是队列相关特性的补充。
总结
1)队列兼具数据传输,同步的两种功能。
2)队列适合每次传输的数据长度固定的情况,并且可以应用在数据传输中有多个发送方、多个接收方的的场景。
3)队列的不足之处是要求每次发送的条目的长度是一样的,并且没有实现自动完成多次发送触发单次接收的机制。
4)大部分情况下,复杂的数控类型,队列传递的往往是指针类型。
资源链接
1)Learning-FreeRTOS-with-esp32 系列博客介绍
2)对应示例的 code 链接 (点击直达代码仓库)
3)下一篇:使用 stream buffer 传递数据