0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

分享一个嵌入式通用FIFO环形缓冲区实现库

strongerHuang 来源:Mculover666 2024-10-23 16:20 次阅读

转自| Mculover666

今天给大家分享一个开源的嵌入式通用FIFO环形缓冲区实现库:ringbuff 地址:

https://github.com/MaJerle/ringbuff

1. 关于ringbuff

开源项目ringbuff ,是一款通用FIFO环形缓冲区实现的开源库,作者MaJerle,遵循 MIT 开源许可协议。

目前 ringbuff 的特点有:

使用C99语法编写,并且没有平台相关代码;

没有动态内存分配;

使用更优的内存复制而不是循环从内存读取数据/向内存写入数据;

2. 移植ringbuff

2.1. 移植思路

在移植过程中主要参考两个资料:项目的readme文档和demo工程。

对于这些开源项目,其实移植起来也就两步:

① 添加源码到裸机工程中;

② 实现需要的接口即可;

2.2. 准备裸机工程

本文中我使用的是小熊派IoT开发套件,主控芯片STM32L431RCT6:

c81da2cc-9074-11ef-a511-92fbcf53809c.png

移植之前需要准备一份裸机工程,我使用STM32CubeMX生成,需要初始化以下配置:

配置一个串口,中断方式接收数据,查询方式发送数据;

printf重定向;

2.3. 添加ringbuff 到工程中

① 复制 ringbuff 源码到工程中:

c85233c0-9074-11ef-a511-92fbcf53809c.png

② 在keil中添加 ringbuff 组件的源码文件:

c86925c6-9074-11ef-a511-92fbcf53809c.png

③ 添加 ringbuff 的头文件路径:

c878e1e6-9074-11ef-a511-92fbcf53809c.png

2.4. 配置ringbuff

ringbuff中默认volatile关键词没有定义,需要手动配置一下,在ringbuff.h中:

c89419e8-9074-11ef-a511-92fbcf53809c.png

至此,ringbuff移植修改完成,可以愉快的使用ringbuff啦~

3. 使用ringbuff

3.1. 为什么使用ringbuff

缓冲区一般用于解决设备接收数据的速度和设备处理速度不匹配的情况下,防止丢包,通俗的来说就是:收到数据先存进缓冲区,等到CPU来处理的时候一次性取出处理。

缓冲区有两种形式,一种是数组,一种就是本文所介绍的环形缓冲区ringbuff。

相较于数组,环形缓冲区对整段内存的利用达到最大,并且使用非常方便,如下:

① 写入的时候不用手动维护下标,直接写入即可(由缓冲区的实现维护);

② 读取的时候不用判断从哪里读,直接读取即可(有缓冲区的实现维护)

本文设计的一个简单的不定长串口协议如下:

c8a75a26-9074-11ef-a511-92fbcf53809c.png

数据类型:比如0x3F表示这是通道1的数据,0x4E表示通道2的数据;

数据长度:表示后面跟着有效数据的长度;

有效数据:有效字节数;

校验数据:省略;

接下来演示如何用环形缓冲区做到不丢包解析。

3.2. 计算缓冲区大小

假定数据每200ms处理一次,而数据10ms接收一次,每次接收的数据包长度为7个字节。

要想做到不丢包,就需要将200ms内接收到的所有数据包都存进缓冲区,所以缓冲区大小至少为:200/10*7 = 140 个字节。

保险起见,可以将缓冲区适当的扩大一下,设置为150个字节。

3.3. 初始化缓冲区

使用时包含头文件:

#include"ringbuff/ringbuff.h"

接着初始化缓冲区:

uint8_tringbuff_init(RINGBUFF_VOLATILEringbuff_t*buff,void*buffdata,size_tsize);

该 API 用来初始化一个ringbuff句柄(指向ringbuff结构体的指针),其中传入的参数分别为:

buff:ringbuff句柄;

buffdata:缓冲区地址;

size:缓冲区大小;

首先创建一个缓冲区句柄,开辟一块缓冲区:

/*Privateusercode---------------------------------------------------------*/
/*USERCODEBEGIN0*/
//用于串口接收
uint8_trecv_data=0;

//用于存储从缓冲区读取出的数据
uint8_tread_data=0;

