用C代码实现环形缓冲区(ring buf)

用C代码实现环形缓冲区(ring buf)

  • 概述
  • 环境介绍
    • launch.json(没改)
    • tasks.json
    • 注意
  • 代码
    • ringbuf.c
    • ringbuf.h
    • main.c
  • 测试说明
    • 工程代码下载

概述

因嵌入式项目需要,串口接收的数据有很高的周期性发送频率,原方式通过查询接收标志再接收会导致数据丢失和硬件buf溢出等问题,因此考虑开足够大的环形缓冲区(ring buf)实现,接收中断中仅实时的进行buf写操作,应用程序进行循环查询处理,将数据处理和数据接收解耦合,本文采用VS Code + Gcc编译器编写了测试验证程序,对ringbuf进行了测试,参考文章链接,并非照抄,而是在原文基础上进行了改进,并封装成单独的.c文件。

环境介绍

本文测试代码时在VS Code环境下进行了编写和调试,编译工具用的mingw64,详细配置方法就不做介绍了,主要介绍我遇到的一个问题:单个C程序可正常编译,但多个C程序编译报错(未定义的函数名),主要问题是launch.json 和 tasks.json 不对,参考文章,我的配置如下:

launch.json(没改)

 {
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": []
}

tasks.json

该文件主要修改了 “ f i l e " 参数为: " {file}" 参数为:" file"参数为:"{cwd}\*.c”,以编译当前工程目录下的所有C文件

{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "cppbuild",
			"label": "C/C++: gcc.exe 生成活动文件",
			"command": "C:\\mingw64\\bin\\gcc.exe",
			"args": [
				"-fdiagnostics-color=always",
				"-g",
				//"${file}", //默认仅编译当前打开的单个文件
				"${cwd}\\*.c",//编译当前目录下的所有C文件
				"-o",
				"${fileDirname}\\${fileBasenameNoExtension}.exe"
			],
			"options": {
				"cwd": "${fileDirname}"
			},
			"problemMatcher": [
				"$gcc"
			],
			"group": "build",
			"detail": "编译器: C:\\mingw64\\bin\\gcc.exe"
		}
	]
}

注意

这2个文件不是自己编写的,生成方法如下:
打开项目文件夹->终端->配置默认生成任务->选择gcc,之后会自动生成,我们只需要修改部分内容即可

代码

三个文件,main.c为主程序,ringbuf.c和ringbuf.h

ringbuf.c


#include "ringbuf.h"

/* ******************************************
* 环形缓冲区初始化函数 InitRingBuff函数参数说明:
*   参数1 buf :指向ringbuf的结构体指针
*   参数2 size :buf大小,单位字节
*   参数3 over_mode :写入覆盖模式
*        0-   当buf满时阻塞写,并丢弃最新数据
*        1-   当buf满时覆盖写,并丢弃最早的数据
***************************************** */
void InitRingBuff(ringfifo *buf, unsigned int size,int over_mode)
{
    buf->pHead = (char *)malloc(size * sizeof(char));
    memset(buf->pHead, 0, size);
    buf->pValidRead = buf->pHead;
    buf->pValidWrite = buf->pHead;
    buf->pTail = buf->pHead + size;
    buf->used_space = 0;
    buf->free_space = size;
    buf->overwrite = over_mode; 
    printf("pread is %d \t pwrite is %d \t used_space is %d \n",buf->pValidRead,buf->pValidWrite,buf->used_space);
}

