在嵌入式开发中,我们经常需要用到 FIFO 数据结构来存储数据,比如任务间的通信、串口数据收发等场合。很多小伙伴不知道 RT-Thread 为我们提供了一个 ringbuffer 数据结构,代码位于:

  • components/drivers/src/ringbuffer.c
  • components/drivers/include/ipc/ringbuffer.h

RingBuffer 其实就是先进先出(FIFO)的循环缓冲区。把一段线性的存储空间当作一个环形的存储空间使用,可以提高存储空间的利用率。

数据结构

RT-Thread 定义了 rt_ringbuffer 结构体,包括四组成员:缓冲区指针 buffer_ptr、缓冲区大小 buffer_size、读指针、写指针。

struct rt_ringbuffer
{rt_uint8_t *buffer_ptr;rt_uint16_t read_mirror : 1;rt_uint16_t read_index : 15;rt_uint16_t write_mirror : 1;rt_uint16_t write_index : 15;rt_int16_t buffer_size;
};

对于读、写指针,rt_ringbuffer 结构体使用位域来定义 read 和 write 的索引值和镜像位。更具体来说,使用 MSB(最高有效位)作为 read_index 和 write_index 变量的镜像位。通过这种方式,为缓冲区添加了虚拟镜像,用于指示 read 和 write 指针指向的是普通缓冲区还是镜像缓冲区。

  • 如果 write_index 和 read_index 相等,但在不同镜像,说明缓冲区满了;
  • 如果 write_index 和 read_index 相等,但在相同镜像,说明缓冲区空了。

为了让大家更好地理解,我给大家画了个图:

接口函数

初始化与重置

void rt_ringbuffer_init(struct rt_ringbuffer *rb, rt_uint8_t *pool, rt_int16_t size);
void rt_ringbuffer_reset(struct rt_ringbuffer *rb);

这两个函数适用于以静态方式初始化或重置 ringbuffer,需要事先准备好 ringbuffer 对象和一段内存空间。

创建和销毁

struct rt_ringbuffer* rt_ringbuffer_create(rt_uint16_t length);
void rt_ringbuffer_destroy(struct rt_ringbuffer *rb);

这两个函数适用于以动态方式创建和销毁 ringbuffer,将在堆空间申请相关资源,并返回一个 ringbuffer 指针。

写入数据

rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length);
rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length);
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch);
rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch);

往 ringbuffer 写入数据可以使用这组函数,其中 `_put` 为写入一串字符,`_putchar` 为写入一个字符,带 `_force` 的函数则表示如果缓冲区满了,将直接用新数据覆盖旧数据(谨慎使用)。

读出数据

rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb, rt_uint8_t *ptr, rt_uint16_t length);
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch);

从 ringbuffer 读出数据可以使用这组函数,其中 `_get` 为读出一串字符,`_getchar` 为读出一个字符。

获取长度

读写操作前可以先判断是否有数据可读或者有位置可写,ringbuffer 提供了三个接口获取长度,包括获取 ringbuffer 的总长度、数据长度、空闲长度。

获取缓冲区数据长度

rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb);

获取缓冲区总长度

rt_uint16_t rt_ringbuffer_get_size(struct rt_ringbuffer *rb);

获取缓冲区空闲长度

#define rt_ringbuffer_space_len(rb) ((rb)->buffer_size - rt_ringbuffer_data_len(rb))

应用示例

下面通过一个简单的示例,来看看在程序中该如何使用 ringbuffer。首先创建一个 ringbuffer 对象,然后 Producer 线程往 ringbuffer 写入数据,Consumer 线程从 ringbuffer 读出数据。这是一个典型生产者-消费者模型。

#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>#define RING_BUFFER_LEN        8static struct rt_ringbuffer *rb;
static char  *str = "Hello, World";static void consumer_thread_entry(void *arg)
{char ch;while (1){if (1 == rt_ringbuffer_getchar(rb, &ch)){rt_kprintf("[Consumer] <- %cn", ch);}rt_thread_mdelay(500);}
}static void ringbuffer_sample(int argc, char** argv)
{rt_thread_t tid;rt_uint16_t i = 0;rb = rt_ringbuffer_create(RING_BUFFER_LEN);if (rb == RT_NULL){rt_kprintf("Can't create ringbffer");return;}tid = rt_thread_create("consumer", consumer_thread_entry, RT_NULL,1024, RT_THREAD_PRIORITY_MAX/3, 20);if (tid == RT_NULL){rt_ringbuffer_destroy(rb);}rt_thread_startup(tid);while (str[i] != '0'){rt_kprintf("[Producer] -> %cn", str[i]);rt_ringbuffer_putchar(rb, str[i++]);rt_thread_mdelay(500);}rt_thread_delete(tid);rt_ringbuffer_destroy(rb);}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT(ringbuffer_sample, Start a producer and a consumer with a ringbuffer);
#endif