//用于串口1的ringbuff句柄
ringbuff_tusart1_ringbuff;

//开辟一块内存用于缓冲区
#defineUSART1_BUFFDATA_SIZE150
uint8_tusart1_buffdata[USART1_BUFFDATA_SIZE];

/*USERCODEEND0*/

然后在main函数中初始化ringbuff:

/*USERCODEBEGIN2*/
printf("ringbuffPortByMculover666
");

//初始化ringbuff句柄
if(1!=ringbuff_init(&usart1_ringbuff,(uint8_t*)usart1_buffdata,USART1_BUFFDATA_SIZE))
{
printf("usart1ringbuffinitfail.
");
}

//使能串口中断接收
HAL_UART_Receive_IT(&huart1,(uint8_t*)&recv_data,1);

/*USERCODEEND2*/

3.4. 数据接收

接收到一个字节数据后,话不多说,直接往缓冲区扔:

/*USERCODEBEGIN4*/
/*中断回调函数*/
voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart)
{
/*判断是哪个串口触发的中断*/
if(huart->Instance==USART1)
{
/*将接收到的数据写入缓冲区*/
ringbuff_write(&usart1_ringbuff,&recv_data,1);
//重新使能串口接收中断
HAL_UART_Receive_IT(huart,(uint8_t*)&recv_data,1);
}
}
/*USERCODEEND4*/

3.5. 数据处理

数据处理在while(1)中进行,每隔200ms将缓冲区数据全部读出进行处理:

/*USERCODEBEGINWHILE*/
while(1)
{
/*USERCODEENDWHILE*/


/*USERCODEBEGIN3*/
while((len=ringbuff_read(&usart1_ringbuff,(uint8_t*)&read_data,sizeof(read_data)))>0)
{
/*捕获起始标志*/
if(read_data==0x3F)
{
//读取数据字节数,最大支持0xFF
if((len=ringbuff_read(&usart1_ringbuff,(uint8_t*)&read_data,sizeof(read_data)))>0)
{
data_len=read_data;
printf("yourdatahas%dbyte(s):
	",data_len);
}

//提取data_len个数据
for(i=0;i< data_len; i++)
   {
    if((len = ringbuff_read(&usart1_ringbuff, (uint8_t*)&read_data, sizeof(read_data))) >0)
{
printf("[0x%02x]",read_data);
}
}
printf("over
");
}
}
HAL_Delay(200);

}
/*USERCODEEND3*/

编译下载测试,实验结果如下,可以做到不丢包解析:

c8c4dc2c-9074-11ef-a511-92fbcf53809c.png

3.6. 丢包测试

经过3.2节的计算,不丢包的最小缓冲区大小是140个字节,接下里我们将缓冲区大小修改为100个字节,测试一下是否产生丢包:

//开辟一块内存用于缓冲区
#defineUSART1_BUFFDATA_SIZE100//会发生丢包
//#defineUSART1_BUFFDATA_SIZE150//10ms接收7byte的协议包时不丢包
uint8_tusart1_buffdata[USART1_BUFFDATA_SIZE];

再次编译下载,查看串口输出:

c8db1294-9074-11ef-a511-92fbcf53809c.png

4. 设计思想解读

关于环形缓冲区背后的设计实现,请阅读这篇文章,写的非常棒:

STM32进阶之串口环形缓冲区实现

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 缓冲区
    +关注

    关注

    0

    文章

    33

    浏览量

    9181
  • 嵌入式
    +关注

    关注

    5096

    文章

    19199

    浏览量

    308272
  • fifo
    +关注

    关注

    3

    文章

    390

    浏览量

    43930
  • 串口
    +关注

    关注

    14

    文章

    1562

    浏览量

    77232
  • 开源
    +关注

    关注

    3

    文章

    3421

    浏览量

    42781

原文标题:分享一个嵌入式通用FIFO环形缓冲区实现库

文章出处:【微信号:strongerHuang,微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于C语言实现环形缓冲区/循环队列

    这里分享自己用纯C实现环形缓冲区
    的头像 发表于 04-11 10:39 3448次阅读
    基于C语言<b class='flag-5'>实现</b><b class='flag-5'>环形</b><b class='flag-5'>缓冲区</b>/循环队列

    基于宏高效实现环形缓冲区教程

    来源 | 小麦大叔 循环缓冲区嵌入式软件工程师在日常开发过程中的关键组件。 多年来,互联网上出现了许多不同的循环缓冲区实现和示例。我非常喜欢这个模块,可以GitHub上找到这个开源的
    的头像 发表于 09-02 09:24 6796次阅读
    基于宏高效<b class='flag-5'>实现</b><b class='flag-5'>环形</b><b class='flag-5'>缓冲区</b>教程

    STM32进阶之串口环形缓冲区实现

    完了数据,‘0’地址空间的数据进行释放掉,列队头指向下一个可以处理数据的地址‘1’。从而实现整个环形缓冲区的数据读写。看图,队列头就是指向已经存储的数据,并且这个数据是待处理的。下
    发表于 06-08 14:03

    STM32串口环形缓冲区实现

    是列队头的数据,处理完了数据,‘0’地址空间的数据进行释放掉,列队头指向下一个可以处理数据的地址‘1’。从而实现整个环形缓冲区的数据读写。看图,队列头就是指向已经存储的数据,并且这个数
    发表于 10-16 11:40

    环形缓冲区的设计分享!

    以下内容转自网络,感谢网友:玩笑joker 环形缓冲区嵌入式系统中十分重要的种数据结构,比如在
    发表于 10-28 23:29

    环形缓冲区简介

    程序中,经常使用环形缓冲器作为数据结构来存放通信中发送和接收的数据。环形缓冲区先进先出的循
    发表于 08-17 06:56

    请问怎么实现串口环形缓冲区FIFO

    请问怎么实现串口环形缓冲区FIFO
    发表于 12-06 07:23

    环形缓冲区读写操作的分析与实现

    环形缓冲区嵌入式系统中种重要的常用数据结构。在多任务环境下实现时,如果有多个读写任务,般需
    发表于 04-15 11:35 40次下载

    环形缓冲区实现原理

    在通信程序中,经常使用环形缓冲区作为数据结构来存放通信中发送和接收的数据。环形缓冲区先进先
    的头像 发表于 03-22 10:03 7617次阅读
    <b class='flag-5'>环形</b><b class='flag-5'>缓冲区</b>的<b class='flag-5'>实现</b>原理

    缓冲区是啥意思 STM32串口数据接收之环形缓冲区

    缓冲区顾名思义是缓冲数据用的。实现缓冲区最简单的办法时,定义多个数组,接收包数据到数组A,就把接收数据的地址换成数组B,每个数据有
    的头像 发表于 07-22 15:33 1.1w次阅读

    STM32串口数据接收 --环形缓冲区

    程序中,经常使用环形缓冲器作为数据结构来存放通信中发送和接收的数据。环形缓冲区先进先出的循
    发表于 12-28 19:24 31次下载
    STM32串口数据接收 --<b class='flag-5'>环形</b><b class='flag-5'>缓冲区</b>

    环形缓冲区实现思路

    单片机程序开发般都会用到UART串口通信,通过通信来实现上位机和单片机程序的数据交互。通信中为了实现正常的收发,般都会有对应的发送和接收缓存来暂存通信数据。这里使用
    的头像 发表于 01-17 15:07 1724次阅读

    STM32进阶之串口环形缓冲区实现

    STM32进阶之串口环形缓冲区实现
    的头像 发表于 09-19 09:20 2539次阅读
    STM32进阶之串口<b class='flag-5'>环形</b><b class='flag-5'>缓冲区</b><b class='flag-5'>实现</b>

    C++环形缓冲区设计与实现

    的存储空间。环形缓冲区的特点是其终点和起点是相连的,形成环状结构。这种数据结构在处理流数据和实现数据缓存等场景中具有广泛的应用。
    的头像 发表于 11-09 11:21 2320次阅读
    C++<b class='flag-5'>环形</b><b class='flag-5'>缓冲区</b>设计与<b class='flag-5'>实现</b>

    嵌入式环形队列与消息队列的实现原理

    嵌入式环形队列,也称为环形缓冲区或循环队列,是种先进先出(FIFO)的数据结构,用于在固定大小
    的头像 发表于 09-02 15:29 698次阅读