串口环形缓冲区

news2024/11/22 10:10:23

文章目录

  • 一、串口环形缓冲区概念
  • 二、STC12例程
    • (1)环形串口缓冲区结构体
    • (2)串口环形缓冲区存和取数据
    • (3)完整工程demo

一、串口环形缓冲区概念

串口环形缓冲区应用于嵌入式、物联网开发中处理接收串口数据量过大的问题。串口环形缓冲简单理解就是建立一个数组,将串口的数据存到数组里缓存,待空闲时处理。而缓存区越大,那么可以缓存的数据就越多。
请添加图片描述
环形串口缓冲区建立的数组还要再定义一个头和一个尾。这时有三种情况:
1、当头等于尾时,我们便知道此时环形串口缓冲区无数据,此时不进行读操作。
2、有数据来时,数组存储数据,并且头按数据的长度向前移动,空闲时尾开始取数据,直到尾等于头为止。
3、当头存到数组长度的最后一位时,返回数组第一位开始存数据。

因为头开始存数据到最后一位时,便有返回数组第一位开始存数据,此时我们就可以想象这个数据是一个类似甜甜圈的环形,这便是串口环形缓冲区。

二、STC12例程

要想写串口环形缓冲区,首先需要初始化串口和接收中断处理,保证串口收发正常,初始化串口部分默认大家都懂了,直接略过,我自己编写的例程使用STC12,因为STC12单片机是51单片机的升级版本,几乎学过51单片机的都能看得懂,比较简单,现在企业的开发标配是STM32了,这时只需移植过去即可。我提供两种MCU的串口初始化供大家参考:
STM32F1x固件库函数学习笔记(一)
STC12C5A60S2串口通信(使用独立波特率发生器)

(1)环形串口缓冲区结构体

串口初始化好后,建立一个环形缓冲区结构体

//环形缓冲区结构体
typedef struct
{
	uint8_t head_count;					//头计数
	uint8_t tail_count;					//尾计数
	uint8_t buf[UART_RX_MAX];		//缓冲区数组
}UART_S;

下一步,我们便可以定义结构体变量初始化结构体

UART_S uart;//定义串口缓冲区结构体变量

//串口环形缓冲区初始化
void uart_Buffer_Init(void)
{
	int i;
	uart.head_count = 0;
	uart.tail_count = 0;
	for(i=0; i<UART_RX_MAX; i++)
	{
		uart.buf[i] = 0x00;
	}
}

(2)串口环形缓冲区存和取数据

下面就是串口环形缓冲代码里比较关键的部分,分别写一个放数据和取数据的函数。
放数据的函数逻辑是有数据来时,将数据存入串口环形缓冲区,当存到数组的最后一位时,返回从第一位存起。
取数据的逻辑是先进行一个判断,当判断缓冲区的头和尾不一样时,这时认为缓冲区有数据,我们便开始从缓冲环形缓冲区里取数据,当取到数组最后一位时,返回数组第一位,从第一位开始取数据。

//往缓冲器里放数据
void uart_buf_put(uchar ch)
{
	uart.buf[uart.head_count++] = ch;
	if(uart.head_count == UART_RX_MAX)
	{
		uart.head_count = 0;
	}
}

//判断缓冲区是否有数据
int fifo_is_empty(void)
{
	if(uart.head_count != uart.tail_count)//判断如果头不等于尾
	{
		return 0;//有数据
	}
	else return 1;//无数据
}

//从缓冲区取数据
int uart_buf_get(uchar *ch)
{
	if(fifo_is_empty() == 0)//如果有数据
	{
		*ch = uart.buf[uart.tail_count++];//取数据
		if(uart.tail_count == UART_RX_MAX)
		{
			uart.tail_count = 0;
		}	
		return 1;//返回成功
	}
	else return 0;//返回失败
}

下一步我们再写一个读数据的函数,一个简单的串口环形缓冲区就写完了,我们使用的时候只需把存数据放到中断里,然后在主函数里取数据就行了。

//读数据
void debug_read(void)
{
	uchar ch;
	/*如果有数据就一直取,直到取完为至*/
	while(!fifo_is_empty())
	{
		if(uart_buf_get(&ch))
		{
			putchar(ch);
		}
	}
}

void main()
{
	UartInit();//初始化串口
	uart_Buffer_Init();//初始化串口环形缓冲区
	while(1)
	{
		debug_read();
	}
}

//串口中断处理函数
void uart_Interrupt() interrupt 4
{
	unsigned char UartData;//单字节串口数据
	if(RI)
	{
		RI = 0;
		UartData = SBUF;
		uart_buf_put(UartData);//往串口缓冲区存数据
	}
}

(3)完整工程demo

#include <STC12C5A60S2.h>

//宏定义
#define uchar unsigned char
#define uint unsigned int

#define UART_RX_MAX 255		//数组最大值

//环形缓冲区结构体
typedef struct
{
	uchar head_count;					//头计数
	uchar tail_count;					//尾计数
	uchar buf[UART_RX_MAX];		//缓冲区数组
}UART_S;

UART_S uart;//定义串口缓冲区结构体变量

