说说串口
【前言】
首先,串口对每一个做硬件和嵌入式软件的人来说,就是一个必备的工具,调试一个带MCU或者CPU的系统。我们在调试的过程中,一般第一件事情:GPIO点灯。这个我们前期内容已经介绍过了。
在完成GPIO点灯之后,一般我们就希望能够实现串口打印的功能,便于我们将一些寄存器信息打印出来便于调试。
2008年我刚进华为工作时,碰到了一个特殊的历史时期,嵌入式领域群雄逐鹿。
1、Intel、AMD高调宣称X86系统进入嵌入式领域,要占领PowerPC的市场。(后来Intel也做到了,通用服务器占领了几乎所有电信核心侧的设备——刀片服务器、机架服务器)。
2、当时,MIPS、ARM、PowerPC还难分伯仲,不过多核ARM不成熟,无法在电信领域广泛应用。MIPS由于其优异的性价比和搞性能展露头角,慢慢由于其较差的质量表现而偃旗息鼓。
3、PowerPC,随着来着其他处理器的压力,也开始推出多核处理器。
我当时的工作是参与X86处理器作为嵌入式的电路开发。当时碰到一个问题:传统X86作为PC机已经演进得非常成熟的架构。PC的硬件结构与嵌入式SoC有很大的区别。
CPU下面是北桥负责高速外设、北桥的南面(下面)是南桥负责低速接口外设、然后还有一个SIO负责更低速的外设。
SIO全称叫Super I/O。
超级输入输出芯片(SIO)一般位于主板左下方或者左上方。主要使用的芯片有Winbond、ITE,它为主板上的标准I/O接口提供控制处理功能。这里所说的"超级"是指它集成了PS/2键盘、PS/2鼠标、串口COM、并口LPT接口等处理功能,而这些接口都是计算机中的慢速I/O设备。它们全部位于主板后部右边。它的主要功能包括负责处理从键盘、鼠标、串行接口等设备传输来的串行数据,将它们转换成为并行数据,同时也负责并行接口、软驱接口数据的传输与处理。SuperIO是通过一个类似于精简的PCI总线,叫做LPC总线与南桥进行连接的。
如此复杂的硬件结构,也是因为Intel强大的发货量,形成自有体系和标准。
所以在传统的PC机的主板上带一个RS232串口的,都是通过SuperIO实现的。X86上也是通过固定的地址去访问
而我们熟悉的ARM、不管是Cortex-M、还是Cortex-A都是一颗MCU、CPU都带了串口——UART;
从iBox选择的STM32F103的MCU的结构框图上面,我们可以看到有一堆UART、USART。
然而,在我当时面对的嵌入式X86的系统的设计需求,不需要并口、PS2、硬件监控、FDC、
H/W Monitor:一个应用程序读出所有计算机访问硬件传感器的测量值。
FDC:提供了一个主处理器和软驱之间的接口(软驱——看懂的人暴露年龄了)
Parallel port:并行端口(SPP),双向并行端口(BPP),增强型并行端口(EPP),扩展功能并行端口(ECP)四种模式。通过DIR可以控制它的输入/输出模式
认识上图的人再次暴露年龄
KBC:电路提供的功能包括一个键盘和一个PS2鼠标。控制器从键盘和鼠标接受串行数据,检查校验后将这些数据输出到其输出缓冲区。从它的读写命令中可以了解一些基本设置。
UART:终于说到我们的本文的主角UART、即串口了。在老式的台式电脑或者笔记本上,其实都会有RS232电平标准的UART:
关于串口的各种电平标准,我们前期有发布过相关的内容:
UART、RS-232、RS-422、RS-485
SuperIO的UART输出的一般也是TTL电平,还需要接到RS232芯片,再接到DB9接口
X86系统的地址的寻址空间还有点复杂:除了内存空间(Memory)、还有IO空间。详细内容点击:
处理器系列(7)——寻址空间
IO空间是
在X86开发时,串口这些低速的外设是用IO空间进行访问和读写的:
由UARTDevice Configuration Registers可知,UART1~UART4的基址分别是03F8H,02F8H,03E8H,02E8H。
GPIO:通用管脚
ACPI:ACPI是控制电脑电源的系统
这些对于传统的由PowerPC实现的电信嵌入式系统来说,除了串口,其他功能不是需要的;同时,原来的一些NorFlash、寄存器、传感器 数据,需要通过MPI接口进行访问,而这些都是SuperIO芯片不能实现的。
另外由于SuperIO的功能多,所以尺寸大,管脚也多。
所以在当时的设计需求里面,使用一个SuperIO并不合适。所以选择一个CPLD实现LPC接口控制UART接口。
由于我是从事过这么一个工作,所以对UART的工作过程特别熟悉。而且,我们一开始按照自己的想法,自定义了很多寄存器,并且地址是按照自己想法去设计的,结果:商业软件windows、商用linux无法直接识别到串口。后来又改回基址:03F8H,02F8H,03E8H,02E8H这几个地址。
UART是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种异步收发传输器,是设备间进行异步通信的关键模块。UART负责处理数据总线和串行口之间的串/并、并/串转换,并规定了帧格式;通信双方只要采用相同的帧格式和波特率,就能在未共享时钟信号的情况下,仅用两根信号线(Rx 和Tx)就可以完成通信过程,因此也称为异步串行通信。
若加入一个合适的电平转换器,如 SP3232E、SP3485,UART 还能用于RS-232、RS-485 通信,或与计算机的端口连接。UART 应用非常广泛,手机、工业控制、PC 等应用中都要用到UART。
UART使用的是 异步,串行通信。
串行通信是指利用一条传输线将资料一位位地顺序传送。特点是通信线路简单,利用简单的线缆就可实现通信,降低成本,适用于远距离通信,但传输速度慢的应用场合。
异步通信以一个字符为传输单位,通信中两个字符间的时间间隔多少是不固定的,然而在同一个字符中的两个相邻位间的时间间隔是固定的。
数据传送速率用波特率来表示,即每秒钟传送的二进制位数。例如数据传送速率为120字符/秒,而每一个字符为10位(1个起始位,7个数据位,1个校验位,1个结束位),则其传送的波特率为10×120=1200字符/秒=1200波特。
数据通信格式如下图:
其中各位的意义如下:
起始位:先发出一个逻辑"0"信号,表示传输字符的开始。
数据位:可以是5~8位逻辑"0"或"1"。如ASCII码(7位),扩展BCD码(8位)。小端传输
校验位:数据位加上这一位后,使得"1"的位数应为偶数(偶校验)或奇数(奇校验)
停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。
空闲位:处于逻辑"1"状态,表示当前线路上没有资料传送。
注:异步通信是按字符传输的,接收设备在收到起始信号之后只要在一个字符的传输时间内能和发送设备保持同步就能正确接收。下一个字符起始位的到来又使同步重新校准(依靠检测起始位来实现发送与接收方的时钟自同步的)
总结起来,如果我们要配置串口通信,至少要设置一下几个参数:字长(即一次传输数据的长度)、波特率(即每秒传输的数据位数)、奇偶校验位及停止位。
1、我们用打电话为例,来说明串口的工作原理:
首先打电话,说话是串行,即:一个字一个字说。
发送方对接收方发送信息,是串行的:
因为对方是一个字发音、一个字发音听到的,所以每个字是按照时间先后顺序发给对方的。
如果我们用GPIO去传递信号,则我们只能传递"高低电平",信号要么为"高电平"、要么为"低电平"。那么这个管脚传递信息,只有两个状态,跟烽火台一样,要么"有"、要么"没"。
所以当我们用GPIO进行点灯的时候,表示状态的时候,一般就是两个状态,"亮"、"灭"。
但是两个状态、根本没法满足我们传递信息的需求。于是我们希望传递,一串"亮"、"灭",来传递更复杂的信息,跟电报、或者海军信号灯的原理是一样的。
2、串行的数据,如何转并行?
如同打电话一样,我们要听完一句话,接收所有的字、然后组词、组成句子,接收完整的一句话,之后人脑去理解他的语意。
学过《数字电路》的朋友,应该还记得"移位寄存器"吧?
细节,我估计你们早忘光了,甚至当时完全就没学会…后来工作,好像也没用得到。(现在做硬件好像就是原理图PCB画对了就好了,都不用管电路原理。)
大致的意思是:
初始状态: 设A3A2A1A0= 1011
然后Q3的输出,是在每个时钟节拍,按照这个先后顺序,把A3A2A1A0串行的输出出去。
其实利用的就是D触发器的特性。
如果我们使用8位的移位寄存器,就可以利用8个clk的时间,发一组8bit的数据通过一跟导线,传输出去。
接收也是一样的,不过过程相反:
3、喂! XXXX 拜拜
打电话的时候,我们一般会先说:"喂!"。
这是一个信号,通知对方:"我要开始说话了"。
因为打电话的时候,我们彼此看不到对方,不知道对方的表情、眼神、动作、是否听你说话。所以我们通过一个信息,通知对方,启动通信。
在串口的通信过程中,一样的,我们需要通知对方:我要开始通信了。
其实很多接口原理都一样:首先要有个常态,然后再发一个不同的状态,告诉对方,开始了!
对于UART来说,首先要有个常态——高电平(至于为什么是高电平、各种说法,个人觉得应该没什么理由,反过来也不影响)
那么,我们就需要用一个信息告诉接收方,我要传数据了。最简单的方法就是,突然让电平拉低,这样,能够检测一个下降沿,或者能够检测到一个低电平,则,我们就可以认为,要开始了。
UART就选择了这么一个简单粗暴的方法:
上图,中Start,那个低电平,实际就是一个表示开始的信号。我们称之为:起始位。
同样,打电话的时候,我们都需要说:"再见"。
我跟我爸打电话的时候,我爸一般不说再见、拜拜之类的结束语,经常导致:我话还没说完,他就挂电话了。导致我要重新拨号过去。
这个"再见",与平时,我们离开时说的"再见",还多一层意思,表达:"通信可以停止了!"
所以,UART也需要这么一个信息,通知对方,我说完了,你可以处理了。
这个就是"停止位",方式也很简单:"高电平"!
如上图中的STOP。
4、波特率——语速
因为,UART中的A表示的是异步:
(Universal Asynchronous Receiver/Transmitter)
所谓异步,也就是说,我给你发信号的时候,我不给你发时钟;
接收方,需要:
1、时钟与发送方时钟误差不能太大。
2、双方的分析数据的时钟需要保持基本一致。
例如:
发送方发出9600波特率信号,但是接收方的波特率设置为19200。起始位没有问题,因为能够接收到那个下降沿,低电平。所以,会去解析数据,但是会出现误码。我们在信号上分析一下就知道了:
白色的数字是9600波特率发出来的本意:01000001
结果,接收方波特率19200,是9600的两倍,采样的速率也是2倍,解析出来的数据:00011000
这样就造成"错误"。
这也是为什么,我们串口对接时,收发双方需要统一"波特率"的原因。