我们以接收方为例,详细讲解串口通讯的简单原理,一个串口数据的接收情况基本如下:
主要分了三层:
1、 硬件层:负责将比特位转换成字节型数据,并且将数据传输的通讯状态记录下来,产生中断让驱动读取,并且部分硬件具备硬件FIFO缓冲区的功能,具体见相关硬件手册。
2、 操作系统驱动层:驱动层的任务很简单,只是负责将数据按照控制方式和通讯状态,放入读缓存,并对产生的数据传输状态进行处理,例如硬件缓存溢出。
3、 应用层:只是负责读取数据和设置通讯方式。
所以简单来说,如果控制方式全部不设置,并且不考虑通讯状态的干扰,从应用层读取的数据就是串口链路的通讯的数据。
2.1硬件层设置
1、波特率:对于串口而言波特率就是每秒传输多少个比特位,比如9600,就是每秒传输9600个比特位,常用的是8个比特位1字节。那么每一位是怎么分辨的,答案是完全靠时钟分辨的。
2、数据位:就是传输数据是按照多少位进行传输的,常用的是5,6,7,8.
3、校验位:只有1位,分奇校验和偶校验,数据位中 1 的个数是奇数,那么偶校验位就置为 1,从而使得总的 1 的个数是偶数;数据位中 1 的个数是偶数,那么奇校验位就置为 1,使得总的 1 的个数保持奇数不变。
4、停止位:分为1和2,用于通知传输结束,高电平,由于串口通讯一定要以一个起始位开始(低电平),那么停止位的高电平到起始位的低电平转换一定可以分辨出传输中的数据位变化,即使两边时钟不一致。
题外话:校验位和停止位设置错误并不一定会导致通讯错误,现代的硬件具备自适应的功能,即使设置错误,也可以被自动纠正,麻烦的是老硬件和新硬件做通讯,就会出现A能接收到B的数据,而B接不到A的数据,常常是这个原因。
5、流控制:
流控制分为两种,一种是硬件流控制,一种是软件流控制,流控制部分本身也比较复杂,下面只是按照大致的功能进行说明。
硬件流控制:硬件流控制常用的有RTS/CTS流控制和DTR/DSR(数据终端就绪/数据设置就绪)流控制。硬件流控制必须将相应的电缆线连上,用RTS/CTS(请求发送/清除发送)流控制时,应将通讯两端的RTS、CTS线对应相连,数据终端设备(如计算机)使用RTS来起始调制解调器或其它数据通讯设备的数据流,而数据通讯设备(如调制解调器)则用CTS来起动和暂停来自计算机的数据流。这种硬件握手方式的过程为:我们在编程时根据接收端缓冲区大小设置一个高位标志(可为缓冲区大小的75%)和一个低位标志(可为缓冲区大小的25%),当缓冲区内数据量达到高位时,我们在接收端将CTS线置低电平(送逻辑0),当发送端的程序检测到CTS为低后,就停止发送数据,直到接收端缓冲区的数据量低于低位而将CTS置高电平。RTS则用来标明接收设备有没有准备好接收数据。
常用的流控制还有还有DTR/DSR(数据终端就绪/数据设置就绪)。我们在此不再详述。由于流控制的多样性,我个人认为,当软件里用了流控制时,应做详细的说明,如何接线,如何应用。
软件流控制:由于电缆线的限制,我们在普通的控制通讯中一般不用硬件流控制,而用软件流控制。一般通过XON/XOFF来实现软件流控制。常用方法是:当接收端的输入缓冲区内数据量超过设定的高位时,就向数据发送端发出XOFF字符(十进制的19或Control-S,设备编程说明书应该有详细阐述),发送端收到XOFF字符后就立即停止发送数据;当接收端的输入缓冲区内数据量低于设定的低位时,就向数据发送端发出XON字符(十进制的17或Control-Q),发送端收到XON字符后就立即开始发送数据。一般可以从设备配套源程序中找到发送的是什么字符。
应该注意,若传输的是二进制数据,标志字符也有可能在数据流中出现而引起误操作,这是软件流控制的缺陷,而硬件流控制不会有这个问题,所以一般的串口通讯需要将软件流控制屏蔽掉。
6、其他
其他部分还有几个,包括CREAD等的设置,由于在基本的通讯里不常用,部分在其他地方讲解,这里就不做详细介绍。
2.2操作系统驱动层
这部分主要介绍操作系统的相关任务,一部分也是硬件的知识,但是由于在调试驱动过程中需要了解,将这部分也移动到这里。操作系统需要了解串口中断的配置和设置,这里也以PC机为例,研祥的MEC5003的工控机和PC机也是一个模式:
2.2.1 串口中断的基本配置:
串口一般可以分两种,一种是主板自带的串口,一般是中断3和4,地址分别为2F8和3F8,另一种是由类似super/IO上的共享串口,中断号可配置成一个,这部分一般可在BIOS部分找到。
串口端口映射到PC机的主板上后,IO端口功能也比较固定,一般一个串口占用8个字节的IO端口,负责完成串口收发工作,这里对应的中断和IO端口地址在BIOS都能找到,并且各个端口的在linux驱动中都能找到相关对应。
详细可以见下,这部分内容需要根据需要进行查找:
在PC上,串口的寄存器是要占用相应的IO空间的,也就是说我们可以通过向相应的IO口写值来改变寄存器的配置。如表2-1所示:
Default I/O addresses and IRQ's on a PC system |
||
COM1 |
0x3F8 - 0x3FF |
4 |
COM2 |
0x2F8 - 0x2FF |
3 |
COM3 |
0x3E8 - 0x3EF |
4 |
COM4 |
0x2E8 - 0x2EF |
3 |
表 2-1 IO端口映射
上面这张表是默认的串口默认使用的I/O地址和中断向量号,在一些系统上,这些值有可能会变动,在PC机上可在BIOS里查看。
接下来要讲的是串口所使用的IO端口了,可暂时略过,需要时做为表进行查找。
对于每一个UART来说,有8个字节的I/O用于其寄存器的访问。如表1-2所示:表中的DLAB是LCR寄存器的Bit7,位于base+3处。
UART register to port conversion table |
||||
|
DLAB = 0 |
DLAB = 1 |
||
I/O port |
Read |
Write |
Read |
Write </ |