(新手必看)自定义数据传输通信协议+STM32代码详解

这篇具有很好参考价值的文章主要介绍了(新手必看)自定义数据传输通信协议+STM32代码详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言


       本篇博客主要学习和了解一些单片机协议的格式,在对传输大数据或者要求准确性的时候,都需要通过协议来发送接收,下面通过了解协议的基本构成和代码来分析和实现协议的发送和接收。本篇博客大部分是自己收集和整理,如有侵权请联系我删除。

本次博客开发板使用的是正点原子精英版,芯片是STM32F103ZET6,需要资料可以@我拿取。

交流群:717237739

如果觉得有用点赞关注收藏三连,多谢支持

本博客内容原创,创作不易,转载请注明
————————————————

一 .什么是协议?

协议,是网络协议的简称,网络协议是通信计算机双方必须共同遵从的一组约定

如怎么建立连接,怎么样互相识别等,只有遵守这个约定,计算机之间才能相互通信交流。它的三要素是:语法,语义,时序。为了使数据在网络上从源到达目的,网络通信的参与方必须遵循相同的规则,这套规则为协议,最终体现为在网络上传输的数据包的格式。 

例如,串口的波特率,也是协议的一种表现格式。

参考知乎的资料了解七层协议:OSI 七层模型和TCP/IP模型及对应协议(详解)

OSI 七层模型和TCP/IP模型及对应协议(详解)

单片机怎样自定义协议去传输数据,常见协议,单片机,自定义协议,嵌入式,STM32

以上图片是为了让我们对协议有个充足的概念,具体的自己可以先行了解协议的含义和作用。

二 .协议的组成 

1.概念

这里说的数据协议是建立在物理层之上的通信数据包格式。所谓通信的物理层就是指我们通常所常用的RS232,RS485,红外,光纤,无线等通信方式

2.组成部分

比较可靠的通信协议包括:帧头,地址信息,数据类型,数据长度,数据块,校验位,帧尾

在日常自己定义的格式里,我们一般也是要遵循这些格式来定义一个数据包的发送和接收,以保证数据的完整性和准确性。

  • 帧头:一帧数据的开始,可以使用多个字节,具体内容自己定义。例如:0X55
  • 地址信息:主要用于多机通信中,通过地址信息的不同来识别不同的通信终端,确定和哪个设备进行通信(类似于IIC的芯片地址ID)。例如:0X01
  • 数据类型:可以标识后面紧接的是命令还是数据,例如0X01标识二进制,0x02标识十六进制等。
  • 数据长度:标识后面的要发送/接收的数据长度的个数。例如:0X02,表示后面跟两个数据。
  • 数据块:真正发送的数据内容,发送数据内容的长度和上面的数据长度对应。
  • 校验码:用来检验数据的完整性和准确性,一般常见的校验方式有(MODBUS_CRC16/CRC32,ADD8/16求和等等)
  • 帧尾:判断数据包的结束,可以为一个数据或者多个数据,自己定义,例如0XAA

根据以上的协议格式介绍,一般正常的数据包为:

0X55        0X01        0X01        0X02        0X13        0X88        CRC16H        CRC16L        0XAA

(帧头        地址        数据类型     长度        数据        数据        CRC检验H      CRC校验L      帧尾)

 

三. 类似的芯片手册协议格式讲解

这里参考一个芯片手册:SYN6658中文语音合成芯片 用户手册

单片机怎样自定义协议去传输数据,常见协议,单片机,自定义协议,嵌入式,STM32

 从这里分析可以得到:

帧头为:        0XFD        数据长度:2字节 0xXX 0xXX       命令字:参考手册一字节

命令参数:一字节     数据文本:最大4K字节

下面是手册的一些命令字和命令参数的参考:

单片机怎样自定义协议去传输数据,常见协议,单片机,自定义协议,嵌入式,STM32

完整的数据包格式:

单片机怎样自定义协议去传输数据,常见协议,单片机,自定义协议,嵌入式,STM32

 注意:在一些使用其他芯片的场景下,我们一般都需要遵守各个芯片的协议格式,然后根据手册和要求发送对应的数据包,这样协议对应才能驱动芯片。

四 . STM32代码实现自定义格式协议

我们在网上找到有对应的嵌入式协议测试题目,我们根据这个题目写出对应的协议发送和接收代码,代码内部做了注释,整体就不再讲解了,不懂的只能去补补C语言了,代码仅做参考。

测试题:

