UART(Universal Asynchronous Receiver Transmitter,通用异步收发器)是广泛使用的异步串行数据通信协议。下面首先介绍UART硬件接口及电平转换电路,分析UART的传输时序并利用Verilog HDL语言进行建模与仿真,最后通过开发板与PC相连进行RS-232通信来测试UART收发器的正确性。
1.5.1 11.5.1 UART界面介绍
本节所介绍的UART即美国电子工业协会定义的RS-232C,简称RS-232。RS-232的接口一般有9针的DB9和25针的DB25,这里以9针为例,它的各个引脚的定义如表11-8所示。 表11-8 DB9的引脚定义 引脚 资料载波检测功能 DCDRXDTXD缩写 123456789 数据接收 资料发送 资料终端准备DTR地 GNDDSRRTSCTS资料设备准备就绪 发送请求 清除发送 地 GND由于RS-232的电气特性与FPGA引脚不相同,因此它们之间不能直接相连,对于RS-232的数据线,当为逻辑“1”时,对应电平是-15V~-3V;当为逻辑“0”时,对应电平是15V~3V。因此,与FPGA相连之前必须进行电平转换,转换原理图如图11-39所示。
图11-39 RS-232电平转换原理图
1.5.2 11.5.2 UART传输时序
UART传输时序如图11-40所示。
T
图11-40 UART传输时序
发送数据过程:空闲状态,线路处于高电位;当收到发送数据指令后,拉低线路一个数据位的时间T,接着数据按低位到高位依次发送,数据发送完毕后,接着发送奇偶校验位和停止位(停止位为高电位),一帧资料发送结束。
接收数据过程:空闲状态,线路处于高电位;当检测到线路的下降沿(线路电位由高电位变为低电位)时说明线路有数据传输,按照约定的波特率从低位到高位接收数据,数据接收完毕后,接着接收并比较奇偶校验位是否正确,如果正确则通知后续设备准备接收数据或存入缓存。
由于UART是异步传输,没有传输同步时钟。为了能保证数据传输的正确性,UART采用16倍数据波特率的时钟进行采样。每个数据有16个时钟采样,取中间的采样值,以保证采样不会滑码或误码。一般UART一帧的数据位数为8,这样即使每个数据有一个时钟的误差,接收端也能正确地采样到数据。
UART的接收数据时序为:当检测到数据的下降沿时,表明线路上有数据进行传输,这时计数器CNT开始计数,当计数器为24=16+8时,采样的值为第0位数据;当计数器的值为40时,采样的值为第1位数据,依此类推,进行后面6个数据的采样。如果需要进行奇偶校验,则当计数器的值为152时,采样的值即为奇偶位;当计数器的值为168时,采样的值为“1”表示停止位,一帧数据接收完成。本节章将按上面的算法进行Verilog HDL语言建模与仿真。
1.5.3 11.5.3 UART分频器
假设数据的波特率为p,则所需时钟的频率为16*p。以波特率p为115200为例,系统时钟为50MHz,则分频系数为50000000/(16*115200) = 27.127,取整为27。分频器Verilog HDL语言代码如下:
module clkdiv(clk, clkout); input clk; //系统时钟 output clkout; //采样时钟输出 reg clkout; reg [15:0] cnt;
always @(posedge clk) //分频进程 begin
if(cnt == 16'd12) begin
clkout <= 1'b1; cnt <= cnt + 16'd1; end
else if(cnt == 16'd26) begin
clkout <= 1'b0; cnt <= 16'd0; end
else begin
cnt <= cnt + 16'd1; end end endmodule
保存文件为clkdiv.v,单击Files → Create/Update → Create Symbol Files for Current File命令,为clkdiv.v生成原理图模块。新建一个原理图文件,在原理图空白处双击,在弹出的Symbol对话框中选择Project → clkidv模块,单击OK按钮退出Symbol对话框。在原理图的适当位置放置clkdiv模块,并添加输入输出模块。保存原理图为uartrxtx.bdf。编译工程文件,编译无误后单击Processing → Generate Functional Simulation Netlist,产生功能仿真网表。新建波形仿真文件,加入输入输出信号,设置系统时钟信号clk的周期为20ns,保存波形文件为 uartrxtx.vwf,单击仿真,波形仿真报告如图11-41所示。
按钮进行分频器的波形
图11-41 分频器的波形仿真报告
波形仿真报告说明:
分频时钟输出实现了所需的27分频,分频模块得到正确验证。
1.5.4 11.5.4 UART发送模块
UART发送模块的功能:接收到发送指令后,把数据按UART协议输出,先输出一个低电平的起始位,然后从低到高输出8个数据位,接着是可选的奇偶校验位,最后是高电平的停止位。Verilog HDL语言代码如下:
module uarttx(clk, datain, wrsig, idle, tx); input clk; //UART时钟
input [7:0] datain; //需要发送的数据
input wrsig; //发送命令,上升沿有效
output idle; //线路状态指示,高为线路忙,低为线路空闲 output tx; //发送数据信号 reg idle, tx; reg send;
reg wrsigbuf, wrsigrise; reg presult;
reg[7:0] cnt; //计数器 parameter paritymode = 1'b0; //检测发送命令是否有效
always @(posedge clk) begin
wrsigbuf <= wrsig;
wrsigrise <= (~wrsigbuf) & wrsig; end
always @(posedge clk) begin
if (wrsigrise && (~idle)) //当发送命令有效且线路为空闲时,启动新的数据发送进程 begin
send <= 1'b1; end
else if(cnt == 8'd176) //一帧资料发送结束 begin
send <= 1'b0; end end
always @(posedge clk) begin
if(send == 1'b1) begin
case(cnt) //产生起始位 8'd0: begin
tx <= 1'b0; idle <= 1'b1;
cnt <= cnt + 8'd1; end 8'd16: begin
tx <= datain[0]; //发送数据0位 presult <= datain[0]^paritymode; idle <= 1'b1;
cnt <= cnt + 8'd1; end
8'd32: begin
tx <= datain[1]; //发送数据1位 presult <= datain[1]^presult; idle <= 1'b1;
cnt <= cnt + 8'd1; end 8'd48: begin
tx <= datain[2]; //发送数据2位 presult <= datain[2]^presult; idle <= 1'b1;
cnt <= cnt + 8'd1; end 8'd64: begin
tx <= datain[3]; //发送数据3位 presult <= datain[3]^presult; idle <= 1'b1;
cnt <= cnt + 8'd1; end 8'd80: begin
tx <= datain[4]; //发送数据4位 presult <= datain[4]^presult; idle <= 1'b1;
cnt <= cnt + 8'd1; end 8'd96: begin
tx <= datain[5]; //发送数据5位 presult <= datain[5]^presult; idle <= 1'b1;
cnt <= cnt + 8'd1; end 8'd112: begin
tx <= datain[6]; //发送数据6位 presult <= datain[6]^presult; idle <= 1'b1;
cnt <= cnt + 8'd1; end 8'd128: begin
tx <= datain[7]; //发送数据7位 presult <= datain[7]^presult; idle <= 1'b1;
cnt <= cnt + 8'd1; end 8'd144: begin
tx <= presult; //发送奇偶校验位 presult <= datain[0]^paritymode; idle <= 1'b1;
cnt <= cnt + 8'd1; end 8'd160: begin
tx <= 1'b1; //发送停止位 idle <= 1'b1;
cnt <= cnt + 8'd1; end 8'd176: begin
tx <= 1'b1;
idle <= 1'b0; //一帧资料发送结束 cnt <= cnt + 8'd1; end default: begin
cnt <= cnt + 8'd1; end endcase end else begin
tx <= 1'b1; cnt <= 8'd0; idle <= 1'b0; end end
endmodule
保存文件为uarttx.v,单击Files → Create/Update → Create Symbol Files for Current File命令,为uarttx.v生成原理图模块。为了测试UART发送模块的正确性,需要编写一个测试模块来测试UART发送模块,Verilog HDL语言代码如下:
module testuart(clk, dataout, wrsig); input clk;
output[7:0] dataout; output wrsig;
reg [7:0] dataout; reg wrsig; reg [7:0] cnt;
always @(posedge clk) begin
if(cnt == 254) begin
dataout <= dataout + 8'd1; //每次数据加“1” wrsig <= 1'b1; //产生发送命令 cnt <= 8'd0; end else begin
wrsig <= 1'b0;
cnt <= cnt + 8'd1; end end
endmodule
保存文件为testuart.v,单击Files → Create/Update → Create Symbol Files for Current File命令,为testuart.v生成原理图模块。新建一个原理图文件,在原理图空白处双击,在弹出的Symbol对话框中选择Project → testuart模块和uarttx模块,单击OK按钮退出Symbol对话框。在原理图的适当位置放置testuart模块和uarttx模块,并添加输入输出模块。为了仿真方便,把原来分频模块的分频系数更改为4,各个模块的连接如图11-42所示。
图11- 42 UART发送模块连接图
保存原理图为uartrxtx.bdf。编译工程文件,编译无误后单击Processing → Generate Functional Simulation Netlist,产生功能仿真网表。新建波形仿真文件,加入输入输出信号,设置系统时钟信号clk的周期为20ns,保存波形文件为uartrxtx.vwf,单击报告如图11-43所示。
按钮进行UART数据发送的波形仿真,波形仿真
图11-43 UART发送模块的波形仿真报告
波形仿真报告说明:
对图11-43分析看出,当发送命令wrsig的上升沿有效时,启动发送数据。串行数据的波形与发送数据dataout相一致,UART的发送模块得到正确验证。
1.5.5 11.5.5 UART接收模块
UART接收模块的功能:时时检测线路,当线路产生下降沿时,即认为线路有数据传输,启动接收数据进程进行接收,按从低位到高位接收数据。UART接收模块的Verilog HDL语言代码如下:
module uartrx(clk, rx, dataout, rdsig, dataerror, frameerror); input clk; //采样时钟
input rx; //UART数据输入 output dataout; //接收数据输出 output rdsig;
output dataerror; //资料出错指示 output frameerror; //帧出错指示
reg[7:0] dataout; reg rdsig, dataerror; reg frameerror; reg [7:0] cnt;
reg rxbuf, rxfall, receive;
parameter paritymode = 1'b0; reg presult, idle;
always @(posedge clk) //检测线路的下降沿
begin
rxbuf <= rx;
rxfall <= rxbuf & (~rx); end
always @(posedge clk) begin
if (rxfall && (~idle)) //检测到线路的下降沿并且原先线路为空闲,启动接收数据进程 begin
receive <= 1'b1; end
else if(cnt == 8'd175) //接收数据完成 begin
receive <= 1'b0; end end
always @(posedge clk) begin
if(receive == 1'b1) begin
case (cnt) 8'd0: begin
idle <= 1'b1;
cnt <= cnt + 8'd1; rdsig <= 1'b0; end
8'd24: //接收第0位数据 begin
idle <= 1'b1;
dataout[0] <= rx;
presult <= paritymode^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end
8'd40: //接收第1位数据 begin
idle <= 1'b1;
dataout[1] <= rx;
presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end
8'd56: //接收第2位数据 begin
idle <= 1'b1;
dataout[2] <= rx;
presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end
8'd72: //接收第3位数据 begin
idle <= 1'b1;
dataout[3] <= rx;
presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end
8'd88: //接收第4位数据 begin
idle <= 1'b1;
dataout[4] <= rx;
presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end
8'd104: //接收第5位数据 begin
idle <= 1'b1;
dataout[5] <= rx;
presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0;
end
8'd120: //接收第6位数据 begin
idle <= 1'b1;
dataout[6] <= rx;
presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end
8'd136: //接收第7位数据 begin
idle <= 1'b1;
dataout[7] <= rx;
presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b1; end
8'd152: //接收奇偶校验位
begin
idle <= 1'b1; if(presult == rx) dataerror <= 1'b0; else
dataerror <= 1'b1; //如果奇偶校验位不对,表示数据出错 cnt <= cnt + 8'd1; rdsig <= 1'b1; end 8'd168: begin
idle <= 1'b1; if(1'b1 == rx)
frameerror <= 1'b0; else
frameerror <= 1'b1; //如果没有接收到停止位,表示帧出错 cnt <= cnt + 8'd1; rdsig <= 1'b1; end default: begin
cnt <= cnt + 8'd1; end endcase end else
begin
cnt <= 8'd0; idle <= 1'b0; rdsig <= 1'b0; end end
endmodule
保存文件为uartrx.v,单击Files → Create/Update → Create Symbol Files for Current File命令,为uartrx.v生成原理图模块。新建一个原理图文件,在原理图空白处双击,在弹出的Symbol对话框中选择Project → uartrx模块,单击OK按钮退出Symbol对话框。在原理图的适当位置放置uartrx模块,并添加输入输出模块,各个模块的连接如图11-44所示。
图11-44 UART 接收模块连接图
保存原理图为uartrxtx.bdf。编译工程文件,编译无误后单击Processing → Generate Functional Simulation Netlist,产生功能仿真网表。新建波形仿真文件,加入输入输出信号,设置系统时钟信号clk的周期为20ns,保存波形文件为 uartrxtx.vwf,单击真报告如图11-45所示。
按钮进行UART数据接收的波形仿真,波形仿
图11-45 UART接收模块的波形仿真报告
波形仿真报告说明:
对图11-45分析看出,UART接收模块接收到的数据与UART发送模块发送的数据相一至,每接收到一个数据都有一个读取数据指示rdisg,UART接收模块得到正确验证。
1.5.6 11.5.6 UART的硬件测试
为了测试UART与PC通信的正确性,本例测试方法是,PC将数据发送到FPGA,FPGA接收到数据再发送给PC。FPGA与PC通信模块连接原理图如图11-46所示。
图11-46 FPGA与PC通信模块连接原理图
根据PC的串口调试工具的设置,决定代码是否需要奇偶校验位,以及分频系数。分配FPGA引脚,编译工程,连接好开发板及下载线缆,接上电源,下载
配置FPGA,打开PC的串口调试工具,发送数据,观察接收到的数据,如图11-47所示。
图11-47 PC串口调试工具
PC串口调试工具中发送“verilog HDL”,同时接收窗口显示“verilog HDL”,说明FPGA的接收和发送模块与PC的通信正确。至此,UART收发器的验证全部完成。
因篇幅问题不能全部显示,请点此查看更多更全内容