串口通信(8)串口中断“边接收边解析数据“的通信程序

news2025/1/20 18:28:09

 本文为博主 日月同辉,与我共生,csdn原创首发。希望看完后能对你有所帮助,不足之处请指正!一起交流学习,共同进步!

> 发布人:@日月同辉,与我共生_单片机-CSDN博客

> 欢迎你为独创博主日月同辉,与我共生点赞❤❤❤+关注👍+收藏🌹+评论☺。

系列专栏: CSDN-单片机串口通信学习系列🎁

> 我的格言是:“尽最大努力,做最好的自己!💪

要转载,请提前告知!!!

版权声明:本文为CSDN博主「日月同辉,与我共生」的原创文章,CSDN独一份。

目录

一、数据帧

1.1数据类型

1.2帧尾

1.3ASCII码

二、系统设计

2.1设计要求

2.2系统原理

2.2.1接收原理&正确性判断原理

2.2.2持续时间原理

三、硬件设计

3.1串口设计

3.2LED模块设计

3.3蜂鸣器模块设计

四、软件设计

4.1串口初始化模块

4.2接收模块

4.3定时器初始化模块

4.4LED+蜂鸣器功能模块

4.5主程序模块

4.6发送数据模块

4.7清除缓冲模块

4.8uart.h

五、结果

一、数据帧

发送到数据帧可以细分成【帧头】、【地址】、【类型】、【长度】、【数据块】、【效验】、【帧尾】7种,但并不是每次发送的数据都要有这7种。

像【地址】,一般只有多机通信会用到,单机通信不需要有。多机通信时,会给每台机编一个地址,确保数据不会发送到其他的机。还有,【长度】并不是每次都要有,如果发的数据长度是固定的,一般不需要有,发送到数据长度不固定时,才需要有。

1.1数据类型

数据类型一般决定处理某个模块。比如我与用户约定好,数据类型01,处理LED,数据类型02,处理蜂鸣器,那么我的设备发送数据01给对方,则对方去处理LED,发送数据02给对方,则对方去处理蜂鸣器。

1.2帧尾

一次通信的结束,一般用一些特殊符号(比如回车等)表示,以防止帧尾前面的数据与帧尾一样,导致通信出现故障。

1.3ASCII码

ASCII码是一种字符编码方式,共有128个字符,包括英文字母、数字、标点符号和一些控制字符等。每个字符用7个二进制位表示,这些二进制位可以转换成十进制数,也可以转换成十六进制数。

字母 A 在 ASCII 码中的二进制表示为 01000001,十进制表示为 65,十六进制表示为 0x41。

数字 0 在 ASCII 码中的二进制表示为 00110000,十进制表示为 48,十六进制表示为 0x30。

控制字符包括换行符、回车符、制表符等,它们的 ASCII 码值在 0~31 和 127 中。

二、系统设计

2.1设计要求

虚拟串口com3发送数据给51单片机com1,com1发回数据给com3,同时处理好接收到的数据。

这次数据帧有帧头+类型+数据块+帧尾组成。帧头为AA 55,数据类型分为01/02,数据块分为高8位和低8位,帧尾为0x0D(回车)。

数据类型为01时,LED灯工作,数据类型为02时,蜂鸣器工作。不论01还是02,持续时间与数据块有关(高8位、低8位)。

2.2系统原理

2.2.1接收原理&正确性判断原理

上两篇文章我们用定时器实现串口通信,本质是先接收后处理数据

回顾上两篇文章:

串口通信(6)应用定时器中断+串口中断实现接收一串数据-CSDN博客

串口通信(7)判断数据帧头来接收一串数据-CSDN博客

今天我们讲述如何一边接收数据一边处理数据

定义一个数组recv_buf,用于存储接收到数据,采用switch-case语句,每接收一个【帧头】数据,立刻用if语句判断【帧头】是否正确,若不正确,则重头判断。

若帧头AA 55数据均正确(recv_buf[0]=AA,recv_buf[1]=55),则进入下一步骤。