单片机怎样自定义协议去传输数据,常见协议,单片机,自定义协议,嵌入式,STM32

题目分析:

  • 1.数据包格式,建议直接做成结构体的模式,然后传入地址,一个个调用就很方便了
  • 2.已知的信息,直接宏定义调用,例如帧头帧尾
  • 3.提前写好串口数据包的发送和接收函数,类似数组遍历那种,然后了解清楚占用的字节大小
  • 4.题目要求最大65536,但是我们在STM32F103上实现,就最大256算了,不然超范围了
  • 串口发送和接收函数讲解和应用:基于STM32 + UART串口通信新手详解

单片机怎样自定义协议去传输数据,常见协议,单片机,自定义协议,嵌入式,STM32

 代码.C.H部分和main部分

#include "rs485.h"
#include <stdio.h>
#include <string.h>
u8 sendbuf[Send_Buf_Size];  //发送数据缓冲区
u8 recbuf[Rec_Buf_Size];		//接收数据缓冲区
RS485 rs485def={sendbuf,recbuf,0,0}; //rs485相关信息结构体

//中断服务函数接收数据
void USART3_IRQHandler(void)
{
	u8 data;
	u32 head,tail;
	u8 len;
	if(USART3->SR & 1<<5)
	{
		data= USART3->DR;
//		printf("%x\t",data);
		rs485def.recbuf[rs485def.reclen]=data ;//存放收到的数据
		rs485def.reclen++;
		if(rs485def.reclen >=8) //收到了包头和数据域长度
		{
			head = *(u32*)rs485def.recbuf;//获取包头
//			printf("head:0x%x\r\n",head);
			if(head == PACK_START)//收到包头
			{
				len = *(u32*)&rs485def.recbuf[4];//获取数据域长度
//				printf("reclen:%d,len:%d\r\n",rs485def.reclen,len);
				if(rs485def.reclen >= len+12) //一帧数据接收完成
				{
					tail = *(u32*)&rs485def.recbuf[len+4+4];//获取包尾 4包头所占4字节,4数据域长度所占4个字节
//					printf("tail:0x%x\r\n",tail);
					if(tail == PACK_TAIL )//包尾正确
					{
						rs485def.recflag = 1; //接收完成标志
					}
					else
					{
						rs485def.reclen = 0 ;
					}
				}
			}
			else
			{
				rs485def.reclen = 0 ;
			}
		}
	}
}

//数据包接收函数
//函数功能:得到数据包的相关内容
//出口参数 :
//返回值 : 0 接收到数据 1 ,没收到数据
u8 RecPacket(Packet* pdata)
{
	u8* ptemp = rs485def.recbuf;
	u8 len;
	u8 buf[Rec_Buf_Size-20];
	pdata->pInform = (char *)buf;
	if(rs485def.recflag == 1)
	{
		rs485def.recflag = 0 ;		
		//跳过包头
		ptemp += 4;
		//获取数据域长度
		len = *(u32*)ptemp;
	  //获取验证码
		ptemp += 4;
		pdata->identify = *(u16*)ptemp;
		//获取源地址
		ptemp += 2;
		pdata->SrcAddr = *(u16*)ptemp;
		//获取目的地址
		ptemp += 2;
		pdata->DesAddr = *(u16*)ptemp;
		//获取命令码
		ptemp += 2;
		pdata->CmdNum = *(u16*)ptemp;
		ptemp += 2;  //指向信息内容
		//获取信息长度
		pdata->InformLlen = len - 8;	
		//获取信息内容
		memcpy(pdata->pInform,ptemp,pdata->InformLlen);
		//清除
//		memset(&rs485def,0,sizeof(RS485));
		rs485def.reclen = 0 ;
		return 0 ;
	}
	return 1;
}

