【STM32 CubeMX】学STM必会的数据结构——环形缓冲区

文章目录

  • 前言
  • 一、环形缓冲区是什么
  • 二、实现环形缓冲区
    • 实现分析
    • 2.1 环形缓冲区初始化
    • 2.2 写buf
    • 2.3 读buf
    • 2.4 测试
  • 三、代码总况
  • 总结


前言

在嵌入式系统开发中,经常需要处理数据的缓存和传输,而环形缓冲区是一种常见且有效的数据结构,特别适用于处理实时数据流或者在有限的内存资源下高效地管理数据。在STM32微控制器的开发中,使用CubeMX工具可以方便地配置和生成环形缓冲区的代码,从而加速开发过程并提高代码的可维护性。本文将介绍STM32 CubeMX中环形缓冲区的使用方法以及其在嵌入式系统开发中的重要性。


一、环形缓冲区是什么

当我们处理数据时,有时候需要一个地方来临时存储它们,就好像我们用盘子装菜一样。但是,内存有限,如果盘子装满了就得从头开始放菜,这样效率不高。环形缓冲区就像是一个环形的菜盘,当盘子满了,就会从一端开始取走菜,同时从另一端继续放新的菜,这样就能不停地装菜,而且效率很高。

现在,让我们画一个简单的图来演示一下:

[ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ]^                           ^|                           |
取走                        放入

在这里插入图片描述

这里,我们有一个有8个位置的环形缓冲区,用方括号表示每个位置。现在,我们从左边取走了一个数据,然后从右边放入了一个新的数据。这样,缓冲区就像一个环,数据可以不停地在其中循环。

这种数据结构适合一方读buf,一方写buf的情节

二、实现环形缓冲区

实现分析

我们需要定义存储区buf

char buf[100];

我们还需要定义读位置为0,写位置为0
后面我们通过这两个变量来操作读和写

int r,w = 0;

那么怎么写入数据和读数据呢?
读:
首先肯定要有数据我们才能读吧,那么怎么判断有没有数据呢?
当我们的r = w时,他是空的,如果是空,我们肯定不能读,如果是有数据,直接返回对应下标即可

写:
首先我们要知道,如果buf满了,肯定是不能把原来的数据给干掉的,那么我们怎么判断他有没有满呢,如果直接使用r = w来判断,那就和判断空是一样的了,我们可以使用w+1 = r来判断,因为如果没满,我写一个进去,他肯定不等于r,如果满了我写一个进去他等于r就是满了,我们使用w+1来模拟写入后的w状态即可

如果读和写超过了这个buf的原始大小,因为他是环形缓冲区,所以需要把下标取余个buf的size

2.1 环形缓冲区初始化

首先声明一个结构体,这个结构体存储着缓冲区buf,读r和写w

typedef struct
{int *buf;int len;int r;int w;
}CircleBuf,*p_CircleBuf;

接下来声明一个函数进行init操作

void CircleBufInit(p_CircleBuf pbuf,int* buf ,int len)
{pbuf->r = pbuf->w = 0;pbuf->buf = buf;pbuf->len = len;
}

对于这个函数,你可以从外部传入buf进行缓冲区的初始化,也可以使用malloc进行内存的分配初始化

2.2 写buf

我们需要实现下面这个函数来进行写buf

void CircleBufWrite(p_CircleBuf pCircleBuf, int val);

首先我们需要先定义一个变量存储w的下一个下标,并且如果下一个下标超出len,需要变成0,实现环形

int nextW = pCircleBuf->w + 1;
nextW %= pCircleBuf->len;

接下来,我们需要去判断nextW是否等于r,如果不等于,代码没有满

if (pCircleBuf->r != nextW)

如果没有满,我们需要把对应的w下标赋值成val
然后w下标++,再对w进行取余len,如果下标超出len,需要变成0,实现环形

pCircleBuf->buf[pCircleBuf->w] = val;
pCircleBuf->w++;
pCircleBuf->w %= pCircleBuf->len;

2.3 读buf

我们需要实现下面这个函数来进行读buf

void CircleBufRead(p_CircleBuf pCircleBuf, int* val);

首先我们先要判断r !=w才能进行读操作

if (pCircleBuf->r != pCircleBuf->w)

如果不等于
我们可以把r对应的下标给val
然后r读下标++
因为可能存在读完的情况所以我们需要进行取余操作

*val = pCircleBuf->buf[pCircleBuf->r];
pCircleBuf->r++;
pCircleBuf->r %= pCircleBuf->len;

如果等于,我们可以把val的值变成NULL

else
{val = NULL;
}

2.4 测试

我们可以先写入一部分数据,然后,我们可以使用CircleBufRead读出来,读出来之后立马进行写,我们可以通过下面这种方法进行缓冲区的测试:

CircleBuf cBuf;
int buf[100] = { 0 };
CircleBufInit(&cBuf,&buf,100);for (int i = 0; i < 100; i++)
{CircleBufWrite(&cBuf, i);
}int i = 100;
while (1)
{int temp = -1;CircleBufRead(&cBuf, &temp);printf("%d ", temp);CircleBufWrite(&cBuf, i);i++;Sleep(10);
}

三、代码总况

//Circle.c
#include "circleBuf.h"
#include <memory.h>void CircleBufInit(p_CircleBuf pbuf,int* buf ,int len)
{pbuf->r = pbuf->w = 0;pbuf->buf = buf;pbuf->len = len;
}void CircleBufRead(p_CircleBuf pCircleBuf, int* val)
{if (pCircleBuf->r != pCircleBuf->w){*val = pCircleBuf->buf[pCircleBuf->r];pCircleBuf->r++;pCircleBuf->r %= pCircleBuf->len;}else{val = NULL;}
}void CircleBufWrite(p_CircleBuf pCircleBuf, int val)
{int nextW = pCircleBuf->w + 1;nextW %= pCircleBuf->len;if (pCircleBuf->r != nextW){pCircleBuf->buf[pCircleBuf->w] = val;pCircleBuf->w++;pCircleBuf->w %= pCircleBuf->len;}
}
//Circle.h
#pragma oncetypedef struct
{int *buf;int len;int r;int w;
}CircleBuf,*p_CircleBuf;void CircleBufInit(p_CircleBuf pbuf, int*buf ,int len);void CircleBufRead(p_CircleBuf pCircleBuf, int* val);void CircleBufWrite(p_CircleBuf pCircleBuf, int val);
//main.c
#include <stdio.h>
#include <stdlib.h>
#include "circleBuf.h"
#include <Windows.h>int main()
{CircleBuf cBuf;int buf[100] = { 0 };CircleBufInit(&cBuf,&buf,100);for (int i = 0; i < 100; i++){CircleBufWrite(&cBuf, i);}int i = 100;while (1){int temp = -1;CircleBufRead(&cBuf, &temp);printf("%d ", temp);CircleBufWrite(&cBuf, i);i++;Sleep(10);}system("pause>0");return 0;
}

总结

环形缓冲区是嵌入式系统开发中常用的数据结构之一,具有高效、可靠的特性。通过STM32 CubeMX工具,我们可以轻松地配置和生成环形缓冲区的代码,从而简化开发流程并提高代码的可维护性。掌握环形缓冲区的原理和使用方法,对于STM32微控制器的开发者来说是必不可少的技能。希望本文能够帮助读者更好地理解和应用环形缓冲区,从而更加高效地开发嵌入式系统。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

幻兽帕鲁官方更新了,服务器端怎么更新?

幻兽帕鲁官方客户端更新了&#xff0c;那么它的服务器端版本也是需要更新的&#xff0c;不然版本不一致的话&#xff0c;就不能进入游戏了。 具体的更新方法有两种&#xff0c;一是手动输入命令进行更新。第二种是在面板一键更新。 无论你是在阿里云或者腾讯云购买的一键部署…

Pycharm里如何设置多Python文件并行运行

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 夕阳何事近黄昏&#xff0c;不道人间犹有未招魂。 大家好&#xff0c;我是皮皮。 一、前言 相信使用Pycharm的粉丝们肯定有和我一样的想法&#xff0c;…

算法学习——LeetCode力扣贪心篇1

算法学习——LeetCode力扣贪心篇1 455. 分发饼干 455. 分发饼干 - 力扣&#xff08;LeetCode&#xff09; 描述 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[…

Vulnhub靶机:DC3

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.15&#xff09; 靶机&#xff1a;DC3&#xff08;10.0.2.56&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://www.vulnhub.com/entry/dc-32,312…

嵌入式系统的基础知识:了解嵌入式系统的构成和工作原理

&#xff08;本文为简单介绍&#xff0c;个人观点仅供参考&#xff09; 嵌入式系统是建立在微处理器基础上的计算机系统,用于对专门的功能进行控制、运算和接口。它结合了硬件和软件,可以提供实时的响应,广泛应用于工业控制、通信、医疗、交通等领域。 嵌入式系统的核心是微处理…

猫头虎分享已解决Bug || 代码部署失败(Code Deployment Failure):DeploymentError, FailedRelease

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

PMDG 737

在Simbrief中生成计划后下载两个文件 放到A:\Xbox\Community\pmdg-aircraft-738\Config\Flightplans中

SpringCloud第一天

1.认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢&#xff1f; 1.1.单体架构 单体架构&#xff1a;将业务的所有功能集中在一个项目中开发&#xff0c;打…

波奇学Linux:文件系统