// 向缓冲区写数据
int WriteRingBuff(ringfifo *buf,char *pdata, unsigned int len)
{
    if (buf->pHead == NULL )
    {
        printf("WriteRingBuff: RingBuff is not Init!\n");
        return -2;
    }
    if (len > buf->pTail - buf->pHead)
    {
        printf("WriteRingBuff: ring buf is too small\n");//每次写入数据不能超过buf总长度,否则认为buf开的不够
        return -1;
    }
    if ((len > buf->free_space) && (buf->overwrite != 1))
    {
        printf("WriteRingBuff: New add data is too long\n");//只有在覆盖模式才可写入超过剩余空间的数据,否则无法写入
        return -1;
    }
    // 若新增的数据长度大于写指针和尾指针之间的长度
    if (buf->pValidWrite + len > buf->pTail)
    {
        int PreLen = buf->pTail - buf->pValidWrite;
        int LastLen = len - PreLen;
        memcpy(buf->pValidWrite, pdata, PreLen);
        memcpy(buf->pHead, pdata + PreLen, LastLen);
        buf->pValidWrite = buf->pHead + LastLen; // 新环形缓冲区尾地址
    }
    else
    {
        memcpy(buf->pValidWrite, pdata, len); // 将新数据内容添加到缓冲区
        buf->pValidWrite += len;              // 新的有效数据尾地址
    }
    if ((len > buf->free_space) && (buf->overwrite == 1))//覆盖写
    {
        buf->pValidRead = buf->pValidWrite;
        buf->used_space = buf->pTail - buf->pHead; 
        buf->free_space = 0;
    }
    else{//未覆盖
        buf->used_space += len; 
        buf->free_space -= len;
    }
    return 1;
}

// 从缓冲区读数据
int ReadRingBuff(ringfifo *buf, char *pdata, unsigned int len)
{
    if (buf->pHead == NULL )
    {
        printf("ReadRingBuff: RingBuff is not Init!\n");
        return -2;
    }
    if (len > buf->used_space)
    {
        printf("ReadRingBuff: Read data is too long\n");
        return -1;
    }
    if (len == 0)
    {
        return 1;
    }
    if (buf->pValidRead + len > buf->pTail)
    {
        int PreLen = buf->pTail - buf->pValidRead;
        int LastLen = len - PreLen;
        memcpy(pdata, buf->pValidRead, PreLen);
        memcpy(pdata + PreLen, buf->pHead, LastLen);
        buf->pValidRead = buf->pHead + LastLen;
    }
    else
    {
        memcpy(pdata, buf->pValidRead, len);
        buf->pValidRead += len;
    }
    buf->used_space -= len;
    buf->free_space +=len;
    return len;
}

ringbuf.h

#ifndef __RINGBUF_H_
#define __RINGBUF_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

typedef struct
{
    char *pHead;       // 环形缓冲区首地址
    char *pValidRead;  // 已使用环形缓冲区首地址
    char *pValidWrite; // 已使用环形缓冲区尾地址
    char *pTail;       // 环形缓冲区尾地址
    unsigned int used_space;  //环形缓冲区有效数据个数
    unsigned int free_space; //环形缓冲区剩余空间
    int overwrite;// 1- overwrite
} ringfifo;

void InitRingBuff(ringfifo *buf, unsigned int size,int over_mode);
int WriteRingBuff(ringfifo *buf,char *pdata, unsigned int len);
int ReadRingBuff(ringfifo *buf, char *pdata, unsigned int len);

#endif

main.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "ringbuf.h"

int main()
{
    char c;
    int len;
    int readLen = 1;
    char readBuffer[10];
    int i = 0;
    ringfifo buf1;
    int r;

	char* strbuff = (char*)malloc(100 * sizeof(char));
    buf1.overwrite = 1;
    InitRingBuff(&buf1,10,1);
    printf("Please enter a character,VER 0.4\n");

    while (1)
    {
        fgets(strbuff,100,stdin);
        printf("strlen is %d\n",strlen(strbuff)-1);
        if(strlen(strbuff)>1)
        {
            switch (*strbuff)
            {
            case 'R':
                r = ReadRingBuff(&buf1,readBuffer, readLen);
                if (r > 0)
                {
                    for (i = 0; i < readLen; i++)
                    {
                        printf("%c ", (char)readBuffer[i]);
                    }
                    printf("\n");
                    printf("pread is %d \t pwrite is %d \t used_space is %d free space is %d BUF:",buf1.pValidRead,buf1.pValidWrite,buf1.used_space,buf1.free_space);
                    for (i = 0; i < buf1.pTail - buf1.pHead; i++)
                    {
                        printf("%c ", (char)*(buf1.pHead+i));
                    }
                    printf("\n");
                }
                break;

            default:
                WriteRingBuff(&buf1,strbuff, strlen(strbuff)-1);
                printf("pread is %d \t pwrite is %d \t used_space is %d free space is %d BUF:",buf1.pValidRead,buf1.pValidWrite,buf1.used_space,buf1.free_space);
                for (i = 0; i < buf1.pTail - buf1.pHead; i++)
                    {
                        printf("%c ", (char)*(buf1.pHead+i));
                    }
                printf("\n");
                break;
            }
        }
    };


    return 0;
}