//数据包发送函数
//入口参数:发送的数据包
void SendPacket(Packet* pdata)
{
	u8* ptemp = rs485def.sendbuf;
	u8 sendlen;
//	u8 i;
	//把需要发送的数据赋给sendbuf
	//包头
	*(u32*)ptemp=PACK_START;
//	printf("0x%x\r\n",*ptemp);
	//数据域长度
	ptemp += 4;
	*(u32*)ptemp = pdata->InformLlen+8;
	//验证码
	ptemp += 4;
	*(u16*)ptemp = pdata->identify;
	//源地址
	ptemp += 2;
	*(u16*)ptemp = pdata->SrcAddr;
	//目的地址
	ptemp += 2;
	*(u16*)ptemp = pdata->DesAddr;
	//命令码
	ptemp += 2;
	*(u16*)ptemp = pdata->CmdNum;
	//信息内容
	ptemp += 2;
	//strcpy strncpy memcpy memset-->这几个函数的区别
	memcpy(ptemp,pdata->pInform,pdata->InformLlen);
//RS485_Send(ptemp,pdata->InformLlen);
	
	//包尾
	ptemp+=pdata->InformLlen;
	*(u32*)ptemp=0x88CC55AA;
		
	//发送数据
	ptemp += 4;
	sendlen = ptemp - rs485def.sendbuf;//发送数据长度	
//	printf("send:");
//	for(i=0;i<sendlen;i++)
//		printf("%x\t",rs485def.sendbuf[i]);
	RS485_Send(rs485def.sendbuf,sendlen); //发送数据
}
#ifndef _RS485_H_
#define _RS485_H_
#include "stm32f10x.h"
#include "io_bit.h"

#define Send_Buf_Size 256
#define Rec_Buf_Size 	Send_Buf_Size

typedef struct
{
	u8 *sendbuf;		 //发送数据缓冲区
	u8 *recbuf;			//接收数据缓冲区
	u8 reclen;			//接收数据总长度
	u8 recflag;			//接收完成事件标志位
}RS485;
extern RS485 rs485def;

//数据包
#define PACK_START 0xAA55CC88	//帧头
#define PACK_TAIL  0x88CC55AA //帧尾
typedef struct
{
	u16 identify;  //验证码 --字节
	u16 SrcAddr;   //源地址
	u16 DesAddr;   //目的地址
	u16 CmdNum;    //命令码
	char* pInform; //信息内容
	u8 InformLlen; //信息长度
}Packet;

u8 RecPacket(Packet* pdata);
void SendPacket(Packet* pdata);


#endif

 main


int main()
{	
	Packet SendPack;
	Packet RecPack;
	char sendbuf[6]= "12345";
	LED_Init();
	KEY_Init();
	SCB->AIRCR= 0X05FA0500 ; //设置为分组2
	USART1_Init(115200);
	delay_init(72);
	OLED_Init();
	W25QXX_Init();
	DHT11_Init();
	RS485_Init();
	while(1)
	{
		if(Key_Scanf(0))  //发送
		{	 
//			printf("key\r\n");
			//填充数据包   ---  学习 433模块 CC1101
			SendPack.identify = 0x1234;		//验证码
			SendPack.SrcAddr  = 0x5678;		//源地址
			SendPack.DesAddr  = 0x90ab;		//目的地址
			SendPack.CmdNum   = 0xcdef;	  //命令码
			SendPack.pInform  = sendbuf;	//信息内容
			SendPack.InformLlen=strlen(sendbuf);//信息长度
			SendPacket(&SendPack);
		}
		if(!RecPacket(&RecPack))//收到数据
		{
			//打印收到的数据
			printf("identify:0x%x\r\n",RecPack.identify);  //验证码
			printf("SrcAddr:0x%x\r\n",RecPack.SrcAddr);		 //源地址
			printf("DesAddr:0x%x\r\n",RecPack.DesAddr);		 //目的地址
			printf("CmdNum:0x%x\r\n",RecPack.CmdNum);			 //命令码
			printf("pInform:%s\r\n",RecPack.pInform);			 //信息内容
			printf("InformLlen:%d\r\n",RecPack.InformLlen);//信息长度
		}
	}	
}

总结:


      协议在一些公司的项目一般都会用到,最常见的就是485-modbus,不过基本的格式都差不多,这部分内容在项目了算是比较重要的,IAP升级的常用YModem协议也是异曲同工,类似的芯片DHT11和模块也会有协议格式要求。大家如果对我的博客有疑问或者错误,可以@我修改,大家相互交流。

交流群:717237739

如果觉得有用点赞关注收藏三连,多谢支持

本博客内容原创,创作不易,转载请注明

  点赞收藏关注博主,不定期分享单片机知识,互相学习交流。
————————————————
 文章来源地址https://www.toymoban.com/news/detail-773874.html

