精讲串口通信协议,小白少走弯路的东西
精讲串口通信协议,小白少走弯路的东西

串口通信协议,基本上是每个单片机开发人员必会的协议,是所有通信协议里面最最常用的。但是很多人并没有去研究过细节,这篇文章干货满满,将带你深入串口协议的内部。
1、串口协议简介
什么是串口通信?
简而言之,串口通信就是通过一根导线(TX,只讨论发送,当然一定还包括GND),将需要的数据按bit流传送给接收端,既然是通信,参与的双方当然要制定数据的传输方式以及规范。
随便打开一个串口助手都可以看到,如果需要使用串口就需要配置端口、波特率、数据位、停止位、校验位、流控这些参数。
如果接收端和发送端的设置不同,就可能会导致数据异常。
端口:这个就不用解释了,使用串口芯片安装驱动后就可以在电脑上看到端口号了。
现在,我们从电平信号角度分析一下波特率、数据位、停止位、校验位、流控(由于用的比较少,暂不分析)的作用。
2、电平信号分析
打开串口工具,分别调整如下参数
①调整参数9600/8/N/1,发送十六进制数据55 AA
②调整参数115200/8/N/1发送十六进制数据55 AA
③调整参数9600/7/N/1发送十六进制数据55 AA
④调整参数9600/8/O/1发送十六进制数据55 BA
⑤调整参数9600/8/E/1发送十六进制数据55 BA
⑥调整参数9600/8/N/2发送十六进制数据55 AA
其中B代表起始位,E代表停止位,很明显看出是先传输的低bit,再传输的高bit。
根据①②分析,调整波特率并不会影响整体波形形状,只有bit的持续时长不同,9600波特率时的一个bit大概占104us,115200波特率大概是9us,这是可以算出来的9600:1000ms/9600 = 104.1us,115200:1000/115200=8.6us。分析可知波特率越大,传输速度越快。
根据①③分析,调整数据位后,55本来应该是01010101但是数据位调整到7之后,55变成了1010101,AA本来是10101010变成了0101010,分析可知错误的数据位会将传输的字节从高位开始截断,可能导致数据丢失。一般来说除非特殊需求,否则不会调整数据位参数。
根据①④⑤分析,将校验位调整至奇校验(ODD)后,传输的bit多了一个奇校验位,就是说如果本来的8个bit的bit位按位加起来是偶数,则在最高位需要补一位1,否则补0,55传输变成了 (1)01010101,BA变成(0)10111010,同样偶校验(EVEN)、MASK校验(校验位始终为1)、SPACE校验(校验位始终为0)是相同的道理。
根据①⑥分析,将停止位设置为2后,传输的结束位(图片中的E)变成之前的2倍,分析可知,设置停止位,可改变数据传输完成后的停止位bit持续的时间。
3、为什么需要起始位和停止位?
波特率、数据位、校验位很好理解,都是为了实现不同的业务需求,但是起始位和停止位存在的意义是什么呢?
起始位:平时这根导线上是高电平,如果接收方检测到低电平了,说明要开始接受数据了,是发送方通知接收方开始接受的一种方式。(不考虑流控)
停止位:发送方通知接收方发送完成的一种方式。发送方发送完一个字节后,“暂停一会”再继续发送下一个字节。
这时帅气的小伙伴就要问了,起始位存在的意义可以理解,但是为什么需要停止位呢?不是提前都约定好了传输8个bit,接收方不能就接受到8个bit后认为一个字节传输结束就OK了吗?
能思考到这一步的小伙伴已经很棒了。如果我们是设计师,我们从设计的角度设计一下接收方接受数据的伪代码
//接收端接收数据线程
while(1) {
//接收到起始位下降沿电平
if((isGetStartFlag == 0) && getDownEdge()) {
Delayus(52);
//检测起始位低电平
if(isLowPin()) {
isGetStartFlag = 1;
getBitIndex = 0;
}
}
//已经接收到起始位
if(isGetStartFlag) {
Delayus(104);
if(getHighOrLow() == high) {
//接收到1bit
}else {
//接收到0bit
}
getBitIndex++;
if(getBitIndex == 8) {
//字节接收完成
isGetStartFlag = 0;
getBitIndex = 0;
}
}
}
按照这种伪代码逻辑,如果不存在停止位,会产生两个问题。
1、可能无法检查下降沿
如果上一个字节最后一次传输是0,而下一个字节的起始位也是0,那么下一个字节的起始位就检测不到下降沿,无法触发下一个字节的传输,就会丢失数据。这时帅气的小伙伴又要问了,那我不检查下降沿,只检查低电平不行吗?直接把getDownEdge换成isLowPin函数不就可以了吗,确实可以,这样又会引入第二个问题。
2、时钟同步问题
假设A跟B说,10分钟后你提醒我喝水,然后B就看着自己的表,10分钟后提醒A,这时A一看表,才过去9分钟。这种场景现实也会出现,造成的原因是A和B的表不同步或者有误差这个误差的引入就导致了A和B所指的“10分钟”不相同,在我们这个串口的场景里,就是发送方和接收方约定了9600波特率,也就相当于约定了104.1us传输一个字节,按照上面的伪代码,几个采集点应该是
但是由于误差,可能导致采集点偏移为
这两个图能大致表达时钟不同步,导致接收设备的采集点后移,如果这时引入了停止位,第二个BYTE开始时,由于还是从下降沿开始采集,所以会重置上一个BYTE引入的误差。
4、总结
这篇干货基本把串口协议分析透彻了,大家在分析协议的时候,最好是从设计的角度去思考这样设计的作用,如果有什么分析不对的地方,欢迎大家指正。