测试说明

程序运行后输入除了”R“以外的任意字符,按回车后写入buf,输入R时从buf读取1个字节,初始化buf时需设置覆盖/阻塞模式,测试结果如下:
在这里插入图片描述

工程代码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/532605.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VideoGPT:Video Generation using VQ-VAE and Transformers

1.introduction 对于视频展示&#xff0c;选择哪种模型比较好&#xff1f;基于似然->transformers自回归。在没有空间和时间溶于的降维潜在空间中进行自回归建模是否优于在所有空间和时间像素级别上的建模&#xff1f;选择前者&#xff1a;自然图像和视频包括了大量的空间和…

java程序生成exe文件启动时,在没有java环境计算机运行

1.idea项目配置工件 2. 开始构建java程序成jar包 3. 生成exe启动程序 注&#xff1a;下面的输入框中写错了&#xff0c;应该是.\jre才对 4. 在已经选择的生成exe存放文件夹找到已经生成exe启动程序

一文详解静态图和动态图中的自动求导机制

01 静态图与动态图的区别 之前在[1]中提到过&#xff0c;自动求导&#xff08;AutoDiff&#xff09;机制是当前深度学习模型训练采用的主要方法&#xff0c;而在静态图和动态图中对于自动求导的处理是不一样的。作为前置知识&#xff0c;这里简单进行介绍。 我们都知道静态图…

Vue.js------vue基础

1. 能够了解更新监测, key作用, 虚拟DOM, diff算法2. 能够掌握设置动态样式3. 能够掌握过滤器, 计算属性, 侦听器4. 能够完成品牌管理案例 一.Vue基础_更新监测和key 1.v-for更新监测 目标&#xff1a;目标结构变化, 触发v-for的更新 情况1: 数组翻转情况2: 数组截取情况3…

QT:信号与槽

作业&#xff1a; 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和…

Platforms Jumping(贪心,处理策略)

文章目录 题目描述输入格式输出格式样例输入1样例输出1样例输入2样例输出2样例输入3样例输出3提交链接提示 解析参考代码 题目描述 有一条宽度为 n n n 的河流。河的左岸是 0 0 0 单元格&#xff0c;右岸是 n 1 n1 n1 单元格(更正式地说&#xff0c;这条河可以表示为一串从…

MySQL基础练习题:习题2-3

这部分主要是为了帮助大家回忆回忆MySQL的基本语法&#xff0c;数据库来自于MySQL的官方简化版&#xff0c;题目也是网上非常流行的35题。这些基础习题基本可以涵盖面试中需要现场写SQL的问题。上期帮助大家建立数据库&#xff0c;导入数据&#xff0c;接下来让我们继续练习。 …

代码随想录35期Day08-字符串

