串口中断(10)自定义通讯协议-协议带数据长度及接收应答处理

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

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

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

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

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

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

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

69d2c602c4ec47cab5112eeed53f9d69.png

目录

一、自定义通讯协议

二、系统设计要求

三、硬件设计

3.1UART通信模块

3.2数码管模块

3.3仿真图

四、软件设计

4.1串口初始化

4.2接收中断

4.3数码管模块

4.4定时器模块

4.5主程序

4.6发送数据模块

4.7清除缓存

4.8uart.h

五、系统测试

5.1正确应答-类型01,长度01

5.2正确应答-类型02,长度02

5.3正确应答-类型03,长度03

5.4错误应答-和效验错误

5.5错误应答-异或效验错误

 

一、自定义通讯协议

自定义通讯协议是指一种特定的数据交互方式,该方式不同于通用的通讯协议,例如HTTP、TCP等。自定义通讯协议可以根据具体的业务需求和通讯要求进行设计,满足数据传输的可靠性、效率、安全性等方面的需求。

⛄定义通信内容及传输方式:首先需要明确通信双方需要交换哪些数据。例如,数据头、数据体、校验位、结束符等。同时需要确定数据传输的方式,如串口通信、TCP/IP通信、WiFi通信等。

 

⛄定义字节序列:根据通信内容,将需要传输的数据按照一定的规则组成字节序列,以便在传输过程中进行处理。

 

⛄添加校验和:在传输数据时,为了保证数据的完整性和正确性,需要给数据添加校验和。常用的校验方式有CRC校验、累加和校验等。

 

⛄定义解析规则:通信双方需要约定如何解析接收到的数据。例如,如何区分数据头和数据体,如何解析数据体中的不同字段等。

 

⛄计好通信协议后,需要进行通信测试。测试时需要模拟发送和接收端,并验证数据传输和解析是否正确。如果出现问题,需要及时修改协议设计或者程序代码。

🌟在实际应用中,自定义通讯协议可以应用于各种领域,例如智能家居、工业控制、物联网等。自定义协议的设计能够在满足特殊需求的同时,提高通信效率、降低通信成本,为应用领域提供更加可靠、安全、高效的通信解决方案。

二、系统设计要求

2.1总设计要求

虚拟终端com3发送数据给单片机com1,发送的数据帧由帧头、类型、数据长度、代码块、和校验、异或校验组成。接收完数据后,单片机根据用户双方约定好的校验位是否正确,发送不同的应答(数据帧),如果数据正确,根据不同的数据类型,让4位数码管显示不同的数据。

2.2设计细节

数据帧:55 AA 类型(01/02/03) 数据长度(1/2/3) 代码块 和校验 异或校验

数据类型为01时,数据长度为1,显示1个字节;数据类型为02时,数据长度为2,显示2个字节;数据类型为03时,数据长度为3,显示2个字节(4位数码管只能显示2个字节,这里显示代码块第2、3个数据);

正确应答:0x55,0xAA,0x80,0x0,0x80,0x80

错误应答:分和效验错误应答和异或效验错误应答。

和效验错误应答:0x55,0xAA,0x81,0x0,0x80,0x80

异或效验错误应答:0x55,0xAA,0x82,0x0,0x80,0x80

三、硬件设计

3.1UART通信模块

d46307903ec043dbb46178025efca0e0.png

3.2数码管模块

线码:dp g f e d c b a

段码(控制数码管第几位显示):1 2 3 4

数码管模块:采用定时延时法。软件编码步骤:1.消隐 2.段码 3.线码 4.延时1ms(定时器定时1ms)。

74HC245芯片用于提高P0的电流驱动能力,让数码管能够显示数据。

a7f04e63db0542daa559ab6dcf9d9bf1.png

3.3仿真图

元件清单:四位数码管采用共阴极。在本文基础上,大家可以尝试使用6位数码管用于显示数据。

e0fb29ddaf3646fe91fbfada31cf5810.png

9cee1a76ec6e424e8a35b249aa92cc62.png

四、软件设计

本文4.1、4.2、4.6、4.7节均为uart.c(串口通信源文件)

代码文件整理:

f9ceb0fcb7244a0fb1ef225e355ef69f.png

