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

news2024/11/25 12:28:01

文章目录

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

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

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

相关文章

Zustand:简化状态管理的现代React状态库

Zustand&#xff1a;简化状态管理的现代React状态库 Zustand是一个用于管理状态的现代React状态库。它提供了简洁、可扩展和高效的状态管理解决方案&#xff0c;使得在React应用中处理复杂的状态逻辑变得更加容易和直观。本文将介绍Zustand的主要特点、使用方法以及它在React开…

【初学者向导】轻松加入OnlyFans世界:一站式订阅与支付指南!掌握使用虚拟卡的订阅技巧

目录 1. 引言2. 注册OnlyFans账户3. 浏览OnlyFans内容4. 选择订阅时长5. 开通虚拟卡 5.1. 什么是虚拟信用卡5.2. 如何开通虚拟卡 6. 使用虚拟卡订阅7. 总结8. 常见问题 1. 引言 什么是OnlyFans&#xff1a;OnlyFans是一种内容订阅服务&#xff0c;成立于2016年&#xff0c;允…

【深度学习每日小知识】交并集 (IoU)

交并集 (IOU) 是一种性能指标&#xff0c;用于评估注释、分割和对象检测算法的准确性。它量化数据集中的预测边界框或分段区域与地面实况边界框或注释区域之间的重叠。 IOU 提供了预测对象与实际对象注释的对齐程度的衡量标准&#xff0c;从而可以评估模型准确性并微调算法以改…

SNMP 简单网络管理协议、网络管理

目录 1 网络管理 1.1 网络管理的五大功能 1.2 网络管理的一般模型 1.3 网络管理模型中的主要构件 1.4 被管对象 (Managed Object) 1.5 代理 (agent) 1.6 网络管理协议 1.6.1 简单网络管理协议 SNMP 1.6.2 SNMP 的指导思想 1.6.3 SNMP 的管理站和委托代理 1.6.4 SNMP…

Spring 用法学习总结(一)之基于 XML 注入属性

百度网盘&#xff1a; &#x1f449; Spring学习书籍链接 Spring学习 1 Spring框架概述2 Spring容器3 基于XML方式创建对象4 基于XML方式注入属性4.1 通过set方法注入属性4.2 通过构造器注入属性4.3 使用p命名空间注入属性4.4 注入bean与自动装配4.5 注入集合4.6 注入外部属性…

如何利用SpringSecurity进行认证与授权

目录 一、SpringSecurity简介 1.1 入门Demo 二、认证 ​编辑 2.1 SpringSecurity完整流程 2.2 认证流程详解 2.3 自定义认证实现 2.3.1 数据库校验用户 2.3.2 密码加密存储 2.3.3 登录接口实现 2.3.4 认证过滤器 2.3.5 退出登录 三、授权 3.1 权限系统作用 3.2 授…

报警产生器

1&#xff0e;  实验任务 用P1.0输出1KHz和500Hz的音频信号驱动扬声器&#xff0c;作报警信号&#xff0c;要求1KHz信号响100ms&#xff0c;500Hz信号响200ms,交替进行&#xff0c;P1.7接一开关进行控制&#xff0c;当开关合上响报警信号&#xff0c;当开关断开告警信号停止&…

前沿技术期刊追踪——以电机控制为例

一、背景 前沿技术期刊追踪是指科研人员、学者或专业人士通过关注和阅读各类顶级科技期刊&#xff0c;了解并跟踪相关领域的最新研究成果和发展动态。以下是一些常见的前沿技术期刊以及追踪方法&#xff1a; 1. **知名科技期刊**&#xff1a; - 自然&#xff08;Nature&#…

Atcoder ABC339 D - Synchronized Players

Synchronized Players&#xff08;同步的球员&#xff09; 时间限制&#xff1a;4s 内存限制&#xff1a;1024MB 【原题地址】 所有图片源自Atcoder&#xff0c;题目译文源自脚本Atcoder Better! 点击此处跳转至原题 【问题描述】 【输入格式】 【输出格式】 【样例1】 【…

