江科大32——USART发送数据包原理

文章介绍了HEX数据包的格式及其在串口通信中的作用,强调了包头包尾的重要性以及如何处理数据和包头包尾可能的冲突。通过固定包长和可变包长的方式,解决了数据包的构建和接收问题。此外,提到了文本数据包的使用场景和优缺点,并概述了状态机在接收数据包过程中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.HEX数据包格式

 数据包的作用:

        把一个个单独的数据打包起来,方便进行多字节的数据通信。

比如:陀螺仪传感器需要用串口发送数据到STM32,陀螺仪的数据有X轴一个字节,Y轴一个字节,Z轴一个字节,3个数据,需要连续不断地发送。如果使用XYZXYZXYZ连续发送就会出现接收方识别不出X,Y,Z对应的数据,即不知道数据哪个对应X,哪个对应Y。因为接收方可能会从任意位置接收,所以会出现数据错位的现象。所以就出现了使用包头包尾把XYZ这一批数据进行分割。分割成一个个数据包,数据包的第一个数据就是X,第二个就是Y。属于把同一批的数据进行打包分割,方便接收方进行识别。

打包的方法可以自己设计,比如在XYZXYA数据流中,数据包的第一个数据即X的数据包,最高位置1,其余数据置0,接收数据后,判断最高位,如果是1就是X数据,接下来的数据就是Y和Z。

这种方法的原理是把每个数据地最高位当作标志位来进行分割。

串口数据包通常使用的收发数据的方法:

        额外添加包头包尾

1)固定包长,含包头包尾,就是每个数据包的长度固定不变,数据包前面是包头,后面是包尾

2)可变包长,含包头包尾,也就是每个数据包的长度可以是不一样的,前面是包头,后面是包尾。

数据包格式可以根据用户需求自己规定,也可以是模块开发者规定。

上图固定有效数据包长为4个字节,在加上包头包尾就是6个字节

定义0XFF为包头,在四个字节之后,定义0XFE为包尾

添加包头包尾打包数据思路:

当接收到0XFF后,就知道一个数据包来了,接下来接收的4个字节数据接当作数据包的第1,2,3,4个数据存在一个数组里。当收到包尾0XFE之后,就可以置一个标志位,告诉程序,我接收到了一个数据包。然后新的数据包过来重复之前的过程。这样就可以在数据流中分割出想要的数据包。

问题1:如果传输的数据本身和包头包尾一样,例如传输的数据是0XFF,0XFE可能会引起误判,解决方法如下:

1)限制载荷数据的范围,在发送的时候对数据进行限幅,比如X,Y,Z3个数据,变化范围可以是0-100,就可以在载荷中只发送0-100的数据,这样就不会和包头包尾重复了。

2)如果无法避免数据和包头包尾重复,就尽量使用固定长度的数据包,这样,由于载荷数据固定

只要通过包头包尾对齐数据,就可以严格知道那个数据是包头包尾,哪个数据是载荷数据,在接收载荷数据的时候不会判断它是否是包头包尾,在接收包头包尾时,会判断它是否属于包头包尾,用于数据对齐,经过几个数据包的对齐之后,剩下的数据包就不会出现问题了。

3)增加包头包尾的数量,并尽量让它呈现出载荷数据呈现不了的状态,比如使用FF,FE作为包头,使用FD,FC作为包尾,这样也可以避免载荷数据和包头包尾重复的情况。

问题2:包头包尾的数据并不是全都需要的,比如可以只要一个包头,把包尾删掉,这样数据包的格式就是一个包头FF+4个数据,当检测到FF,开始接收4个字节,置标志位,一个数据包接收完成。但是这样载荷和包头重复的问题会更严重,比如最严重时,载荷全是FF,这时包头也是FF,这时就不知道哪个是包头,加上FE作为结尾后,数据怎么变化都可以分辨出包头包尾。

问题3:固定包长和可变包长的选择

对于HEX数据包,如果载荷和包头包尾会出现重复的情况,最好选择固定包长,这样可以避免接收错误。载荷不会和包头包尾重复,可以选择可变包长这时数据长度可以任意变化,因为这时包头包尾是唯一的。

问题4:各种数据转化为字节流

由于数据包是一个字节一个字节组成的,如果想发送uint16_t,uint32_t,float,double,结构体数据都是可以的,因为它们内部是由一个字节一个字节组成的。