在分支2(case 2),接收【类型】(recv_buf[2])和【数据块】(recv_buf[3]和recv_buf[4])。

接着在分支3中,如果帧尾(recv_buf[5]=0x0D)正确,则开始处理LED灯和蜂鸣器。

2.2.2持续时间原理

分别定义两个控制持续时间的变量led_data、beep_cnt。

持续时间=高8位<<8+低8位

在定时器定时1ms的中断中,利用if语句来控制LED灯/蜂鸣器的持续时间。

至于是LED灯还是蜂鸣器工作,由recv_buf[2]决定。

三、硬件设计

3.1串口设计

com1与com3通信,com2是两者的通信媒介,所以单片机com1的发送端TXD接com2的TXD,接收端RXD则接com2的RXD即可。

3.2LED模块设计

LED灯采用共阳极接法,左端接电源(高电平1),右端通过电阻接P1^0,P1^0低电平时,LED导通,发亮;P1^0高电平时,LED不导通,不亮(熄灭)。

3.3蜂鸣器模块设计

R2右端接到P1^7,P1^7为低电平时,三极管导通,+5V电源(提供电压电流的作用)与蜂鸣器连接,蜂鸣器正极为高电平;P1^7为高电平,三极管不导通,蜂鸣器正极为低电平。如图,黄色波形为R2右端(buzzor),蓝色为蜂鸣器正极波形,蜂鸣器发声的原理就是高低电平不断切换。

蜂鸣器模块电路图:

四、软件设计

4.1串口初始化模块

波特率为9600b/s,采用中断法。

回顾中断法:UART通信-中断法

void UartInit(void)		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;			//设置定时初始值
	TH1 = 0xFD;			//设置定时重载值
	ET1 = 0;			  //禁止定时器中断
	ES=1;           //串口中断打开
	TR1 = 1;			  //定时器1开始计时
}

4.2接收模块

可以看看本文2.2.1讲述的原理。

void ES_timers() interrupt 4 //接收中断
{
	static unsigned char machine_step=0;//状态变量
	if(RI)
	{ 
		RI=0; 
		switch(machine_step)
		{
			      case 0:recv_buf[0]=SBUF;//接收第一个数据
			            if(recv_buf[0]==0xAA)
						 {
							 machine_step=1;//帧头第一个数据正确,状态变为1
						 }
						 else
						 {
							 machine_step=0;//帧头第一个数据错误,重新判断下一个是否正确
						 }
				         break;
			       case 1:recv_buf[1]=SBUF;//接收第二个数据
			             if(recv_buf[1]==0x55)
						 {
							 machine_step=2;//帧头第二个数据正确,状态变为2
							 recv_cnt=2;
						 }
						 else
						 {
							 machine_step=0;//帧头第一个数据错误,重新重头判断是否正确
						 }
				         break;
			       case 2:recv_buf[recv_cnt]=SBUF;//接收第3、4、5个数据
						 recv_cnt++;
			             if(recv_cnt>4)
						 {
							 machine_step=3;
						 }
						 else
						 {
							 machine_step=2;
						 }
				         break;
				   case 3:recv_buf[recv_cnt]=SBUF;//接收第6个数据
						if(recv_buf[recv_cnt]==0x0D)//帧尾 0x0D
                         {
							
							switch(recv_buf[2])//通过数据类型判断处理LED还是蜂鸣器
							{
								case 0x01:
								  led_data=recv_buf[3]<<8;
								  led_data=led_data+recv_buf[4];//高8位<<8+低8位=LED控制时 
                                                                //间
								  led_cnt=0;
								  break;
								case 0x02:
								  beep_data=recv_buf[3]<<8;
								  beep_data=beep_data+recv_buf[4];//高8位<<8+低8位=蜂鸣器控 
                                                                  //制时间
								  beep_cnt=beep_data;
								  break;
								default:break;	
							}
							machine_step=0;
							recv_cnt=0;
							recv_flag=1;//接收完成标志位,=1时表明接收完成
						}			
				    break; 
				    default:break;		 
		}
  }
}

