一.什么是 Stream Buffer?
Stream Buffer(流式缓冲区)是一种在实时操作系统(RTOS)中用于处理和传输连续流式数据的特殊数据结构和机制。它被设计用来有效地管理大块的连续数据,如音频、视频等,与传统的队列不同,它更适合于连续数据流的处理。
1.特性概述
1)发送消息的一方(发送方)与获取消息的一方(接收方)之间可以按任意长度的字节流的方式进行数据传递。
2)可以设置触发唤醒通知的字节数,仅在缓冲区中的数据达到一定长度时,才唤醒接收方接收数据。
3)适用于仅有一个发送方、一个接收方的场景。如果有多个发送方、接收方,则需要在发送、接收处添加互斥保护,特别地,多个接收方时应将接收阻塞时间设置为0。
2.主要特点和作用
-
连续数据流管理: Stream Buffer 能够在环形缓冲区中连续地接收和发送数据。这种特性使其非常适合于需要不间断传输和处理大量数据的应用,如实时音视频流。
-
环形缓冲区设计: 它基于环形缓冲区的概念,允许数据的循环使用。这样一来,数据可以被连续写入和读取,而无需关心物理存储上的碎片化问题。
-
数据量较大: 相对于队列,Stream Buffer 更适用于需要大块数据传输的场景。它可以处理较大的数据块,而不是单个数据项的传输。
-
实时性和效率: FreeRTOS 的 Stream Buffer 实现了高效的数据传输和管理机制,确保在实时操作系统中处理流媒体数据时具有较高的性能和响应速度。、
3.使用场景
-
音频和视频处理:在嵌入式系统中,处理实时音频和视频流需要高效的数据传输和处理能力,Stream Buffer 提供了必要的支持。
-
传感器数据流:当需要采集和处理大量连续的传感器数据时,Stream Buffer 可以帮助有效地管理数据流。
-
实时通信:在需要低延迟和高可靠性的通信应用中,如实时监控系统或远程控制系统,Stream Buffer 可以作为数据传输的重要工具。
二.Stream Buffer 的基本操作
1.创建 Stream Buffer:
使用 xStreamBufferCreate
函数创建一个新的 Stream Buffer。它的参数包括缓冲区的大小和触发接收任务的最小字节数。
StreamBufferHandle_t xStreamBufferCreate(
size_t xBufferSizeBytes, //缓冲区的大小(字节数)。
size_t xTriggerLevelBytes);/触发接收任务的最小字节数。意思是,当buffer至少有大于等于这个值的字节数时,消息才能被接收,该值最小为1,
返回值:
- 成功时返回 Stream Buffer 的句柄(非 NULL);失败时返回 NULL。
2.发送数据到 Stream Buffer:
使用 xStreamBufferSend
函数将数据发送到缓冲区。这个函数需要指定 Stream Buffer 句柄、数据指针、数据长度以及等待时间。
size_t xStreamBufferSend(
StreamBufferHandle_t xStreamBuffer, //Stream Buffer 的句柄。
const void *pvTxData, //要发送的数据指针
size_t xDataLengthBytes, //发送的数据长度(字节数)即拷贝到stream buffer的字节数量。
TickType_t xTicksToWait);//等待时间。
返回值:
- 成功发送的数据字节数。如果返回值小于 xDataLengthBytes,则表示在 xTicksToWait 时间内没有足够的空间发送所有数据。
3.从 Stream Buffer 接收数据:
size_t xStreamBufferReceive(
StreamBufferHandle_t xStreamBuffer, //Stream Buffer 的句柄。
void *pvRxData, //接收数据的缓冲区指针。
size_t xBufferLengthBytes, //接收缓冲区的大小(字节数)。
TickType_t xTicksToWait);//等待时间。
返回值:
- 成功接收的数据字节数。如果返回值小于 xBufferLengthBytes,则表示在 xTicksToWait 时间内没有接收到足够的数据。
注意,Receive 返回的情况有两种可能:
1)获取到不小于唤醒长度的数据。
2)超时返回,此时实际获取的数据长度为 [0,TriggerLevel]。
4.其他 Stream Buffer API
除了上述基本操作外,还有一些其他有用的 Stream Buffer API:
xStreamBufferCreateStatic: 创建静态分配的 Stream Buffer。
xStreamBufferReset: 重置 Stream Buffer,使其变为空。
xStreamBufferSpacesAvailable: 获取 Stream Buffer 中可用的空闲空间。
xStreamBufferBytesAvailable: 获取 Stream Buffer 中可读取的字节数。
xStreamBufferSetTriggerLevel: 设置触发接收任务的最小字节数。
vStreamBufferDelete: 删除 Stream Buffer,释放相关资源。
这些 API 提供了灵活的方式来管理和优化流媒体数据的传输和处理,尤其适用于需要实时性和效率的应用场景。
三、注意
FreeRTOS堆使用情况大小不够时,在Config parameters中把TOTAL_HEAP_SIZE调大一点,比FreeRTOS总堆数大即可
创建俩个任务,一个任务用来Send,一个任务用来Receive
引入头文件 和宏定义BUFFER_LEN 、 TRIGGER_LEVEL
#include "stream_buffer.h"
#define BUFFER_LEN 80 //流缓冲区大小(字节)
#define TRIGGER_LEVEL 20 //触发水平(字节)
先声明streamBuf,类型是StreamBufferHandle_t
在void MX_FREERTOS_Init(void)中创建流缓冲区保存在streamBuf
在send的任务中调用xStreamBufferSend(); 定义lux =753,noisy =3000
void LED1_Task(void const * argument)
{
/* USER CODE BEGIN LED1_Task */
uint32_t lux = 871 ,noisy = 3279;
char buf[64];
/* Infinite loop */
for(;;)
{
//stream buffer 获取数据并存储
printf("adc_value: Lux[%d] Noisy[%d]\n", lux, noisy);
memset(buf, 0, sizeof(buf));
snprintf(buf, sizeof(buf), "{\"lux\":%d,\"noisy\":%d}", lux, noisy);//打包数据在buf中
if(streamBuf != NULL)
{
xStreamBufferSend(streamBuf, buf, 64, 0);//将buf指向的数据,长度为64字节,从串行通信缓冲区的其实地址开始发送
}
osDelay(1000);
}
在Receive的任务中,
void LED2_Task(void const * argument)
{
/* USER CODE BEGIN LED2_Task */
uint16_t requiredBytes = 64;
char adcArry[64];
/* Infinite loop */
for(;;)
{
//获取stream buffer里面的数据
uint16_t actualReadBytes=xStreamBufferReceive(streamBuf, adcArry, requiredBytes, portMAX_DELAY);
printf("actualReadBytes is %d\r\n", actualReadBytes); //接收缓冲区的大小(字节数)
printf("accept array is %s\r\n", adcArry); //接收到的数据
osDelay(1000);
}
四、结语
Stream Buffer 是 FreeRTOS 中强大且高效的工具,用于处理大块流媒体数据的传输和管理。它的设计考虑了实时性和资源效率,使得在嵌入式系统中处理音视频流等连续数据流变得更加简单和可靠。通过上述介绍,希望读者能够更好地理解和应用 Stream Buffer 在实时操作系统中的作用和优势。