4.1串口初始化

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接收中断

数组recv_buf存储类型、长度、代码块数据,用于主程序处理数码管显示。

定义sum_check、 xor_check分别求和效验值、异或效验值。

分支0:判断帧头数据55是否正确==>分支1:判断帧头数据AA是否正确==>分支2:接收类型,从分支2开始计算和效验、异或效验==>分支3:接收长度,计算和效验、异或效验==>分支4:接收代码块,计算和效验、异或效验==>分支5:判断和效验是否正确,若错误发送和效验错误应答==>分支6:判断异或效验是否正确,若错误单片机发送异或效验错误应答,正确发送单片机发送正确应答。

void ES_timers() interrupt 4 //接收中断
{static unsigned char machine_step=0;static unsigned char sum_check;static unsigned char xor_check;unsigned char i;if(RI){ RI=0; recv_data=SBUF;//recv_data为中间变量,用于接收发送的数据switch(machine_step) //55 AA 01/02/03 长度 代码块 和效验 异或效验{case 0:if(recv_data==0x55) //帧头:55H AAH{machine_step=1;}else{machine_step=0;}break;case 1:if(recv_data==0xAA){machine_step=2;recv_cnt=0;}else{machine_step=0;}break;case 2:recv_buf[recv_cnt]=recv_data; //接收数据类型sum_check=recv_data;xor_check=recv_data;machine_step=3;recv_cnt++;break;case 3:recv_length=recv_data; //数据字节长度sum_check+=recv_data;xor_check^=recv_data;machine_step=4;break;case 4:recv_buf[recv_cnt]=recv_data; //接收数据sum_check+=recv_data;         //计算和效验xor_check^=recv_data;         //计算异或效验if(recv_cnt==recv_length)     {machine_step=5;//接收数据完成后跳到下一个分支}else{machine_step=4;}recv_cnt++;break;case 5:if(sum_check==recv_data) //和效验正确{machine_step=6;}else                     //和效验错误{machine_step=0;for(i=0;i<6;i++){sendByte(sum_check_error[i]);//和效验错误应答}  }break; case 6:if(xor_check==recv_data) //异或效验正确{recv_flag=1; //接收正确,标志位置1for(i=0;i<6;i++){sendByte(recv_correct[i]);//发送正确应答}  }else{for(i=0;i<6;i++){sendByte(xor_check_error[i]);//异或效验错误应答}  }machine_step=0;sum_check=0;xor_check=0;recv_cnt=0;break; 			default:break;		 }}
}

4.3数码管模块

display.c

#include "display.h"unsigned char code leddata[]={0x3F, //00x06, //10x5B, //20x4F, //30x66, //4																																																																		0x6D, //50x7D, //60x07, //70x7F, //80x6F, //90x77, //A																																																																							0x7C, //B0x39, //C0x5E, //D0x79, //E0x71, //F0x76, //H0x38, //L0x37, //n0x3E, //u	0x73, //P																																																																	0x5C, //o0x40, //-0x00  //熄灭};//数码管段码表unsigned char LEDBuf[]={8,8,8,8};//缓冲区
unsigned char code PLACE_COOE[]={0xfe,0xfd,0xfb,0xf7};//位码
/******************************************************************************************
函数名:display
功能:数码管显示函数
参数:无
返回值:无
******************************************************************************************/
void display()
{unsigned char i;IO_DIG=0x00;//消隐IO_DIG=leddata[LEDBuf[i]];//段码IO_PLACE=PLACE_COOE[i];//位码i++;if(N==i)i=0;
}

display.h

#ifndef __DISPLAY_H__
#define __DISPLAY_H__#include <reg51.h>#define IO_DIG   P0 //段码IO
#define IO_PLACE P2 //位码IO#define N 4 //数码管个数unsigned char code leddata[];//变量声明
extern unsigned char LEDBuf[];void display();//数码管显示函数声明#endif

4.4定时器模块

定时1ms,用于数码管能够显示出数字。

void Timer0_Init(void)		//1毫秒@11.0592MHz
{TMOD &= 0xF0;			//设置定时器模式TMOD |= 0x01;			//设置定时器模式TL0 = 0x66;				//设置定时初始值TH0 = 0xFC;				//设置定时初始值TF0 = 0;				//清除TF0标志ET0=1;          //定时器0中断打开TR0 = 1;				//定时器0开始计时
}void T0_timer() interrupt 1 //利用1ms计数,判断是否接收完成
{TR0=0;display();TL0 = 0x66;				//设置定时初始值TH0 = 0xFC;				//设置定时初始值TR0=1;
}

4.5主程序

LEDBuf[ ]:数码管显示缓冲区,用于显示display.c表中对应的数字/字符。

recv_buf[0]:数据类型

长度为1,显示recv_buf[0]

长度为2,显示recv_buf[1]、recv_buf[2]

长度为3,显示recv_buf[2]、recv_buf[3]

要想显示数据,就要将数据(2位数)拆成每一位分别显示到对应的位置。十位数=数据右移4位,个位数=数据&0x0f。

#include <reg51.h>
#include "uart.h"
#include "display.h"void Timer0_Init(); //定时器0函数声明sbit LED=P1^0;//位定义
sbit Beep=P1^7;void main()
{UartInit();     //调用串口初始化函数Timer0_Init();EA=1;           //总中断允许printf("Wait for Serial Communication Tset Start.\r\n");printf("Please Send a string of data:\r\n");while(1){if(recv_flag==1) //接收完毕,开始解析{recv_flag=0;switch(recv_buf[0])//数据类型---命令{case 0x01://数码管显示1字节LEDBuf[0]=23;LEDBuf[1]=23;LEDBuf[2]=recv_buf[1]>>4;LEDBuf[3]=recv_buf[1]&0x0f;break;case 0x02://数码管显示2字节(第1、2个数据)LEDBuf[0]=recv_buf[1]>>4;LEDBuf[1]=recv_buf[1]&0x0f;LEDBuf[2]=recv_buf[2]>>4;LEDBuf[3]=recv_buf[2]&0x0f;break;case 0x03://数码管显示2字节(第2、3个数据)LEDBuf[0]=recv_buf[2]>>4;LEDBuf[1]=recv_buf[2]&0x0f;LEDBuf[2]=recv_buf[3]>>4;LEDBuf[3]=recv_buf[3]&0x0f;break;default:clr_recvbuffer(recv_buf); //清除缓存break;	}}}
}

4.6发送数据模块

发送数据dat==>等待发送完成(发送完成TI自动置1)==>TI清0,以便下次能够发送数据帧。

void sendByte(unsigned char dat) //发送一帧数据功能函数
{SBUF=dat;while(!TI);TI=0;
}void sendString(unsigned char *dat)//发送字符串函数
{while(*dat != '\0'){sendByte(*dat++);}
}

4.7清除缓存

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 5extern 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 int led_data;
extern unsigned int beep_data;
extern unsigned int led_cnt;
extern unsigned int 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

五、系统测试

串口助手模式:十六进制

5.1正确应答-类型01,长度01

类型:01,长度:01,代码快:10

和效验正确,异或效验正确,正确应答55 AA 80 00 80 80

数码管显示  10

c7d16f56d8724f18a4682039e34c411a.png

5.2正确应答-类型02,长度02

类型:02,长度:02,代码快:10 11

和效验正确,异或效验正确,正确应答55 AA 80 00 80 80

数码管显示1011

461b247642da4dc78415425d318cc246.png

5.3正确应答-类型03,长度03

类型:03,长度:03,代码快:10 11 13

和效验正确,异或效验正确,正确应答55 AA 80 00 80 80

数码管显示1113

8b92579ced0145f6927f22de8ac75f2d.png

5.4错误应答-和效验错误

和效验错误,异或效验正确,和效验错误应答55 AA 81 00 80 80

ee0f1c75fcb0415f84200566054b1902.png

5.5错误应答-异或效验错误

和效验错误,异或效验错误,异或效验错误应答55 AA 82 00 80 80

6a3f01d5372648b880685ff3d3524832.png

想要快速计算出效验值吗?关注我并在评论区留言“666”,博主@日月同辉,与我共生将免费提供快速计算出效验值的网站。

目前,串口通信系列已经写了9篇,大家可以到我的主页​​​​​​​免费查询。

下一文将着重讲述CRC16效验,亲爱的读者敬请期待,下一文更精彩!!!

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

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

 

 

 

 

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

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

相关文章

【无标题】【教3妹学编程-算法题】2918. 数组的最小相等和

3妹&#xff1a;呜呜&#xff0c;烦死了&#xff0c; 脸上长了一个痘 2哥 : 不要在意这些细节嘛&#xff0c;不用管它&#xff0c;过两天自然不就好了。 3妹&#xff1a;切&#xff0c;你不懂&#xff0c;影响这两天的心情哇。 2哥 : 我看你是不急着找工作了啊&#xff0c; 工作…

帷幄内容管理系统:从立人设、做内容到定向投流,品牌 KOS 体系打造「百万导购」

随着公域流量越来越贵&#xff0c;获客成本越来越高&#xff0c;品牌们已经越来越不满足于高曝光&#xff0c;而是更多地关注起销售转化率。继 KOL、KOC&#xff08;关键意见消费者&#xff09; 之后&#xff0c;KOS&#xff08;关键意见销售&#xff09;营销模式走入品牌的视野…

排序算法之-冒泡

顺序排序算法原理 从头开始遍历未排序数列&#xff0c;遍历时比较相邻的两个元素&#xff0c;前面的大于后面的&#xff0c;则双方交换位置&#xff0c;一直比较到末尾&#xff0c;这样最大的元素会出现在末尾&#xff0c;接着再依次从头开始遍历剩余未排序的元素&#xff0c;…

MSQL系列(十四) Mysql实战-SQL语句 left join inner join On和Where语句的区别

Mysql实战-SQL语句On和Where语句的区别 前面我们讲解了Join的底层驱动表 选择原理&#xff0c;也知道了基本的内连接外连接两种SQL查询表连接方式 但是我们再查询多表的时候on和where语句到底有什么区别? where是过滤条件 ,不满足where的一定不会出现在结果中on是连接条件, …

网上3D虚拟数字展厅进一步增强营销效果

数字化营销已经成为了企业推广产品和服务的重要手段。由于制作成本及周期限制&#xff0c;企业或个人难以拥有个性化的3D云展厅&#xff0c;顺应市场需求和时代发展&#xff0c;3D云展数字平台作为一种新型的数字化营销工具&#xff0c;具有许多传统营销方式无法比拟的优势。 3…

怎么调整excel表里面所有单元格中,某个相同字体大小,单元格中其他文字大小不变?

环境: excel 2021 python3.8 问题描述: 怎么调整excel表里面所有单元格里面1这个字体大小,单元格里面其他文字不变? excel表里面。很多单元格都有1,1和文字都是10号字体,现在想把全部1字字体调整为16号其他字大小都不变 解决方案: 一、使用python来实现,经过测…

iOS加固原理与常见措施:保护移动应用程序安全的利器

目录 iOS加固原理与常见措施&#xff1a;保护移动应用程序安全的利器 前言 一、iOS加固的原理 1. 代码混淆 2. 加密算法 3. 防调试技术 4. 签名校验 二、iOS加固的常见措施 1. 代码混淆 2. 加密算法 3. 防调试技术 4. 签名校验 三、iOS加固的效果和注意事项 参考…

如何在macbook上删除文件?Mac删除文件的多种方法

在使用MacBook电脑时&#xff0c;桌面上经常会积累大量的文件&#xff0c;而这些文件可能已经不再需要或已经过时。为了保持桌面的整洁和提高电脑性能&#xff0c;我们需要及时删除这些文件。本文将介绍MacBook怎么删除桌面文件&#xff0c;以及macbook删除桌面文件快捷键。 一…

为什么说亚马逊、Lazada、虾皮等跨境平台测评很重要?

在亚马逊、shopee、Lazada的生态系统中&#xff0c;给店铺测评是一个重要的环节&#xff0c;优质的评论可以给潜在的买家对于产品质量更加信任&#xff0c;其次对于提高产品的销售跟排名也可以起到关键的作用 为什么测评重要&#xff1f; 1. 提高页面权重 一般页面有三个部分…

【大数据】Apache NiFi 数据同步流程实践

Apache NiFi 数据同步流程实践 1.环境2.Apache NIFI 部署2.1 获取安装包2.2 部署 Apache NIFI 3.NIFI 在手&#xff0c;跟我走&#xff01;3.1 准备表结构和数据3.2 新建一个 Process Group3.3 新建一个 GenerateTableFetch 组件3.4 配置 GenerateTableFetch 组件3.5 配置 DBCP…

Linux学习第36天:Linux RTC 驱动实验:时间是一条流淌的河

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 RTC就是实时时钟。 本笔记主要学习Linux RTC驱动试验&#xff0c;主要内容包括Linux内核RTC驱动简介、I.MX6U内部RTC分析、RTC时间查看与设置。因为Linux内核已经…

matplotlib.pyplot学习笔记

import matplotlib.pyplot as plt import numpy as np # 画单条线 plot([x], y, [fmt], *, dataNone, **kwargs) # 画多条线 plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs) >>> plot(x, y) # 创建 y 中数据与 x 中对应值的二维线图&#xff0c;使用…

【GEE】8、Google 地球引擎中的时间序列分析【时间序列】

1简介 在本模块中&#xff0c;我们将讨论以下概念&#xff1a; 处理海洋的遥感图像。 从图像时间序列创建视频。 GEE 中的时间序列分析。 向图形用户界面添加基本元素。 2背景 深水地平线漏油事件被认为是有史以来最大的海上意外漏油事件。该井释放了超过 490 万桶石油&am…

JAVA自己写什么功能可以提升技术?

JAVA自己写什么功能可以提升技术&#xff1f; 对于技术提升这个话题&#xff0c;勤于练习&#xff0c;多敲多积累这是一个必经的过程。那我们展开来详细的说一说&#xff0c;比如&#xff1a; 实现各种数据结构和算法&#xff0c;比如链表、树、图、排序、搜索等。这可以提高…

MAC设备(M1)环境下编译安装openCV for Java

最近发现一个需求&#xff0c;可以用openCV来实现&#xff0c;碰巧又新买了mac笔记本&#xff0c;就打算利用业余时间安装下openCV。这里将主要步骤记录下&#xff0c;希望能帮助有需要的人。 1、准备编译环境 #查询编译opencv相关依赖 brew info opencv查询结果如下图所示&a…

Blocking waiting for file lock on the registry index 问题解决

问题表现&#xff1a; cargo build时一直卡在Blocking waiting for file lock on the registry index。 解决方法&#xff1a; 1、之前在linux下出现过一次&#xff0c;采用这种方法解决了&#xff1a;rust - Cargo build hangs with " Blocking waiting for file lock…

虚拟展厅如何在艺术领域应用,虚拟展厅对艺术展有什么帮助

引言&#xff1a; 随着科技的不断发展&#xff0c;虚拟展厅作为一种新的展示方式&#xff0c;在艺术领域逐渐受到重视和应用。虚拟展厅利用虚拟现实技术&#xff0c;将艺术品展示于虚拟空间中&#xff0c;为观众带来更加身临其境的艺术体验。 一、虚拟展厅在艺术领域的应用 1…

批量迁移redis实例的key

我们知道migrate 命令可以迁移redis的多个key&#xff0c;但是如果redis的key有非常多&#xff0c;那用起来就很不方便了。 所以下面分享一个脚本来实现批量key的迁移&#xff0c;主要使用的命令为dump和restore 脚本如下&#xff1a; #!/bin/bash redis-cli -h host1 -p 63…

防止砍单、封号:亚马逊、沃尔玛测评方案优化建议

许多卖家和工作室的朋友们向我咨询&#xff0c;为何他们在测评过程中常常遇到砍单和封号的问题。事实上&#xff0c;这个问题并不难理解。测评所涉及到的技术问题非常复杂&#xff0c;仅仅解决IP或环境单一因素是无法实现稳定的测评的。 目前市场上存在许多技术方案&#xff0c…

工业路由器网关的网络协议之NAT技术

在物联网通讯领域&#xff0c;NAT技术能将内网的一个私有IP转换成一个公网IP去接入互联网&#xff0c;解决组建局域网络时私有IP地址无法在公网上进行路由的问题。 NAT&#xff08;Network Address Translation&#xff09;的三种方式&#xff1a; 静态NAT 1、一个私有IP对应…