磁盘认识 磁盘被访问的基本单元是扇区-512字节。 磁盘可以看成多个同心圆&#xff0c;每个同心圆叫做磁道&#xff0c;多个扇区组成同心圆。 我们可以把磁盘看做由无数个扇区构成的存储介质。 要把数据存到磁盘&#xff0c;先定位扇区&#xff0c;用哪一个磁头&#xff0c;…

【原创 附源码】Flutter集成Apple支付详细流程(附源码)

最近有时间&#xff0c;特意整理了一下之前使用过的Flutter平台的海外支付&#xff0c;附源码及demo可供参考 这篇文章只记录Apple支付的详细流程&#xff0c;其他相关Flutter文章链接如下&#xff1a; 【原创 附源码】Flutter集成谷歌支付详细流程(附源码) 【原创 附源码】F…

《Java 简易速速上手小册》第2章:面向对象的 Java(2024 最新版)

文章目录 2.1 类和对象 - 构建你的小宇宙2.1.1 基础知识2.1.2 重点案例&#xff1a;设计一个简单的图书类2.1.3 拓展案例 1&#xff1a;学生管理系统2.1.4 拓展案例 2&#xff1a;账户管理系统 2.2 继承与多态 - 让一切变得更有趣2.2.1 基础知识2.2.2 重点案例&#xff1a;动物…

【51单片机】蜂鸣器(江科大)

11.1蜂鸣器 1.蜂鸣器介绍 蜂鸣器是一种将电信号转换为声音信号的器件,常用来产生设备的按键音、报警音等提示信号 蜂鸣器按驱动方式可分为有源蜂鸣器和无源蜂鸣器 有源蜂鸣器:内部自带振荡源,将正负极接上直流电压即可持续发声,频率固定 无源蜂鸣器:内部不带振荡源,需…

C语言strlen和sizeof的区别

strlen和sizeof没有联系 前者是库函数&#xff0c;统计长度的标志是是否有\0 后者是操作符。计算长度的标志是字节数量。

Linux_线程

线程与进程 多级页表 线程控制 线程互斥 线程同步 生产者消费者模型 常见概念 下面选取32位系统举例。 一.线程与进程 上图是曾经我们认为进程所占用的资源的集合。 1.1 线程概念 线程是一个执行分支&#xff0c;执行粒度比进程细&#xff0c;调度成本比进程低线程是cpu…

本地部署 Stable Cascade

本地部署 Stable Cascade 0. 引言1. 事前准备2. 本地部署 Stable Cascade3. 使用 Stable Cascade 生成图片4. Stable Cascade Github 地址 0. 引言 Stable Cascade 模型建立在 Wrstchen 架构之上&#xff0c;它与 Stable Diffusion 等其他模型的主要区别在于它的工作潜在空间要…

软考27-上午题-查找

一、基本概念 1-1、查找表&#xff1a; 同一类型的数据元素构成的集合。 对查找表常用的操作&#xff1a; 从查找表中查询某个特定的元素&#xff1b;检索某个特定的元素的各种属性。 通常只进行这两种操作的查找表&#xff1a;静态查找表 1-1-2、静态查找表&#xff1a; 顺…

B2科目二考试项目笔记

B2科目二考试项目笔记 1 桩考1.1 右起点倒库1.2 移库&#xff08;左→右&#xff09;1.3 驶向左起点1.4 左起点倒库1.5 驶向右起点 2 侧方停车考试阶段&#xff08;从路边开始&#xff09;&#xff1a; 3 直角转弯4 坡道定点停车和起步5 单边桥6 通过限速限宽门7 曲线行驶8 连续…

[OPEN SQL] 删除数据

DELETE语句用于删除数据库表中的数据 本次操作使用的数据库表为SCUSTOM&#xff0c;其字段内容如下所示 航班用户(SCUSTOM) 需要删除以下数据 1.删除单条数据 语法格式 DELETE <dbtab> FROM <wa>. DELETE <dbtab> FROM TABLE <itab>. DELETE FROM &…

Linux makefile 大型多文件的处理

最简单的例子是 main.cpp test.cpp test.h 首先将这三个写好 然后的话 test.cpp 上面输出 helloworld 首先我们在同一个目录下创建一个makefile 文件 然后用vim 编辑它 如下图&#xff08;使用的c&#xff09; mybin 是我们的可执行程序 gcc是编译的命令 gcc 前面必…

人形机器人专题:准直驱执行器深度:人形机器人执行器技术的前沿

今天分享的是人形机器人系列深度研究报告&#xff1a;《人形机器人专题&#xff1a;准直驱执行器深度&#xff1a;人形机器人执行器技术的前沿》。 &#xff08;报告出品方&#xff1a;招商证券&#xff09; 报告共计&#xff1a;34页 准直驱执行器具备独特优势 刚性执行器…