只需用uint8_t指针指向它,把他们当作一个字节数组发送就行了。

2.文本数据包

文本数据包需要经过编码和译码,最终表现出文本格式,但实际上每个文本字符背后还是一个字节的HEX数据。

文本传输数据的模式也是固定包长和可变包长两种模式,由于数据译码成了字符的形式,就会有很多字符可以作为包头包尾,可以有效避免载荷和包头包尾重复。所以文本数据包基本不需要担心数据包和包头包尾重复的问题。可变包长中各种字母,数字,符号都可以随意使用。

当接收到载荷数据之后得到的就是一个字符串,在软件中对字符串进行操作和判断,就可以进行指令控制的功能。字符串表达的意义比较明显

3.两种数据包的优缺点

1)HEX数据包:

优点:传输直接,解析数据简单,比较适合模块发送的原始数据。

比如使用串口通信的陀螺仪,温湿度传感器。

缺点:灵活性不足,载荷容易和包头包尾重复。

2)文本数据包

优点:数据直观易理解,非常灵活,比较适合一些输入指令进行人机交互的场合。

比如蓝牙模块常用的AT指令,CNC和3D打印机常用的G代码。

缺点:解析效率低,比如发送100,HEX数据包发送一个字节100就行了,文本数据包就需要发送3个字节的字符,‘1’,‘0’,‘0’.收到之后还要把字符转换成数据,才能得到100.

可以根据实际场景选择数据包格式

4.数据包的收发流程

1)数据包的发送流程:

比如HEX数据包:定义一个数组,填充数据,用SendArray()函数就行了

文本数据包:写一个字符串,调用SendString()

2)接收数据包流程

固定包长HEX数据包的接收方法:

根据之前的代码,每收到一个字节程序都会进行一次中断,在中断程序函数拿到字节数据,拿到数据后就退出中断,所以每拿到一个数据,都是一个独立的过程。

但是对于数据包,它具有前后关联性,包头之后是数据,数据之后是包尾,对于这3种状态需要不同的处理逻辑,所以需要设计一个能记住不同状态的机制。在不同状态进行不同的操作,同时进行状态的合理转移。

这种程序设计思维叫做状态机

这里使用状态机的方法接收数据包,要想设计一个好的状态机程序,上面的状态转移图是必要的。

对于固定包长HEX数据来说,可以定义3个状态

第一个状态是等待包头,第二个状态是接收数据,第三个状态是等待包尾。

每个状态需要用一个变量来标志比如上面用变量S进行标志.3个状态依次为S=0,S=1,S=2。

类似标志位。

执行流程:S=0,收到一个数据,进中断,根据S=0进入第一个状态的程序,判断数据是不是包头FF,如果是FF则代表收到包头,之后置S=1,退出中断,结束。下次进中断,根据S=1,就可以进行接收数据的程序。如果不是FF,证明数据包没有对齐,应该等待数据包包头的出现。这时状态等然是0,下次进中断,还是判断包头的逻辑。直到出现FF才能转到下一个状态,出现FF就可以转移到接收数据的状态,接收到了数据就直接把它存在数组中,再用另一个变量记录收到了多少个数据,如果没收够4个数据,就一直是接收状态,收够了,就置S=2.下次进中断时就可以进下一个状态了。下个状态就是等到包尾,判断是不是FE,判断完之后置S=0。

当数据和包头重复,导致包头判断错误,包尾位置可能就不是FE,这时就可以进行重复等待包尾的状态,直到接收到真正的包尾。

使用的基本步骤:

根据项目要求定义状态,(画个圈)考虑好各个状态在什么情况下会进行转移,如何转移(画好线和转移条件)根据图进行编程思维更清晰。

2)可变包长文本数据包接收流程

利用状态机定义3个状态

第一个状态:等待包头,判断接收到数据的是不是规定的‘@’符号

,如果收到@就进入接收状态,在这个状态下接收数据,同时,这个状态还应该兼具等待包尾的功能。因为这时可变包长,我们在接收数据的时候,要时刻监视是不是接收到包尾了。一旦接收到包尾了就结束。

这个状态的接受逻辑是:

收到一个数据,判断是不是\r   如果不是就正常接收,如果是就不接收,同时跳到下一个状态,等待包尾\n因为这里有2个包尾。如果只有一个包尾,在出现包尾之后就可以直接回到初始状态了。

串口的包头包尾不会出现在数据中,所以不会出现数据错位的现象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值