运行结果:

.net thread操作串口_听说你不知道 RT-Thread 有个 ringbuffer相关推荐

  1. 多线程设置操作时间间隔_听说,有位Java程序员学完这59道多线程面试题之后,直接面上阿里...

    前言 多线程是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能.具有这种能力的系统包括对称多处理机.多核心处理器以 ...

  2. RT Thread Studio 配置IIC并读取AS5600角度

    RT Thread Studio 配置IIC并读取AS5600角度 一.RT Thread Studio 配置IIC 1.在RT Thread Seting 中开启IIC功能 并保存 一定要保存才能更 ...

  3. 正点原子delay函数移植到rt thread操作系统(HAL库)

    正点原子教程中涉及到的操作系统只涉及了UCOS的教程,其中例程的system文件夹中的delay.c函数只是适配了UCOS. 下面将delay.c函数移植到rt thread中,使用的bsp是rt t ...

  4. python3.6串口编程实例_使用python3实现操作串口详解

    通过引用serial模块包,来操作串口. 1.查看串口名称 在Linux和Windows中,串口的名字规则不太一样. 需要事先查看. Linux下的查看串口命令 root@D2:~# ls -l /d ...

  5. JAVA操作串口有感

    在做过一年多的RXTX操作串口项目有现在把一些平时遇到的问题在这里写写:  RXTX是一个开源包,主要是在COMM开源包中做扩张,以前的COMM包只能在WINDOWS下面对串口或并口做操作,扩充后的R ...

  6. RT Thread之 Uart2 操作

    官网连接:https://docs.rt-thread.org/#/rt-thread-version/rt-thread-standard/programming-manual/device/uar ...

  7. Android 操作串口 (android serial port api)

    Android 操作串口 (android serial port api)

  8. micropython stm32f030_STM32F0单片机快速入门六 用库操作串口(UART)原来如此简单

    1.从 GPIO 到 UART 前面几节我们讲了MCU如何启动,如何用翻转IO引脚,以及用按键去触发中断.接下来我们介绍的也是最常用的一个模块,串口(UART). 串口可以说是最古老,而且生命力最强的 ...

  9. c++ thread 内存泄漏_深入剖析ThreadLocal原理、内存泄漏及应用场景

    本文主要针对JDK1.8讲解 ThreadLocal作用 先看一个简单的示例,创建两个线程,第一个线程向ThreadLocal中写入数据,第二个线程等待第一个线程完成从ThreadLocal中读取数据 ...

最新文章

  1. Transformer深至1000层还能稳定训练,微软实习生一作,LSTM之父转发
  2. java 502错误,Spring Boot连接超时导致502错误的实战案例
  3. java任何表达式都可以当作语句_在Java语言中语句用分号终止,并不是所有的表达式都可以构成语句...
  4. 邮件群发工具的编写(二)数据的保存
  5. ADF:将UI类别与动态表单一起使用
  6. ASP.NET中Session简单原理图
  7. java怎么给坦克上图片_Java坦克大战 (七) 之图片版
  8. 重设OS X (macOS)系统帐户密码的几种方法
  9. 小程序多标签切换、Tab切换类似功能
  10. 5G无线技术基础自学系列 | 5G基站形态演进
  11. excel流程图分叉 合并_excel流程图怎么画
  12. android手机wifi打不开,手机wifi开关打不开什么原因_手机wifi开关失灵的解决方法-系统城...
  13. 《权力的游戏》里,是谁活成了史诗?
  14. 计算机网络 - 应用层
  15. 操作系统实验指导书(完整版)
  16. 动态色调范围 (网络整理)
  17. 针对Unity导出的exe如果提示运行库报错或者系统缺少XX组件的对话框的话。一般解决办法如下:
  18. idea导入项目及导入项目后无目录解决
  19. 【文献笔记】【部分精读】【CIR】Angle of Arrival Estimation based on Channel Impulse Response Measurements
  20. zan-ajax的使用方式

热门文章

  1. 厉害!苏炳添即将在暨南大学成立短跑实验室
  2. 揭晓飞桨平台提速秘诀:INT8量化加速实现“事半功倍”
  3. 【微软出品】AI-神经网络基本原理简明教程
  4. int和Integer的区别在哪里
  5. python3.5全局解释器锁GIL-实现原理浅析
  6. celery源码分析-wroker初始化分析(上)
  7. BIG T 下学期选修_python作业
  8. 刷脸背后,卷积神经网络的数学原理原来是这样的
  9. 可旋转的2K显示器,写代码逼格要到位,免费包邮送到家
  10. 还在用肉眼找不同吗?这个技术轻松搞定