在我们定义串口通讯协议的时候,肯定是首先要考虑通讯协议内容是以 ASCII码 还是 hex十六进制。
对于这两类的各有各的优点和缺点。
一、ASCII
优点:
1、简单直观。(比如在串口调试助手很容易看懂协议上传的数据)
2、数据起始标志位和结束标志位唯一,不与数据内容冲突。(比如起始位为SS,结束位为\r\n)
3、适用大小端MCU的协议通讯,8位单片机基本都是大端,32位及以上单片机和PC都是小端。(大小端MCU数据高低字节内存保存位置不同,只能通过转译成int数据才能处理)
缺点:
1、效率低。(把ASCII码转译成int类型进行协议处理)
2、发送数据也要转译。(把int转译成ASCII)
数据接收方式:
1、 单条协议接收;(常用)
2、队列接收数据。(最好)
模板:
数据与数据之间使用空格符分隔;协议的除了起始位和结束位以为都将转译成int类型,再进行进一步解析处理。
起始标志位:这个标志位自定义,SS;
指令:对应的控制的指令;为什么要把指令放在前,数据内容长度放后面的,其实这是有关系的,每个指令都有数据内容长度,一旦数据内容长度也代码定义的指令的数据内容长度代表协议错误。
数据内容个数(可选):数据内容int类型的个数;
数据内容:对应指令传递的数据;
CRC16(可选):计算的是转译后int类型的数据,指令和数据内容个数及数据内容这部分数据的CRC16;计算CRC16的时候一定要取消字节对齐。
结束标志位:一般用\r\n作为结束符。
二、hex十六进制
优点:
1、高效。(接收到的数据无需转译,直接协议解析处理)
2、数据直接发送。
缺点:
1、数据不直观(比如在串口调试助手很难看懂协议上传的数据)
2、数据起始标志位和结束标志位不唯一,与数据内容冲突。(比如起始位为0xCC 0xDD,一旦数据内容出现0xCC 0xDD则可能会被认为是协议起始位,没有结束标志位)
3、不适用于大小端MCU的协议通讯,8位单片机基本都是大端,32位及以上单片机和PC都是小端。(大小端MCU数据高低字节内存保存位置不同,但是强行使用也可以注意数据高低字节颠倒)
数据接收方式:
1、单条协议接收;(使用这种方式的一定要把起始标志位和结束标志位或者数据长度定好,比如起始标志一定要多字节,起始标志字节越多和数据内容冲突的概率越低,结束标志位也一样)
2、个人只推荐队列(个人常用,稳定)。
队列模板:
起始标志位:起始标志位自定义,常用1个字节做起始标志位;两个字节及以上解析麻烦一点点,但是也有好处,冲突概率低很多。
指令:对应的控制的指令;
为什么指令要放在数据长度前面,不像其他人一样先把“数据长度”放在“指令”前面呢?
其实这是有好处的。
原因是每条“指令”在写代码都知道对应的“数据长度”,此时我们只需要判断通讯协议中的“指令”和“数据长度”是否一致,一致则继续接收,最后进行CRC16校验;否则释放当前起始标志,寻找下一个起始标志。
极端如果“数据长度”在前,万一出现0xFFFF这个数据长度,是否单片机要接收到数据长度为0xFFFF才进行校验,那要多少条数据,才能开始校验。
数据长度:数据内容的字节数;
CRC16:确保协议数据正确及完整,绝对不可省去。
为什么我个人只喜欢用队列呢?
原因是:hex十六进制通讯的时候不像ASCII码一样有起始标志有结束标志,可以知道一条数据开始和结束。
hex十六进制怎么知道一个条数据的完整呢?
第一步:现在队列找到起始标志位0xAA,队头不是0xAA的都出队。
第二步:找到队头后,等待获取指令和数据长度,若与代码固化的指令数据长度一致则从队列中获取数据长度的数据,进行CRC16校验。
若不一致则0xAA队头出队。
全篇完。
本人是一个嵌入式未入门小白,博客仅仅代表我个人主观见解,记录成长笔记。
笔记是以最简单的方式,只展示最核心的原理。
若有与 大神大大 见解有歧义,我绝对坚信 大神大大 见解是对的,我的是错的。
若无积分等无法下载源码,可加入QQ群657407920下载交流经验。感谢~!