//串口初始化,晶振11.0592,波特率9600
void UartInit(void)		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x04;		//独立波特率发生器时钟为Fosc,即1T
	BRT = 0xDC;		//设定独立波特率发生器重装值
	AUXR |= 0x01;		//串口1选择独立波特率发生器为波特率发生器
	AUXR |= 0x10;		//启动独立波特率发生器
	
	EA = 1;//开总中断
	ES = 1;//开串口中断
}

//向串口发送一个字符
void putchar(char ch)
{
	SBUF = ch;
	while(!TI);TI = 0;
}

//向串口发送一段字符串
//void prints(char *s)
//{
//	while(*s != '\0')//发送字符串,直到遇到0才结束
//	{
//		SBUF = *s++;
//		while(!TI);
//		TI = 0;
//	}
//}

//串口环形缓冲区初始化
void uart_Buffer_Init(void)
{
	int i;
	uart.head_count = 0;
	uart.tail_count = 0;
	for(i=0; i<UART_RX_MAX; i++)
	{
		uart.buf[i] = 0x00;
	}
}

//往缓冲器里放数据
void uart_buf_put(uchar ch)
{
	uart.buf[uart.head_count++] = ch;
	if(uart.head_count == UART_RX_MAX)
	{
		uart.head_count = 0;
	}
}

//判断缓冲区是否有数据
int fifo_is_empty(void)
{
	if(uart.head_count != uart.tail_count)//判断如果头不等于尾
	{
		return 0;//有数据
	}
	else return 1;//无数据
}

//从缓冲区取数据
int uart_buf_get(uchar *ch)
{
	if(fifo_is_empty() == 0)//如果有数据
	{
		*ch = uart.buf[uart.tail_count++];//取数据
		if(uart.tail_count == UART_RX_MAX)
		{
			uart.tail_count = 0;
		}	
		return 1;//返回成功
	}
	else return 0;//返回失败
}

//读数据
void debug_read(void)
{
	uchar ch;
	/*如果有数据就一直取,直到取完为至*/
	while(!fifo_is_empty())
	{
		if(uart_buf_get(&ch))
		{
			putchar(ch);
		}
	}
}

void main()
{
	UartInit();//初始化串口
	uart_Buffer_Init();//初始化串口环形缓冲区
	while(1)
	{
		debug_read();
	}
}

//串口中断处理函数
void uart_Interrupt() interrupt 4
{
	unsigned char UartData;//单字节串口数据
	if(RI)
	{
		RI = 0;
		UartData = SBUF;
		uart_buf_put(UartData);//往串口缓冲区存数据
	}
}

在这里插入图片描述

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

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

相关文章

windows C++多线程同步<3>-互斥量

windows C多线程同步&#xff1c;3&#xff1e;-互斥量 概念&#xff0c;如下图&#xff1a; 另外就是互斥对象谁拥有&#xff0c;谁释放 那么一个线程允许多次获取互斥对象吗&#xff1f; 答案是允许&#xff0c;但是申请多次就要释放多次&#xff0c;否则其他线程获取不到互…

在线进销存-亿发移动进销存管理系统,助力批发零售企业线上线下同步经营

随着移动互联网的蓬勃发展&#xff0c;商品进销存管理日益变得复杂而关键&#xff0c;数字化转型已经成为批发零售企业增强竞争力的有效工具。移动进销存管理系统为批发零售企业提供一体化 解决方案&#xff0c;实现线上线下同步经营&#xff0c;帮助企业实现对商品的有效管理&…

TDengine Cloud 加入 AWS 合作伙伴网络,助力出海企业数字化转型

近日&#xff0c;全托管的时序数据云平台 TDengine Cloud 正式入驻 AWS Marketplace&#xff08;海外区&#xff09;&#xff0c;用户可通过 AWS Marketplace 轻松实现 TDengine Cloud 的订阅与部署&#xff0c;以最低的成本搭建最高效的数据处理架构。此外&#xff0c;早在 20…

python新手如何系统学习,走过这4个阶段成为高手

目录 python初级阶段学习 python中级阶段学习 python高级阶段学习 python进阶阶段学习 Python是一种简洁而强大的编程语言&#xff0c;广泛应用于软件开发、数据科学、人工智能等领域。很多新手如何系统学习python&#xff0c;今天我们从4个阶段来学习&#xff0c;就能成为高…

SpringBoot实现的旅游酒店管理系统源码附带视频运行教程

基于SpringBootMybatissThymeleaf框架系统主要有以下功能&#xff1a;分为前后台 前台用来展示数据&#xff0c;预定酒店、预定旅游、预定车票、购买保险等 后台&#xff1a;旅游路线管理、景点管理、酒店管理、车票管理、保险管理、攻略管理、留言管理、订单管理等后台管理员 …

关注这些问题,助你找到理想工作

导语&#xff1a;在寻找理想工作的过程中&#xff0c;有一些关键问题需要我们特别关注。了解并回答这些问题将有助于我们更好地定位自己&#xff0c;并找到符合自身需求和目标的职位。本文将介绍一些在找工作时需要关注的重要问题。 个人定位&#xff1a;首先&#xff0c;我们…

