【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 once

typedef 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微控制器的开发者来说是必不可少的技能。希望本文能够帮助读者更好地理解和应用环形缓冲区,从而更加高效地开发嵌入式系统。

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

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

相关文章

提前部署游戏业务防护,为何如此重要?

现在做网络游戏的企业都知道服务器的安全对于我们来说很重要&#xff01;互联网上面的DDoS攻击和CC攻击等等无处不在&#xff0c;而游戏服务器对服务器的防御能力和处理能力要求更高&#xff0c;普通的服务器则是比较注重各方面能力的均衡。 随着游戏行业的壮大&#xff0c;网络…

java 宠物在线商城系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目

一、源码特点 java 宠物在线商城系统是一套完善的java web信息管理系统 servletdaobean mvc模式&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S 模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&…

尚硅谷最新Node.js 学习笔记(三)

目录 六、Node.js 模块化 6.1、介绍 什么是模块化与模块&#xff1f; 什么是模块化项目&#xff1f; 模块化好处 6.2、模块暴露数据 模块初体验 暴露数据 6.3、导入&#xff08;引入&#xff09;模块 6.4、导入模块的基本流程 6.5、CommonJS规范 七、包管理工具 7…

站在C/C++的肩膀速通Java面向对象

默认学过C或C&#xff0c;对变量、表达式、选择、循环都会。 运行特征 解释型语言&#xff08;JavaScript、Python等&#xff09; 源文件-(平台专属解释器)->解释器中执行编译型语言&#xff08;C、Go等&#xff09; 源文件-(平台编译器)->平台可执行文件Java 源文件-(…

算法详解:滑动窗口-- 最大连续1的个数 III

题目来源:力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 本期讲解滑动窗口经典例题,我会从三个点开始讲解题目1.题目解析2.算法原理 3.编写代码 1.题目解析 这道题目理解起来还是比较简单的,我们简单分析一下,也就是给定一个数组,数组是由1和0组成…

AtCoder Beginner Contest 335 (Sponsored by Mynavi) --- F - Hop Sugoroku -- 题解

目录 F - Hop Sugoroku 题目大意&#xff1a; 思路解析&#xff1a; 代码实现&#xff1a; F - Hop Sugoroku 题目大意&#xff1a; 思路解析&#xff1a; 容易想到这是一个dp题&#xff0c;然后初始转移方程为&#xff1a; 如果当a[i] 较大时&#xff0c;时间复杂度为 O(N…

【AI视野·今日NLP 自然语言处理论文速览 第七十九期】Thu, 18 Jan 2024

AI视野今日CS.NLP 自然语言处理论文速览 Thu, 18 Jan 2024 Totally 35 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Deciphering Textual Authenticity: A Generalized Strategy through the Lens of Large Language Semantics …

MySQL数据库-MVCC多版本并发控制

mvcc,多版本并发控制&#xff08;Multi-Version Concurrency Control&#xff09;,是一种用于数据库管理系统中的并发控制方法. 在传统的并发控制方法中,如锁定机制,当一个事务修改数据时,会对相关的数据对象进行锁定,其他事务需要等待该锁释放才能进行操作。这种方法存在着事…

操作系统-408

一、操作系统概述 1、定义 负责协调软件和硬件的计算机资源的工作为上层应用提供简易的服务操作系统是系统软件 2、功能&#xff1a; 操作系统是系统资源的管理者 处理机管理存储器管理文件管理设备管理向上层提供方便易用的服务 命令接口程序接口对硬件机器的扩展 3、特征…

详解tomcat中的jmx监控

目录 1.概述 2.如何开启tomcat的JMX 3.tomcat如何实现JMX的源码分析 1.概述 本文是博主JAVA监控技术系列文章的第二篇&#xff0c;前面一篇文章中我们介绍了JAVA监控技术的基石——jmx&#xff1a; 【JMX】JAVA监控的基石-CSDN博客 本文我们将从使用和源码实现两个方面聊…

springboot743二手交易平台

springboot743二手交易平台 获取源码——》公主号&#xff1a;计算机专业毕设大全

Python面向对象学习小记——面向过程VS面向对象

【面向过程就好比你是一个工人&#xff0c;你得亲自去做一个个任务 面向对象就好比你一个包工头&#xff0c;你可以差遣你下面的工人去做】

日期类运算符重载以及const成员详细解析

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 算法 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂 目录 一.前言 二.运算符重载 2.1概念 2.2比较的符号重载 2.2.1…

linux 安装docker

目录 环境 操作步骤 1 下载脚本 2 执行脚本 3 检查docker版本&#xff0c;证明安装成功 环境 阿里云 ubuntu 22.04 64位 操作步骤 参考linux系统安装docker-腾讯云开发者社区-腾讯云 (tencent.com) 1 下载脚本 curl -fsSL https://get.docker.com -o get-docker.sh …

JavaWeb学习|Filter与ThreadLocal

学习材料声明 所有知识点都来自互联网&#xff0c;进行总结和梳理&#xff0c;侵权必删。 引用来源&#xff1a;尚硅谷最新版JavaWeb全套教程,java web零基础入门完整版 Filter 1、Filter 过滤器它是 JavaWeb 的三大组件之一。三大组件分别是&#xff1a;Servlet 程序、Liste…

RH850从0搭建Autosar开发环境【2X】- Davinci Configurator之XCP模块配置详解(上)

XCP模块配置详解 - 上 一、XCP模块配置项处理1.1 Tx Pdu配置项二、XCP模块其他配置项2.1 参数XcpMainFunctionPeriod2.2 参数XcpOnCanEnabled2.3 容器XcpOnCan总结从本节开始先专注与配置项错误处理以及构建Autosar Rh850的最小系统搭建。 XCP模块在汽车电子各控制器中处于十分…

使用ShardingJDBC实现分库分表

一、测试环境 JDK&#xff1a;1.8SpringBoot&#xff1a;2.7.17MySQL驱动&#xff1a;5.1.49MyBatis&#xff1a;2.3.1shardingJDBC&#xff1a;5.1.0 二、核心依赖 <!-- mysql 驱动 --> <dependency><groupId>mysql</groupId><artifactId>mysq…

Django学习笔记教程全解析:初步学习Django模型,初识API,以及Django的后台管理系统(Django全解析,保姆级教程)

把时间用在思考上是最能节省时间的事情。——[美]卡曾斯 导言 写在前面 本文部分内容引用的是Django官方文档&#xff0c;对官方文档进行了解读和理解&#xff0c;对官方文档的部分注释内容进行了翻译&#xff0c;以方便大家的阅读和理解。 概述 在上一篇文章里&#xff0…

【Python】高级数据类型

&#x1f6a9; WRITE IN FRONT &#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四" &#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…

8.JS中的== 操作符的强制类型转换规则

对于 来说&#xff0c;如果对比双方的类型不一样&#xff0c;就会进行类型转换。假如对比 x 和 y 是否相同&#xff0c;就会进行如下判断流程&#xff1a; 首先会判断两者类型是否相同&#xff0c;类型相同的话就比较两者的大小&#xff1b;类型不相同的话&#xff0c;就会进…