4.3定时器初始化模块

定时器T0定时1ms:

回顾定时器:

中断&定时计数器-CSDN博客

单片机笔记(3)定时计数与中断-CSDN博客

void Timer0_Init(void)		//1毫秒@11.0592MHz
{
	TMOD &= 0xF0;			//设置定时器模式
	TMOD |= 0x01;			//设置定时器模式
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	ET0=1;          //定时器0中断打开
	TR0 = 1;				//定时器0开始计时
}

4.4LED+蜂鸣器功能模块

定时1ms,则每1ms中断1次:

void T0_timer() interrupt 1 //利用1ms计数,判断是否接收完成
{
	TR0=0;
	if(recv_flag==1)//接收完毕
	{
		if(led_cnt<led_data)
		{
			LED=~LED;
			led_cnt++;
		}
		else
		{
			led_cnt=0;
			recv_flag=0;
		}
		if(beep_cnt!=0)
		{
			Beep=~Beep;
			beep_cnt--;
		}
		else
		{
			beep_cnt=0;
			recv_flag=0;
		}
	}
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TR0=1;
}

4.5主程序模块

void main()
{
	UartInit();     //调用串口初始化函数
	Timer0_Init();  //调用定时器T0初始化
	EA=1;           //总中断允许
	while(1)
	{
		if(recv_flag==1)//接收完数据后单片机发送回数据给com3
		{
		  sendString(recv_buf);//发送数据,数组recv_buf存储接收到的数据
		  clr_recvbuffer(recv_buf);//清除缓冲
		}
	}
}

4.6发送数据模块

不懂指针和数组的,可以试着回顾前面写的文章的3.2节:

串口通信(5)-一串固定长度数据的接收-CSDN博客

void sendByte(unsigned char dat) //发送一帧数据功能函数
{
	SBUF=dat;
	while(!TI);
	TI=0;
}

void sendString(unsigned char *dat)//发送字符串函数
{
	while(*dat != '\0')
	{
		sendByte(*dat++);
	}
}

4.7清除缓冲模块

unsigned char *buf=recv_buf,则buf[i]=0是将第i+1个数据清0。

void clr_recvbuffer(unsigned char *buf)
{
	unsigned char i;
	for(i=0;i<MAX_REX_NUM;i++)
	{
	  buf[i]=0;
	}
}

4.8uart.h

#ifndef __UART_H__
#define __UART_H__

#include <reg51.h>
#include <stdio.h>

#define MAX_REX_NUM 20
#define MAX_timer_cnt 5

extern unsigned char recv_buf[MAX_REX_NUM];
extern unsigned char recv_cnt;
extern unsigned char start_timer;
extern unsigned char recv_timer_cnt;
extern unsigned char recv_flag;
extern unsigned char led_data;
extern unsigned char beep_data;
extern unsigned char led_cnt;
extern unsigned char beep_cnt;

void UartInit(void);
void sendByte(unsigned char dat);
void sendString(unsigned char *dat);
char putchar(char c);
void clr_recvbuffer(unsigned char *buf);

#endif

本次设计完整代码,请关注不白吃并在评论区回复666!!!

@日月同辉,与我共生-不白吃CSDN博客

五、结果

LED灯:

蜂鸣器:

下一文将着重串口中断即时解析用户自定义通讯协议--接收数据字节固定情况,亲爱的读者敬请期待,下一文更精彩!!!

一日不读书,胸臆无佳想。我叫不白吃,喜欢我的,可以支持我@日月同辉,与我共生!!!

欢迎大家的阅读和交流,也可以自由查阅博主其他文章哦!!!

@日月同辉,与我共生_单片机基础,单片机串口通信-CSDN博客@日月同辉,与我共生擅长单片机基础,单片机串口通信,等方面的知识,@日月同辉,与我共生关注stm32,c语言,51单片机,proteus,单片机领域.https://blog.csdn.net/LIN___IT?spm=1000.2115.3001.5343

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

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