到了这里,关于(新手必看)自定义数据传输通信协议+STM32代码详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据通信——传输层TCP(可靠传输原理的ARQ)

    上一篇讲述了停止等待协议的工作流程,在最后提到了ARQ自动请求重传机制。接下来,我们就接着上一篇的篇幅,讲一下ARQ这个机制 还是这个图来镇楼  发送端对出错的数据帧进行重传是自动进行的,因而这种差错控制体制常简称为ARQ(Automatic Repeat reQuest),直译是自动重传请

    2024年02月10日
    浏览(28)
  • TCP数据传输协议详解

    1、TCP概述 1、点对点 一个发送方,一个接收方 2、可靠地,按顺序的字节流 没有报文边界 3、管道化(流水线) TCP拥塞控制和流量控制设置 窗口大小 4、发送和接收缓存 5、全双工数据 在同一连接中数据流双向流动 MSS:最大报文段大小 6、面向连接: 在数据交换之前,通过握

    2024年02月13日
    浏览(35)
  • 数据通信——传输层(UDP)

    我们上网观看比赛的时候,一旦网络信号出现问题,那可就太难受了,这意味着卡顿的时间内,你会错过这段时间内的内容。这种特性要归功于UDP(User Datagram Protocol)用户数据报协议。     一般的,数据在通过应用层后会到达传输层,如果传输层使用UDP作为封装手段,那么

    2024年02月11日
    浏览(20)
  • FPGA(Verilog)实现uart传输协议传输数据(含仿真)

    目录 实现功能: 1.接收uart串行数据,输出并行数据(1byte)。 2.输入并行数据(1byte),输出uart串行数据。 3.完成uart传输的1次环回。 uart协议的1帧数据传输 模块封装-port设置 Verilog代码实现 1.uart接收模块:接收串行数据,输出并行数据和其有效标志。 仿真结果: 2.uart发送模块:接收

    2024年04月16日
    浏览(28)
  • STM32+ESP-01s+EMQX实现单片机MQTT协议传输数据上云(二)STM32F103与ESP-01s的Usart通信,实现STM32连接上网上云

    单片机:STM32F103c8t6 WiFi模块:ESP8266-01s EMQX:自身服务器上搭载emq服务器或者借用emqx window 版本  USB TO TTL模块:CH340 因为CH340不能给ESP-01s供3.3V的电,所以测试时需要外加供电           本章中涉及到的技术原理主要为ESP01S wfi模块的AT指令通信,我在上一篇文章给大家提到了

    2024年02月16日
    浏览(35)
  • openmv与stm32串口通信数据传输

    在openmv与stm32数据传输过程中遇到了奇怪的问题。 先说明我遇到的问题,后面又源码。 若发现问题-------或者有什么想法-------还望指教!!! 我的目的: openmv矩形识别,获取中心点坐标,通过串口发给stm32接受数据 我在main函数中,将存放的数据打印出来,然而并没有。如图

    2024年02月15日
    浏览(29)
  • UDP(用户数据报协议)和TCP(传输控制协议)是互联网协议(IP)中两种主要的传输层协议

    您的描述是正确的。UDP(用户数据报协议)和TCP(传输控制协议)是互联网协议(IP)中两种主要的传输层协议。他们之间有几个重要的区别,其中之一就是建立连接的方式。 连接方式: • TCP:在进行数据传输之前,需要通过三次握手(3-way handshake)建立连接。这可以确保

    2024年02月02日
    浏览(88)
  • 数据链路层传输协议(点到点):停等协议、GBN、SR协议

        1. 上层调用(网络层) 上层要发送数据时,发送方先检查发送窗口是否已满。 如果 未满, 则产生一个帧并将其发送;如果窗口 已满 ,发送方只需将数据返回给上层,暗示窗口已满. 2. 收到一个ACK G B N rm GBNGBN协议中,对n nn号帧的确认采用累计确认,标明接收方已经收到n nn号帧和

    2024年02月08日
    浏览(22)
  • 哈工大计算机网络传输层协议详解之:可靠数据传输的基本原理

    哈工大计算机网络课程传输层协议详解之:流水线机制与滑动窗口协议 哈工大计算机网络课程传输层协议详解之:TCP协议 哈工大计算机网络课程传输层协议详解之:拥塞控制原理剖析 什么是可靠? 不错、不丢、不乱 可靠数据传输协议 可靠数据传输对应用层、传输层、链路

    2024年02月12日
    浏览(30)
  • 【计算机网络笔记】传输层——可靠数据传输之流水线机制与滑动窗口协议

    什么是计算机网络? 什么是网络协议? 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能(1)——速率、带宽、延迟 计算机网络性能(2)——时延带宽积、丢包率、吞吐量/率 计算机网络体系结构概念 OSI参考模型

    2024年02月06日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包