344.反转字符串 位运算 func reverseString(s []byte) {l : 0r : len(s) - 1for l < r {s[l] ^ s[r]s[r] ^ s[l]s[l] ^ s[r]lr--} }541. 反转字符串II 没技巧 func reverseStringRange(s []byte, l int, r int) {if r > len(s) {r len(s) - 1}for l < r {s[l] ^…

c++的学习之路:22、多态(1)

摘要 本章主要是说一些多态的开头。 目录 摘要 一、多态的概念 二、多态的定义及实现 2.1、多态的构成条件 2.2、虚函数 2.3、虚函数的重写 2.4、C11 override 和 final 2.5、重载、覆盖(重写)、隐藏(重定义)的对比 三、思维导图 一、多态的概念 多态的概念&#…

Harmony鸿蒙南向驱动开发-Regulator

Regulator模块用于控制系统中各类设备的电压/电流供应。在嵌入式系统&#xff08;尤其是手机&#xff09;中&#xff0c;控制耗电量很重要&#xff0c;直接影响到电池的续航时间。所以&#xff0c;如果系统中某一个模块暂时不需要使用&#xff0c;就可以通过Regulator关闭其电源…

Vue3---基础2(component)

主要讲解 component 的创建 以及vue插件的安装 Vue.js Devtools 为谷歌浏览器的Vue插件&#xff0c;可以在调试工具内查看组件的数据等 下载 有两种下载方式 1. 谷歌应用商店 打开Chrome应用商店去下载&#xff0c;这个方法需要魔法 2. 极简插件 极简插件官网_Chrome插件下载_…

【图论】详解链式前向星存图法+遍历法

细说链式前向星存图法 首先要明白&#xff0c;链式前向星的原理是利用存边来进行模拟图。 推荐左神的视频–建图、链式前向星、拓扑排序 比方说有这样一张图&#xff0c;我们用链式前向星来进行模拟时&#xff0c;可以将每一条边都进行编号&#xff0c;其中&#xff0c;红色的…

SQL注入sqli_labs靶场第五、六题

第五题 根据报错信息&#xff0c;判断为单引号注入 没有发现回显点 方法&#xff1a;布尔盲注&#xff08;太耗时&#xff0c;不推荐使用&#xff09; 1&#xff09;猜解数据库名字&#xff1a;&#xff08;所有ASCII码值范围&#xff1a;0~127&#xff09; ?id1 and length…

数字化浪潮下,制造业如何乘势而上实现精益生产

随着数字化技术的迅猛发展&#xff0c;制造业正迎来前所未有的变革机遇。本文将探讨如何利用数字化手段助推制造业实现精益生产&#xff0c;从而在激烈的市场竞争中脱颖而出。 1、构建智能化生产系统 借助物联网技术&#xff0c;实现设备之间的互联互通&#xff0c;构建智能化…

【Qt踩坑】ARM 编译Qt5.14.2源码-QtWebEngine

1.下载源码 下载网站&#xff1a;Index of /new_archive/qt/5.14/5.14.2/single 2.QWebEngine相关依赖 sudo apt-get install flex libicu-dev libxslt-dev sudo apt-get install libssl-dev libxcursor-dev libxcomposite-dev libxdamage-dev libxrandr-dev sudo apt-get …

3. Spring 注解存储对象 Bean的命名规范

从Java5.0开始&#xff0c;Java开始支持注解。Spring做为Java生态中的领军框架&#xff0c;从2.5版本后也开始支持注解。相比起之前使用xml来配置Spring框架&#xff0c;使用注解提供了更多的控制Spring框架的方式。 SpringFramework版本对应jdk版本重要特性SpringFramework 1…

Linux——fork复制进程

1)shell: 在计算机科学中&#xff0c;Shell俗称壳&#xff08;用来区别于核&#xff09;&#xff0c;是指“为使用者提供操作界面”的软件&#xff08;command interpreter&#xff0c;命令解析器&#xff09;。它类似于DOS下的COMMAND.COM和后来的cmd.exe。它接收用户命令&…

练习题(2024/4/10)

1. 删除有序数组中的重复项 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元…

安装VMware ESXi虚拟机系统

简介&#xff1a;ESXi是VMware公司开发的一款服务器虚拟化操作系统。它能够在一台物理服务器上运行多个虚拟机&#xff0c;每个虚拟机都可以独立运行操作系统和应用程序&#xff0c;而且对硬件配置要求低&#xff0c;系统运行稳定。 准备工具&#xff1a; 1.8G或者8G以上容…

查看TensorFlow已训模型的结构和网络参数

文章目录 概要流程 概要 通过以下实例&#xff0c;你将学会如何查看神经网络结构并打印出训练参数。 流程 准备一个简易的二分类数据集&#xff0c;并编写一个单层的神经网络 train_data np.array([[1, 2, 3, 4, 5], [7, 7, 2, 4, 10], [1, 9, 3, 6, 5], [6, 7, 8, 9, 10]]…