相关文章

linux笔记总结-基本命令

参考&#xff1a; 1.Linux 和Windows比 比较 &#xff08;了解&#xff09; 1. 记住一句经典的话&#xff1a;在 Linux 世界里&#xff0c;一切皆文件 2. Linux目录结构 /lib • 系统开机所需要最基本的动态连接共享库&#xff0c;其作用类似于Windows里的DLL文件。几 乎所有…

流媒体服务实现H5实时预览视频

目录 背景方案业务实践细节注意 待办 背景 客户aws服务磁盘存储告急&#xff0c;最高可扩容16T。排查如下&#xff1a;主要是视频文件存在大量复制使用的情况。例如发布节目时复制、预览时复制&#xff0c;这样上传一份视频后最大会有四份拷贝&#xff08;预览、普通发布、互动…

PHP隐藏手机号码、银行卡号、真实姓名部分方法

1、隐藏手机号码,隐藏手机号中间部分 /*** 隐藏手机号码* param int $mobile 手机号码* param int $head 头部显示数* param int $tail 尾部显示数* param string $hide_str 隐藏字符串* return string*/ function getHiddenMobile($mobile, $head 3, $tail 4, $hide_str *…

PHP依赖注入 与 控制反转详解

依赖注入 是一种设计模式&#xff0c;用于解耦组件之间的依赖关系。 它的主要思想是通过将依赖的对象传递给调用方&#xff0c;而不是由调用方自己创建或管理依赖的对象。这种方式使得组件的依赖关系更加灵活&#xff0c;易于维护和测试。 控制反转 是一个更广泛的概念&#…

C++ 输入输出流

iostream库&#xff0c;包含两个基础类型istream(输入流)和ostream(输出流)。一个流就是一个字符序列。 流 输入输出产生的字符串称为流。 被称为流的原因&#xff1a;所有的字符都在缓冲区中&#xff0c;从缓冲区拿/放都是顺序进行的&#xff0c;字符串的消耗&#xff0c;像…

IDEA 设置代码注释模板

功能简介&#xff1a; 每次看别人代码时&#xff0c;面对毫无注释的类&#xff0c;除了头大还是头大&#xff0c; 以下提供了一种代码类注释模板 新建java类的时候&#xff0c;自动增加类注释&#xff0c;养成代码开发好习惯 效果展示&#xff1a; 代码模板&#xff1a; #if (…

《算法通关村—如何使用中序和后序来恢复一颗二叉树》

《算法通关村—如何使用中序和后序来恢复一颗二叉树》 中序&#xff1a;3 4 8 6 7 5 2 1 10 9 11 15 13 14 12 后序&#xff1a;8 7 6 5 4 3 2 10 15 14 13 12 11 9 1 通过后续遍历我们知道根节点是1&#xff0c;通过知道根节点是1&#xff0c;我们就可以从中序序列知道那些 …

不只保护隐私的防窥膜,还是屏幕的小铠甲

电脑防窥膜这种东西确实很实用&#xff0c;尤其是那些经常在公共场所用笔记本的朋友&#xff0c;更是需要这张贴膜的保护&#xff0c;不过虽然现在市面上这种防窥膜种类繁多&#xff0c;但是产品质量良莠不齐。有些防窥膜虽然有防窥效果&#xff0c;但透光率下降太多了&#xf…

【使用Python编写游戏辅助工具】第一篇:概述

引言 欢迎阅读本系列文章&#xff0c;本系列将带领读者朋友们使用Python来实现一个简单而有趣的游戏辅助工具。 写这个系列的缘由源自笔者玩了一款游戏。正巧&#xff0c;笔者对Python编程算是有一定的熟悉&#xff0c;且Python语言具备实现各种有趣功能的能力&#xff0c;因…

如何解决MySQL主从复制延时问题

MySQL 主从延时的原因是什么&#xff1f; 具体哪个环节发生延时&#xff1f; 如何解决呢&#xff1f; 对于这“三连问”&#xff0c;极少有同学能通关&#xff0c;甚至有同学连主从复制原理都不清楚。 01 什么是主从延时&#xff1f; 有时候我们遇到从数据库中获取不到信息…

Centos8安装yum源时候出现的异常问题及解决方案(保好使)

问题的出现 作者在使用centos8的时候&#xff0c;想安装tree命令&#xff0c;输入了如下的命令&#xff1a; yum install tree 但是却显示了下面的错误&#xff1a; Errors during downloading metadata for repository base: - Curl error (28): Timeout was reached for h…

MySQL第一讲·存储与字段

你好&#xff0c;我是安然无虞。 文章目录 1. 存储&#xff1a;一个完整的存储过程是怎样的&#xff1f;创建MySQL数据库确认字段创建数据表插入数据 2. 字段&#xff1a;那么多字段类型&#xff0c;该怎么定义&#xff1f;整数类型浮点数类型和定点数类型文本类型日期与时间类…

Shiny Server和ShinyProxy是什么,有什么区别?

调研以及参与过多个生物公司的生信工具研发&#xff0c;不管是ShinyServer还是ShinyProxy都有一定研究&#xff0c;尤其是ShinyServer。如果仅是本地化测试想快速的搭建Shiny应用&#xff0c;我推荐用Shiny Server&#xff0c;如果多并发用户且更好的线上管理Shiny应用&#xf…

【Unity数据交互】Json序列化你记得几分

ˊˊ &#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1…

掌握这几个技巧,才敢称为Jenkins大神!

01、Performance插件兼容性问题 自由风格项目中&#xff0c;有使用 Performance 插件收集构建产物&#xff0c;但是截至到目前最新版本&#xff08;Jenkins v2.298&#xff0c;Performance&#xff1a;v3.19&#xff09;&#xff0c;此插件和Jenkins都存在有兼容性问题&#x…

scanpy赋值问题

今天发现一个很奇怪的bug import numpy as np import pandas as pd import anndata as ad from scipy.sparse import csr_matrix print(ad.__version__)counts csr_matrix(np.random.poisson(1, size(100, 2000)), dtypenp.float32) adata1 ad.AnnData(counts) print(adata1)…

基于深度学习的视频多目标跟踪实现 计算机竞赛

文章目录 1 前言2 先上成果3 多目标跟踪的两种方法3.1 方法13.2 方法2 4 Tracking By Detecting的跟踪过程4.1 存在的问题4.2 基于轨迹预测的跟踪方式 5 训练代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的视频多目标跟踪实现 …

网络安全演练(一句话木马)

在享受互联网带来的便利的同时&#xff0c;也充满了各种网络安全风险&#xff0c;本文通过搭建实验环境&#xff0c;演示一句话木马获取主机权限。 演示环境 服务端&#xff1a;安装LAMP环境&#xff0c;部署web网站&#xff0c;上传一句话木马文件 客户端&#xff1a;安装A…

基于springboot实现在线考试平台项目【项目源码+论文说明】计算机毕业设计

基于springboot实现在线考试演示 摘要 网络的广泛应用给生活带来了十分的便利。所以把在线考试管理与现在网络相结合&#xff0c;利用java技术建设在线考试系统&#xff0c;实现在线考试的信息化。则对于进一步提高在线考试管理发展&#xff0c;丰富在线考试管理经验能起到不少…

【Linux】Nignx的入门使用负载均衡动静分离(前后端项目部署)---超详细

一&#xff0c;Nignx入门 1.1 Nignx是什么 Nginx是一个高性能的开源Web服务器和反向代理服务器。它使用事件驱动的异步框架&#xff0c;可同时处理大量请求&#xff0c;支持负载均衡、反向代理、HTTP缓存等常见Web服务场景。Nginx可以作为一个前端的Web服务器&#xff0c;也可…