用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART。它将要传输的资料在串行通信与并行通信之间加以转换。作为把并行输入信号转成串行输出信号的芯片,UART通常被集成于其他通讯接口的连结上
1.1.1串口信号定义和接线方法-5针串口-9针串口-全功能串口
1.串口、并口接口定义 并行口与串行口的区别是交换信息的方式不同,并行口能同时通过8条数据线传输信息,一次传输一个字节;而串行口只能用1条线传输一位数据,每次传输一个字节的一位。并行口由于同时传输更多的信息,速度明显高于串行口,但串行口可以用于比并行口更远距离的数据传输。 2.25针并行口插口的针脚功能: 表 2 ‑ 3 25针并行口插口的针脚功能
针脚 |
功能 |
传输方向 |
针脚 |
功能 |
传输方向 |
1 |
选通 (STROBE低电平) |
PC->Printer |
10 |
确认 (ACKNLG低电平) |
Printer->PC |
2 |
数据位0 (DATAO) |
PC->Printer |
11 |
忙 (BUSY) |
Printer->PC |
3 |
数据位1 (DATA1) |
PC->Printer |
12 |
却纸 (PE) |
Printer->PC |
4 |
数据位2 (DATA2) |
PC->Printer |
13 |
选择 (SLCT) |
Printer->PC |
5 |
数据位3 (DATA3) |
PC->Printer |
14 |
自动换行 (AUTOFEED低电平) |
PC->Printer |
6 |
数据位4 (DATA4) |
PC->Printer |
15 |
错误观点(ERROR低电平) |
Printer->PC |
7 |
数据位5 (DATA5) |
PC->Printer |
16 |
初始化成(INIT低电平) |
PC->Printer |
8 |
数据位6 (DATA6) |
PC->Printer |
17 |
选择输入 (SLCTIN低电平) |
PC->Printer |
9 |
数据位7 (DATA7) |
PC->Printer |
18-25 |
地线路(GND) |
- |
3.串行口的典型代表是RS-232C及其兼容插口,有9针和25针两类。 25针串行口具有20mA电流环接口功能,用9、11、18、25针来实现。其针脚功能如下: 表 2 ‑ 4 25针串行口插口的针脚功能
针脚 |
功能 |
针脚 |
功能 |
1 |
未用 |
|
|
2 |
发出数据(TXD) |
11 |
数据发送 |
3 |
接受数据(RXD) |
12-17 |
未用 |
4 |
请求发送(RTS) |
18 |
数据接收 |
5 |
清除发送(CTS) |
19 |
未用 |
6 |
数据准备好(DSR) |
20 |
数据终端准备好比(DTR) |
7 |
信号地线路 (SG) |
21 |
未用 |
8 |
载波检测 (DCD) |
22 |
振铃指示精神 (RI) |
9 |
发送返回 |
23-24 |
未用 |
10 |
未用 |
25 |
接收返回 |
4.9针串行口的针脚功能 表 2 ‑ 5 9针串行口插口的针脚功能
针脚 |
功能 |
针脚 |
功能 |
1 |
载波检测(DCD) |
6 |
数据准备好(DSR) |
2 |
接受数据(RXD) |
7 |
请求发送(RTS) |
3 |
发出数据(TXD) |
8 |
清除发送(CTS) |
4 |
数据终端准备好(DTR) |
9 |
振铃指示(RI) |
5 |
信号地线(SG) |
|
|
5. 串口通信基本原理及接线方法 目前较为常用的串口有9针串口(DB9)和25针串口(DB25),通信距离较近时(<12m),可以用电缆线直接连接标准rs232端口(rs422< span="">,RS485较远),若距离较远,需附加调制解调器(MODEM)。最为简单且常用的是三线制接法,即地、接收数据和发送数据三脚相连,本文只涉及到最为基本的接法,且直接用RS232相连。表2‑6中为DB9和DB25的常用信号脚说明。 表 2 ‑ 6 DB9和DB25的常用信号脚说明
9针串口(DB9) |
共同部分 |
25针串口(DB25) |
针号 |
功能说明 |
缩写 |
针号 |
1 |
数据载波检测 |
DCD |
8 |
2 |
接收数据 |
RXD |
3 |
3 |
发送数据 |
TXD |
2 |
4 |
数据终端准备 |
DTR |
20 |
5 |
信号地 |
GND |
7 |
6 |
数据设备准备好 |
DSR |
6 |
7 |
请求发送 |
RTS |
4 |
8 |
清除发送 |
CTS |
5 |
9 |
振铃指示 |
DELL |
22 |
RS232C串口通信接线方法(三线制),串口传输数据只要有接收数据针脚和发送针脚就能实现:同一个串口的接收脚和发送脚直接用线相连,两个串口相连或一个串口和多个串口相连 : 同一个串口的接收脚和发送脚直接用线相连 对9针串口和25针串口,均是2与3直接相连 ; 两个不同串口(不论是同一台计算机的两个串口或分别是不同计算机的串口) 。 上面 分析 是对微机标准串行口而言的,还有许多非标准设备,如接收GPS数据或电子罗盘数据,只要记住一个原则:接收数据针脚(或线)与发送数据针脚(或线)相连,彼此交叉,信号地对应相接,就能百战百胜。
![8de03aa9c10a46abf29f4879803c627a.png](https://i-blog.csdnimg.cn/blog_migrate/e53b243228a9591f77bc03234a2f390f.jpeg)
图 2 ‑ 32 常用串口电缆 串口调试中要注意的几点: 串口调试时,准备一个好用的调试工具,如串口调试助手、串口精灵等,有事半功倍之效果; 强烈建议不要带电插拨串口,插拨时至少有一端是断电的,否则串口易损坏。 6 .单工、半双工和全双工的定义 如果在通信过程的任意时刻,信息只能由一方A传到另一方B,则称为单工。如果在任意时刻,信息既可由A传到B,又能由B传A,但只能由一个方向上的传输存在,称为半双工传输。如果在任意时刻,线路上存在A到B和B到A的双向信号传输,则称为全双工。 电话线就是二线全双工信道。由于采用了回波抵消技术,双向的传输信号不致混淆不清。双工信道有时也将收、发信道分开,采用分离的线路或频带传输相反方向的信号,如回线传输。 7 .奇偶校验 串行数据在传输过程中,由于干扰可能引起信息的出错,例如,传输字符‘E’,其各位为:
由于干扰,可能使位变为1,这种情况,我们称为出现了“误码”。我们把如何发现传输中的错误,叫“检错”。发现错误后,如何消除错误,叫“纠错”。最简单的检错方法是“奇偶校验”,即在传送字符的各位之外,再传送1位奇/偶校验位。可采用奇校验或偶校验。 奇校验:所有传送的数位(含字符的各数位和校验位)中,“1”的个数为奇数,如:
偶校验:所有传送的数位(含字符的各数位和校验位)中,“1”的个数为偶数,如:
奇偶校验能够检测出信息传输过程中的部分误码(1位误码能检出,2位及2位以上误码不能检出),同时,它不能纠错。在发现错误后,只能要求重发。但由于其实现简单,仍得到了广泛使用。 有些检错方法,具有自动纠错能力。如循环冗余码(CRC)检错等。 8.串口通讯流控制 在串行通讯处理中,常常看到RTS/CTS和XON/XOFF这两个选项 (尤其在上位机中) ,这就是两个流控制的选项,目前流控制主要应用于调制解调器的数据通讯中,但对普通RS232编程,了解一点这方面的知识是有好处的。那么,流控制在串行通讯中有何作用,在编制串行通讯程序怎样应用呢?这里我们就来谈谈这个问题。 流控制在串行通讯中的作用 这里讲到的“流”,当然指的是数据流。数据在两个串口之间传输时,常常会出现丢失数据的现象,或者两台计算机的处理速度不同,如台式机与单片机之间的通讯,接收端数据缓冲区已满,则此时继续发送来的数据就会丢失。现在我们在网络上通过MODEM进行数据传输,这个问题就尤为突出。流控制能解决这个问题,当接收端数据处理不过来时,就发出“不再接收”的信号,发送端就停止发送,直到收到“可以继续发送”的信号再发送数据。因此流控制可以控制数据传输的进程,防止数据的丢失。PC机中常用的两种流控制是硬件流控制(包括RTS/CTS、DTR/CTS等)和软件流控制XON/XOFF(继续/停止),下面分别说明。 硬件流控制 硬件流控制常用的有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字符后就立即开始发送数据。一般可以从设备配套源程序中找到发送的是什么字符。应该注意,若传输的是二进制数据,标志字符也有可能在数据流中出现而引起误操作,这是软件流控制的缺陷,而硬件流控制不会有。 9. 额外说明 : UART含义 随着计算机的日益普及,很多非RS232的串口也要接入PC机,如果为每一种新出现的串口都增加一个新的I/O口显然不现实,因为PC后面板位置有限,因此,将RS232串口和非RS232串口都通过RS232口接入是最佳方案。UART的U(通用)指的就是这个意思。早期ROM BIOS和DOS里的通信软件都是为RS232设计的,在没有检测到DCD有效前不会发送数据,因此,就连发送一个字符这样朴素的应用也要给出DCD、DTR、DSR等控制信号。因此,串口接头上要将一些控制线短接,或者干脆绕过系统软件自己写通信程序。 到此,UART的涵义就总结为:通用的 异步 (串行) I/O口。就在UART冠以通用二字,准备一统江湖的时候,制造商们不满于它的速度、体积和灵活性(软件可配置),推出了USB和1394串口。目前,笔记本上的UART串口有被取消的趋势,因而有网友发出了“没有串口,吾谁与归”的慨叹,古今多少事,都付笑谈中,USB取代UART是后话,暂且不表。 话说自从贺氏(Hayes)公司推出了聪明猫(SmartModem),他们制定的MODEM接口就成了业界标准,自此以后,所有公司制造的兼容猫都符合贺氏标准(连AT指令也兼容)。 细观贺氏制定的MODEM串口,与RS232标准大不相同。DTR在整个通信过程中一直保持有效,DSR在MODEM上电后/可以拨号前有效(取决于软件对DSR的理解),在通信过程的任意时刻,只要DTR/DSR无效,通信过程立即终止。在某种意义上,这也可以算是流控,但肯定不是RS232所指的那种主流控。如果拘泥于RS232,你是不会理解DTR和DSR的用途的。 贺氏不但改了DTR和DSR,竟然连RTS和CTS的涵义也重新定义了。因此,RTS和CTS已经不具有最开始的意义了。从字面理解RTS和CTS,是用于半双工通信的,当DTE想从收模式改为发模式时,就有效RTS请求发送,DCE收到RTS请求后不能立即完成转换,需要一段时间,然后有效CTS通知DTE:DCE已经转到发模式,DTE可以开始发送了。在全双工时,RTS和CTS都缺省置为有效即可。然而,在贺氏的MODEM串口定义中,RTS和CTS用于硬件流控,和什么全双工/半双工一点关系也没有。注意,硬件流控是靠软件实现的,之所以强调“硬件”二字,仅仅是因为硬件流控提供了用于流量情况指示的硬件连线,并不是说,你只要把线连上,硬件就能自己流控。如果软件不支持,光连上RTS和CTS是没有用的。 RTS和CTS硬件流控的软件算法如下:(RTS有效表示PC机可以收,CTS有效表示MODEM可以收,这两个信号互相独立,分别指示一个方向的流量情况) 。 PC端处理: 发 : 当发现(不一定及时发现) CTS (-3v to -15v)无效时,停止发送, 当发现(不一定及时发现) CTS (3v to 15v)有效时,恢复发送; 收 : 当接收buffers中的bytes当接收buffers中的bytes>N 时,给 RTS 无效信号(-3v to -15v); MODEM端处理:同上,但RTS与CTS交换。 在RS232中本来CTS 与RTS 有明确的意义,但自从贺氏(HAYES ) 推出了聪明猫(SmartModem)后就有点混淆了。在RS232中RTS 与CTS 是用来半双工模式下的方向切换;HAYES Modem中的RTS ,CTS 是用来进 行硬件流控的。通常UART的RTC、CTS 的含义指后者,即用来做硬流控的。 如果UART只有RX、TX两个信号,要流控的话只能是软流控;如果有RX,TX,CTS ,RTS 四个信号,则多半是支持硬流控的UART;如果有 RX,TX,CTS ,RTS ,DTR,DSR 六个信号的话,RS232标准的可能性比较大。 硬流控的RTS 、CTS :RTS (Require To Send,发送请求)为输出信号,用于指示本设备准备好可接收;CTS(Clear To Send,发送清除)为输入信号,有效时停止发送。假定A、B两设备通信,A设备的RTS 连接B设备的CTS ;A设备的CTS 连接B设备 的RTS 。前一路信号控制B设备的发送,后一路信号控制A设备的发送。对B设备的发送(A设备接收)来说,如果A设备接收缓冲快满的时发出RTS 信号(意思 通知B设备停止发送),B设备通过CTS 检测到该信号,停止发送;一段时间后A设备接收缓冲有了空余,发出RTS 信号,指示B设备开始发送数据。A设备发(B设备接收) 类似。上述功能也能在数据流中插入Xoff(特殊字符)和Xon(另一个特殊字符)信号来实现。A设备一旦接收到B设备发送过来的Xoff,立刻停止发 送;反之,如接收到B设备发送过来的Xon,则恢复发送数据给B设备。同理,B设备也类似,从而实现收发双方的速度匹配。 半双工的方向切换:RS232中使用DTR(Date Terminal Ready,数据终端准备)与DSR(Data Set Ready ,数据设备准备好)进行主流控,类似上述的RTS 与CTS 。对半双工的通信的DTE(Date Terminal Equipment,数据终端设备)与DCE(Data circuit Equipment )来说,默认的方向是DTE接收,DCE发送。如果DTE要发送数据,必须发出RTS 信号,请求发送数据。DCE收到后如果 空闲则发出CTS 回 应RTS 信 号,表示响应请求,这样通信方向就变为DTE->TCE,同时RTS 与CTS 信号必须一直保持。从这里可以看出,CTS ,TRS虽 然也有点流控的意思(如CTS 没有发出,DTE也不能发送数据),但主要是用来进行方向切换的。
1.1.2UART传输时序分析
串口传输数据都是一帧数据 11 位 ,参考 图 2‑33 中的串口时序。
![fca6c19c56fde3435e1e85c51b52bb65.png](https://i-blog.csdnimg.cn/blog_migrate/51de94e26899bc04265e3883f680dca1.png)
图 2 ‑ 33 串口时序 表 2 ‑ 7 串口时序说明表
位 |
位作用 |
0 |
起始位 |
1~7 |
数据位 |
9 |
校验位 |
10 |
停止位 |
在串口的总线上“高电平”是默认的状态,当一帧数据的开始传输必须先拉低电平,这就是第 0 位的作用。第 0 位过后就是 8 个数据位,这八个数据位才是一帧数据中最有意 义的东西。最后的两位是校验位和停止位,作用如同命名般一样。 串口传输还有另一个重要参数就是“波特率”。“波特率”在宏观上理解就是串口传输的传输速度;在微观上“波特率”就是串口传输中“一个位的周期”,换句话说亦是“一个位所逗留的时间”。这个概念在后期编写程序是很重要的。 常用的波特率有 9600 bps 和 115200 bps ( bit per second )。“9600 bps” 表示每秒可 以传输 9600 位。但是经过公式计算“一个位的周期”就会暴露出来。 一个位的周期 = 1 / bps = 1/ 9600 = 0.000104166666666667 从上述的公式,我们明白一个事实 9600 bps , 传输 一位数据占用 0.000104166666666667s 时 间。如果是一帧 11 位的数据,就需要 0.000104166666666667 x 11 = 0.00114583333333334 那么一秒钟内可以传输 1 / 0.00114583333333334 = 872.727272727268 872.727272727268 个帧数据。 当然这只是在数字上计算出来而已,但是实际上还有许多看不见的延迟因数。 当使用1 15200 bps , 一个位的周期 = 1 / bps = 1/ 115200 = 0.000086805555555555555555555555555556 传输 一位数据占用 0.000086805555555555555555555555555556s 时 间。如果是一帧 11 位的数据,就需要 0.000086805555555555556 x 11 = 0.00095486111111111111111111 那么一秒钟内可以传输 1 / 0.00095486111111111111111111 = 1047.2727272727272727272739459174 1047.2727272727272727272 个帧数据。 如果用 50Mhz 的时钟频率去量化的话: ( 1/115200 ) / (1/50E+6) = 8.68E-6 / 20E-9 = 434
1.1.3简单UART传输FPGA实现
![8c5ef957ba7d20cd232c7b9cf2eb4252.png](https://i-blog.csdnimg.cn/blog_migrate/6118d96cb7cc7f181b86140cbeba71f5.png)
图 2 ‑ 34 FPGA发送一帧串口数据(考虑波特率) 如果 图 2‑34 考虑 115200 的波特率,结果如 图 2‑34 所示,每一位数据都保持 434 个时钟 ,为此 Verilog 可以这样表示,如 代码 2‑11 所示: 代码 2 ‑ 11
1.reg [10:0]D1; 2.reg [8:0]C1; 3.always @( posedge CLOCK) 4. case( i) 5. 0,1,2,3,4,5,6,7,8,9,10: 6. if( C1 == 9’ d434 -1 ) begin C1 <= 9’ d0; i <= i + 1’ b1; endelse begin TXD <= D1[i]; C1 <= C1 + 1'b1; end 7....... 8.endcase |
如 代码 2‑11 所示,步骤 1~8 不再保持一个时钟,换之每个步骤都保持 434 个时钟,因 此每位 TXD 的发送数据也保持 8.68us。 除此此外,串口传输协议不仅可以自定义波特率,串口传输协议也可以自定义一帧数据的位宽,自定义内容如 表 2‑8 所示: 表 2 ‑ 8 自定义一帧数据
自定义数据位 |
自定义内容 |
数据位 |
5~9 |
校验位 |
有/无 |
停止位 |
1~2 |
如 表 2‑8 所示,可以自定义的数据其中便包含数据位,默认下为 1 字节,自定义内容则 是 5~9 位,校验位也可以设置为有或者无( 默认下是有),停止位也可以增至 2 位(默 认下是 1 位)。
![fb1420516966106421355ba1d118ae2d.png](https://i-blog.csdnimg.cn/blog_migrate/7272ed4ac201df093b5b6d8b3c7783da.png)
图 2 ‑ 35 TX 功能模块的建模图 如 图 2‑35 所示,该模块的左方有问答信号,还有 8 位的 iData,至于右方则是 TXD 顶 层信号。此外,一帧数据的波特率为 115200 bps。 代码 2 ‑ 12 TX 功能模块代码
1.//****************************************************************************// 2.//# @Author: 碎碎思 3.//# @Date: 2019-04-21 21:14:51 4.//# @Last Modified by: zlk 5.//# @WeChat Official Account: OpenFPGA 6.//# @Last Modified time: 2019-08-04 02:48:17 7.//# Description: 8.//# @Modification History: 2014-05-10 13:42:27 9.//# Date By Version Change Description: 10.//# ========================================================================= # 11.//# 2014-05-10 13:42:27 12.//# ========================================================================= # 13.//# | | # 14.//# | OpenFPGA | # 15.//****************************************************************************// 16.module tx_funcmod 17.( 18. input CLOCK, RESET, 19. output TXD, 20. input iCall, 21. output oDone, 22. input [7:0]iData 23.); 24. parameter B115K2 = 9'd434; // formula : ( 1/115200 )/( 1/50E+6 ) 25. 26. reg [3:0]i; 27. reg [8:0]C1; 28. reg [10:0]D1; 29. reg rTXD; 30. reg isDone; 31. 32. always @( posedge CLOCK or negedge RESET ) 33. if( !RESET ) 34. begin 35. i <= 4'd0; 36. C1 <= 9'd0; 37. D1 <= 11'd0; 38. rTXD <= 1'b1; 39. isDone <= 1'b0; 40. end 41. else if( iCall ) 42. case( i ) 43. 44. 0: 45. begin D1 <= { 2'b11 , iData , 1'b0 }; i <= i + 1'b1 |