IDEA 28 个天花板技巧

IDEA 作为Java开发工具的后起之秀&#xff0c;几乎以碾压之势把其他对手甩在了身后&#xff0c;主要原因还是归功于&#xff1a;好用&#xff1b;虽然有点重&#xff0c;但依旧瑕不掩瑜&#xff0c;内置了非常多的功能&#xff0c;大大提高了日常的开发效率&#xff0c;下面汇总…

书生浦语大模型实战营-课程笔记(2)

介绍了一下InternLm的总体情况。 InternLm是训练框架&#xff0c;Lagent是智能体框架。 这个预训练需要这么多算力&#xff0c;大模型确实花钱。 Lagent是智能体框架&#xff0c;相当于LLM的应用。 pip设置 开发机的配置 pip install transformers4.33.1 timm0.4.12 sente…

二次元自适应动态引导页

源码介绍 二次元自适应动态引导页&#xff0c;HTMLJSCSS&#xff0c;记事本修改&#xff0c;上传到服务器即可&#xff0c;也可以本地双击index.html查看效果 下载地址 https://wfr.lanzout.com/isRem1o7bfcb

山脉的个数/攀登者

题目描述 攀登者喜欢寻找各种地图&#xff0c;并且尝试攀登到最高的山峰。 地图表示为一维数组&#xff0c;数组的索引代表水平位置&#xff0c;数组的元素代表相对海拔高度。其中数组元素0代表地面。 例如&#xff1a;[0,1,2,4,3,1,0,0,1,2,3,1,2,1,0]&#xff0c;代表如下…

Vue 全组件 局部组件

一、组件定义和使用 1、全局组件 定义 <template> <div> <h1>This is a global component</h1> </div> </template> <script lang"ts"> </script> <style></style> 导入 全局组件在main.ts&#xff…

CVE-2023-41892 漏洞复现

CVE-2023-41892 开题&#xff0c;是一个RCE Thanks for installing Craft CMS! You’re looking at the index.twig template file located in your templates/ folder. Once you’re ready to start building out your site’s front end, you can replace this with someth…

猫头虎分享已解决Bug || ValueError: Unknown label type: ‘continuous‘

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

ESP32学习(2)——点亮LED灯

1.前期准备 开发板原理图如下&#xff1a; 可见LED灯接在了GPIO2口 那么要如何编写代码控制GPIO口的电平高低呢&#xff1f; 我们可以参考micropython的官方文档Quick reference for the ESP32 — MicroPython latest documentation 可见&#xff0c;需要导入machine包 若要…

二叉树的层序遍历II

1.题目 这道题是2024-2-15的签到题&#xff0c;题目难度为中等。 考察的知识点为BFS算法&#xff08;树的层序遍历&#xff09; 题目链接&#xff1a;二叉树的层序遍历II 给你二叉树的根节点 root &#xff0c;返回其节点值 自底向上的层序遍历 。 &#xff08;即按从叶子节…

【数据结构】二叉树的三种遍历

目录 一、数据结构 二、二叉树 三、如何遍历二叉树 一、数据结构 数据结构是计算机科学中用于组织和存储数据的方式。它定义了数据元素之间的关系以及对数据元素的操作。常见的数据结构包括数组、链表、栈、队列、树、图等。 数组是一种线性数据结构&#xff0c;它使用连续…

基于 InternLM 和 LangChain 搭建你的知识库(三)

基于 InternLM 和 LangChain 搭建你的知识库 大模型开发范式 Finetune 在大型语言模型中&#xff0c;Finetune&#xff08;微调&#xff09;是一种技术&#xff0c;用于调整预训练的模型以提高其在特定任务或数据集上的表现。这种方法通常涉及以下步骤&#xff1a; 预训练模…