深度探索串口通信

时间:2022-03-31 13:34:09

串口通信,用的太多了,然而一直没有深入研究过。从刚开始入门单片机,就学习了如何用电脑和单片机通信,但是一旦通信成功后,就再也没有仔细去深入研究过了。这次在使用嵌入式Linux开发板的过程中,被一个问题卡了很久很久,使得我重新认识了串口通信。

问题初现

JZ2440开发板带有1个USB-COM口,三个普通的COM口。电脑通过一条USB线,插到板子的USB-COM口,与板子相连,用来发送控制命令。现在我想使用普通的COM口来和电脑通信,笔记本电脑不带COM口,所以常规的做法就是接一条USB转串口线来实现。

接好之后,开发板串口测试程序也写好了,于是,我打开了电脑上的串口调试助手,开始调试。结果发现,从开发板发过来的数据,跟调试助手显示的不一致。我从开发板发送“ttttt”,电脑收到的十六进制是D1 D1 D1 D1 11。从ascii表上,查到't'应该是74,完全对不上。从此,我陷入到了维持几乎两周的困境。

噩梦开始

1.怀疑COM2口本身坏了,换成旁边的COM3,依旧如此,更换了USB转串口线,还是如此。

2.仔细检查程序是否存在bug,并没有。

3.检查串口参数设置是否一致。波特率、数据位、校验位、停止位、流控,全部都一致。

4.接下来,我开始从发送和接收的数据上来推算,某些规律。

下面是一些测试:
发送一个0x01
电脑串口助手发送 0000 0001
开发板收到的 是   0111 1111
感觉上是位的位置对调,然后全部取反了。电脑和开发板的取位顺序不一致?

发送两个0x01
电脑串口助手发送 0000 0001 0000 0001
开发板收到的是   0111 1111 0111 1111
是一样的。

发送一个0x02
电脑串口助手发送 0000 0010 
开发板收到的 是  0011 1111
这个已经不符合上面的推测了

发送两个个0x02
电脑串口助手发送 0000 0010 0000 0010
开发板收到的 是   1011 1111 0011 1111 
跟上面发送一个0x02相比,很奇怪,感觉错位了。

我凌乱了。。。

5.我开始怀疑是不是编码的问题,找了一些编码转换函数,依旧没什么变化。
6.开发板COM2的TXD和RXD脚短接,自发自收,发送的跟接收的是一致的。同样的,将USB转串口线上的2号脚和3号脚短接,串口调试助手自收自发,结果也是一致的。可以得出的结论是,两边各自都没有问题,一旦相互,就出现了问题。
7.再次怀疑编码的问题,难道Linux和Windows的编码方式不一样?网上讲了一大堆ASCII,UTF-8,Unicode等,丝毫帮不上忙。
8.我开始寻求外援,最后给到的最好的答案是用示波器来观察电平。
刚开始我很怀疑,发送的数据能在示波器上显示出来?不尝试怎么会知道。我先来测试电脑发送的数据波形图,毕竟电脑或者说串口调试助手都是比较稳定的东西,一般都不会错。设置10ms重复发送0x01,真的就看到了图,慢慢调节后,图就出来了。然而,出来的图跟预想的不一样,其实我压根就不知道应该是什么样的图。只知道0和1表现为一高一低的方波。去网上一搜,才知道了真相。

不得不重新来认识一下串行数据的格式,以下内容来自网上一篇文章,也不知道作者是谁,感谢作者。

————————————————— 引用 ————————————————

异步串行数据的一般格式是:起始位+数据位+停止位,其中起始位1 位,数据位可以是5、6、7、8位,停止位可以是1、1.5、2位。起始位是一个值为0的位,所以对于正逻辑的TTL电平,起始位是一位时间的低电平;停止位是值为1的位,所以对于正逻辑的TTL电平,停止位是高电平。对于负逻辑(如RS-232电平)则相反。

例如,对于16进制数据0x55aa,当采用8位数据位、1位停止位传输时,它在信号线上的波形如图1(TTL电平)和图2(RS-232电平)所示。 (先传第一个字节55,再传第二个字节aa,每个字节都是从低位向高位逐位传输)

深度探索串口通信 
图1 TTL电平的串行数据帧格式(0x55aa)

深度探索串口通信 
图2 RS-232电平的串行数据帧格式(0x55aah)

————————————————————————————————————

里面我要重点强调“每个字节都是从低位向高位逐位传输”这一点,如0001这个,示波器图形表现为1000。

另外,终于明白了数据格式的真正的具体形式:起始位+数据位+停止位,从上面的图中就能很清晰看出。

当时着急寻找答案,忘了拍波形图,从网上down来一张,仅供演示:

深度探索串口通信


回到前面我说图形跟数据对不上,实际是自己压根就不懂,瞎猜的。图像跟我所发的数据完全一致。同样的,我测试了开发板串口发出的数据,图形也是吻合的。那就奇怪了,因为示波器是同一个,开发板和电脑给示波器发同一个指令,得到的是一样的图形。这就没问题啊,为什么两者一连通就出现问题了呢?

答案初现

偶然间,我瞥见开发板发数据的图形上面,电压是3.4V。但是,在测试电脑发数据的时候,印象中是10V。回来验证了一下,果真是10V。两边电压不对等啊!连忙去看了开发板的原理图,惊呆了,COM2接口是直接从arm芯片引脚出来的,没有任何转变。常规都是通过一个MAX232芯片来转换一下才接出来。因为arm芯片引脚出来的是TTL电平,差不多3.3-5V,而RS-232电平在10-15v左右,所以不能直连,需要像MAX232这种芯片来转换一下。原来如此,问题就出在这里了,COM2是TTL电平3.4V,而USB转串口线这边是RS-232电平10V。直接连在一起就大错特错了。

新的疑问

前面说过,板子自带一个USB-COM口,于是我去研究了一下,它其实是arm芯片引脚出来接了一个PL2303芯片,这个芯片直接将串口信号转化成了USB信号。再来看我另买的USB转串口线,刚好线材是透明的,我能看到里面有个芯片也是PL2303。这就奇怪了,为什么同样都是PL2303,板子的可以直接连到芯片引脚上,而USB转串口线的必须通过一个MAX232芯片来转换呢?

终极答案

我又仔细看了板子的PL2303芯片,全称是PL2303TA,USB转串口线里面的全称是PL2303RA,一个字母之差会有什么区别呢?在网上找到了PL2303TA和PL2303RA的技术手册,终于真相大白了。虽然同为PL2302芯片,PL2303TA直接在TTL电平下将串口信号转换成USB信号。而PL2303RA会将电平拉高,信号转换的同时电平也变化了。

解决方案

针对COM2口,可以有两种选择:

  1. 买一个带PL2303TA的USB接头,直接插到电脑上
  2. 买一个带MAX232的9针串口,插到USB转串口线上,再插到电脑上