失去SSL证书,会对网站安全造成什么影响?

作为网络世界中的“身份证”&#xff0c;SSL证书可以在网络世界中证明你是一个真实可信的企业或个人网站&#xff0c;而不是一个钓鱼网站。且在网站的服务器上部署SSL证书后&#xff0c;可以使网站与访问者之间通过SSL协议建立安全的加密连接&#xff0c;确保在Web服务器和浏览…

H5编辑二维码,如何将图文、视频、文件、链接全都展示在一个页面?

在二维彩虹可以制作各种类型的二维码。今天我们要介绍的是二维彩虹的【H5编辑二维码】&#xff0c;包括基本功能、应用场景、制作步骤&#xff0c;以及其优势特点。现在就来随我们一次看看吧&#xff01; 一&#xff0c;认识H5编辑二维码 二维彩虹的【H5编辑】是一款功能非常…

【数据分享】1999—2021年地级市劳动力就业及工资情况(Shp/Excel格式)

在之前的文章中&#xff0c;我们分享过基于2000-2022年《中国城市统计年鉴》整理的1999-2021年地级市的人口相关数据、各类用地面积数据、污染物排放和环境治理相关数据、房地产投资情况和商品房销售面积、社会消费品零售总额和年末金融机构存贷款余额、地方一般公共预算收支状…

【Linux命令200例】cut强大的文本处理工具

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;本文已收录于专栏&#xff1a;Linux命令大全。 &#x1f3c6;本专栏我们会通过具体的系统的命令讲解加上鲜活的实操案例对各个命令进行深入…

关于Spring的bean的相关注解以及其简单使用方法

一、前置工作 第一步&#xff1a;创建一个maven项目 第二步&#xff1a;在resource中创建一个名字叫做spring-config.xml的文件&#xff0c;并把以下代码复制粘贴 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.sprin…

java+springboot+mysql员工宿舍管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的员工宿舍管理系统&#xff0c;系统包含超级管理员、管理员、员工角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;楼栋管理&#xff1b;宿舍管理&#xff1b;员工管理&#xff08;分配…

IntelliJ IDEA 2023.2 正式发布,彻底弃用Struts2,不再支持Win7

点击“终码一生”&#xff0c;关注&#xff0c;置顶公众号 每日技术干货&#xff0c;第一时间送达&#xff01; 1、主要更新 IntelliJ IDEA 2023.2已经到来&#xff01;此版本为IDE带来了大量令人兴奋的功能和有价值的改进。下面是本次的主要更新&#xff1a; IntelliJ IDEA 2…

【Java】智慧校园家校互通小程序源码

智慧校园家校互通小程序源码包含电子班牌系统考勤功能&#xff0c;以云服务器为基础&#xff0c;实现大数据和资源共享。是一款全功能智慧校园管理平台系统&#xff0c;融合了多媒体信息发布、家校互通、物联控制、教务管理、日常办公等一系列应用&#xff0c;是校园管理的现代…

如何在Linux系统上安装cpolar内网穿透

文章目录 如何在Linux系统上安装cpolar内网穿透 如何在Linux系统上安装cpolar内网穿透 cpolar作为一款体积小巧却功能强大的内网穿透软件&#xff0c;不仅能够在多种环境和应用场景中发挥巨大作用&#xff0c;还能适应多种操作系统&#xff0c;应用最为广泛的Windows、Mac OS系…

软件外包开发的流程图工具

软件开发过程中需要画流程图&#xff0c;可以更清楚的表达软件业务流程&#xff0c;减少在开发过程中的业务理解偏差&#xff0c;因此在软件开发过程中流程图工具是必不可少的软件管理工具。今天和大家分享常见的一些软件流程图工具&#xff0c;每款工具都有其自身的特色&#…

NAT网络地址转换(红茶三杯CCNA)

私有IPv4地址空间 10.0.0.0-10.255.255.255 172.16.0.0-172.31.255.255 192.168.0.0-192.168.255.255 问题&#x1f4a1;&#xff1f; 问问题NAT实验

el-table数据处理

在写表格时遇到&#xff0c;后端返回的数据是对象&#xff0c;并且缺少字段 1.每一条数据加上 一个字段 2.将对象转成数组 以下是数据 {"groupA": {"groupName": null,"orgName": null,"orgId": null,"allPeoper": &quo…

【实践篇】推荐算法PaaS化探索与实践 | 京东云技术团队

作者&#xff1a;京东零售 崔宁 1. 背景说明 目前&#xff0c;推荐算法部支持了主站、企业业务、全渠道等20业务线的900推荐场景&#xff0c;通过梳理大促运营、各垂直业务线推荐场景的共性需求&#xff0c;对现有推荐算法能力进行沉淀和积累&#xff0c;并通过算法PaaS化打造…

建木-自动化部署工具-安装文档

阿丹&#xff1a; 在管理微服务在开发环境以及线上环境的时候。发现每次都要手动的去进行更新迭代。但是在项目的管理中使用建木就可以很简单流程化的进行管理项目。 建木官网如下&#xff1a; 建木 下载docker-compose.yml wget https://gitee.com/jianmu-dev/jianmu-deplo…