刘 博
(航空工业集团公司洛阳电光设备研究所,河南 洛阳 471000)
在计算机通信过程中,如果计算机与外设直接相连,它们之间的信息交换会存在不匹配的问题,表现在速度、信息类型和数据格式等方面[1]。为解决这个问题,需要设计一个信息交换的中间接口。通用异步收发器(Universal Asynchronous Receiver/Transmitter,UART)就是其中一个常用的物理接口,用于计算机与鼠标、打印机等串行外设或其他使用串行协议的设备之间的信息交换。
UART接口在计算机和外设的通信中完成两方面的工作:① 电路板的工作电平和串口电平的转换,功能实现采用的专用芯片有MAX232等;② 通信过程中计算机的并行数据和外设的串行数据的转换,专用芯片有8250和8251等。
随着对不同型号飞机产品上的电路板研究工作的深入,发现UART接口功能的实现方法也有了转变。带有80C186处理器的电路板,其串口通信往往通过8251A/B芯片来实现,随着航空电子技术的发展,电路板的集成度越来越高,电路板上BGA器件越来越多,串口通信功能的实现多是将UART模块集成在CPU里面,8251系列芯片在这些电路板上不再出现[2]。选择专门的UART芯片,如8250、8251等来进行串口通信,往往只用到这些芯片的基本功能,使用这些芯片会造成很大的资源浪费,而且芯片的数据传输速率慢并有不可移值的特点[3]。而选择集成有UART模块的处理器,不但简化了电路,还在一定程度上增加了系统的可靠性与稳定性。
本文探讨的内容更进一层,现阶段FPGA在电路板上的应用越来越广泛,与其他数字系统的串行通信需求也在增加[4]。虽然大部分处理器集成了UART模块,而多数FPGA芯片不具备这个特点。通过硬件描述语言将UART的功能集成在FPGA上,将方便后续FPGA与处理器或者其他设备的串口通信[5]。
异步通信传输的帧格式一般为起始位1位,数据位为5~8位,奇偶校验位可选奇校验、偶校验或无校验,停止位为1位、1.5位或2位[5]。UART的数据帧格式如图1所示。
为了加快开发进程,本文没有设置奇偶校验位。采用的数据帧格式为1位起始位,8位数据位,无奇偶校验位,1位停止位。通信接口标准选择RS-232,全双工通信方式,波特率设置为9 600 bps。在整体设计中,采用自顶向下的设计方法设计接收器模块、发送器模块以及波特率模块[6]。
图1 UART数据帧格式
顶层模块设计在整个模块化设计中起着关键作用,需要设计者对设计总体进行综合与布局,充分发挥模块化设计的优势。顶层设计实现了串口收发通信功能,这其中不包含任何逻辑设计,将会方便以后进行维护和移植操作[7]。
顶层模块Verilog主要代码及注释如下:
module UART(
input clk, ∥50 MHz
input rst_n,∥低电平复位信号
input uart_rx,∥串口接收端
output uart_tx∥串口发送端
);
wire[7:0] rx_data_sig;
wire rx_flag_sig;
UART_RXUART_RX_Inst(
.clk(clk),∥50 MHz
.rst_n(rst_n),∥低电平复位信号
.uart_rx(uart_rx),∥串口接收端
.rx_data(rx_data_sig),∥串口接收到的一字节数据
.rx_flag(rx_flag_sig)∥接收数据中断信号,接收数据期间始终为高电平
);
regen_tx;
reg[7:0]tx_data_reg;
wire en_tx_sig=en_tx;
wire[7:0] tx_data_sig=tx_data_reg;
wire tx_flag_sig;
UART_TXUART_TX_Inst(
.clk(clk),∥50 MHz
.rst_n(rst_n),∥低电平复位信号
.en_tx(en_tx_sig),∥使能串口发送,高有效
.tx_data(tx_data_sig),∥串口发送的一字节数据
.uart_tx(uart_tx),∥串口发送端
.tx_flag(tx_flag_sig)∥串口发送标志位,串口在发送期间一直为高电平
);
……
endmodule
波特率是每秒传输二进制代码的位数,是数据传送速率的一种度量,单位为bps。假设一个字符是10位(包含1个起始位、8个数据位和1个停止位),每秒传送960个字符,那么波特率就是:10位×960个/s=9 600 bps。异步串行通信中波特率通常设置为9 600 bps、19 200 bps和38 400 bps等。
设计波特率时钟的基本思路就是设计一个计数器[8]。设计时首先设定好波特率,电路板上的晶振频率CLK是已知量,需要算出分频因子。这里将分频因子设为BPS_PARA,计算公式为:
波特率分频因子BPS_PARA=CLK/波特率。
(1)
为保证在每位数据传输的中间时刻采样,根据分频因子,设计占空比为50%的采样时钟[9]。具体做法为计数到BPS_PARA/2时输出高电平,再计数到BPS_PARA/2时输出低电平。
本文系统时钟为50 MHz,要求波特率是9 600 bps,则波特率分频因子BPS_PARA=50 M/9 600=5 208,则计数器取5 208/2=2 604时,计数器溢出时输出电平取反就可以得到约定波特率时钟。
波特率模块Verilog主要代码及注释如下:
module Baud_Rate_Generator(
input clk,∥50 MHz
input rst_n,∥低电平复位信号
input start,∥波特率使能信号
output reg sampling_clk∥数据采样时钟
);
Define BPS_PARA5208∥波特率为9600 bps时的分频因子
Define BPS_PARA_22604∥波特率为9600 bps时的分频因子值的一半,采样数据点
reg[12:0] cnt;
/*设置使能信号,已知波特率和系统时钟,设计波特率时钟*/
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt <=′d0;
else if((cnt==′BPS_PARA)||!start)
cnt <=′d0;
else
cnt <= cnt+1′b1;∥
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
sampling_clk <=1′b0;
else if(cnt==BPS_PARA_2)
sampling_clk <=1′b1;
else sampling_clk <=1′b0;
end
endmodule
接收模块的设计方法是当检测到数据帧的起始位时,使能波特率发生器和移位寄存器,开始采集数据,接着对接收的数据进行串并转换,最后按照时序将寄存器中的数据输出[10]。
设计的重点是检测数据帧的起始位。通常情况下每一帧的数据传送之前,传输线处于逻辑高电平状态,为“1”,一旦检测变为“0”时,可视为一帧数据起始位的到来。然而,通信线上的噪音也极有可能使逻辑1跳变到逻辑0,这样就不能保证通信双方交换信息的准确性。本文采用下降沿的检测来滤掉通信线上噪音的干扰[11]。设置了neg_uart_rx对发送器数据由1跳变0的情况进行检测,确定输入由1到0,经过8个sampling_clk周期,才认为是正常的起始位,而不是噪音引起的。捕捉到起始位后,将neg_uart_rx置1。
采到正确的起始位后,开始接收数据,当采样计数器计数结束后所有数据位都已经输入完成。程序中设置接收数据标志位rx_flag,接收数据期间rx_flag始终为高电平,一帧数据接收完成后,rx_flag置低,数据转存到数据寄存器rx_data [7:0]中以便输出。
接收器模块部分Verilog代码及注释如下:
module UART_RX(
input clk,∥50 MHz
input rst_n,∥低电平复位信号
input uart_rx,∥串口接收端
output reg[7:0] rx_data,∥串口接收到的一字节数据
output reg rx_flag∥接收数据标志位,接收时高电平,接收完毕低电平
);
reg[3:0] num;∥移位次数
reg[7:0] rx_data_temp;∥当前接收数据寄存器
reg uart_rx0,uart_rx1,uart_rx2,uart_rx3;∥接收数据寄存器,滤波用
reg start_bps;∥接收到数据后,波特率时钟启动信号置位
wire start_bps_sig=start_bps;
wiresampling_clk; ∥数据采样时钟
/*滤掉通信信号线上的噪音*/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
uart_rx0 <=1′b0;
uart_rx1 <=1′b0;
uart_rx2 <=1′b0;
uart_rx3 <=1′b0;
end
else
begin
uart_rx0 <=uart_rx;
uart_rx1 <=uart_rx0;
uart_rx2 <=uart_rx1;
uart_rx3 <=uart_rx2;
end
end
∥数据线接收到下降沿时,neg_uart_rx为一个时钟周期的高电平
wire neg_uart_rx=uart_rx3 & uart_rx2 & ~uart_rx1 & ~uart_rx0;
/*接收数据控制和数据接收部分*/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
start_bps <=1′b0;
rx_flag <=1′b0;
end
else if(neg_uart_rx)∥检测uart_rx的下降沿信号
begin
start_bps <=1′b1;
rx_flag <=1′b1;∥开始接收数据
end
else if(num==′d10) ∥一个字符接收完成
begin
start_bps <=1′b0;
rx_flag <=1′b0;∥数据接收完毕
end
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
num <=4′d0;
rx_data<=′dz;
rx_data_temp <=′d0;
end
else if(rx_flag) ∥接收数据处理
begin
if(sampling_clk)
begin∥读取并保存数据,接收数据为1位起始位,8位数据位,1个结束位
num <= num+1′b1;
case (num)
′d1: rx_data_temp[0] <=uart_rx;
′d2: rx_data_temp[1] <=uart_rx;
′d3: rx_data_temp[2] <=uart_rx;
′d4: rx_data_temp[3] <=uart_rx;
′d5: rx_data_temp[4] <=uart_rx;
′d6: rx_data_temp[5] <=uart_rx;
′d7: rx_data_temp[6] <=uart_rx;
′d8: rx_data_temp[7] <=uart_rx;
default: ;
endcase
end
else if(num ==′d10)
begin
num <=′d0;
rx_data <= rx_data_temp;∥把数据锁存到数据寄存器rx_data中
end
end
end
endmodule
UART发送器的工作过程与接收器的工作过程相反,它将8位数据进行并行到串行的转换,同时加载上起始位和停止位,数据加载完成后重置波特率发生器,移位寄存器每隔一个发送周期按照帧格式及速率输出数据[12]。
在本程序中tx_data[7:0]就是要发送出去的并行数据。接收到数据时,发送标志位tx_flag为逻辑高电平状态,数据接收完成后,tx_flag置为低电平,启动串口发送端uart_tx发送相应的串行数据。
发送器模块部分Verilog主要代码及注释如下:
module UART_TX(
input clk,∥50 MHz
input rst_n,∥低电平复位信号
input en_tx,∥使能串口发送,高有效
input[7:0] tx_data,∥串口发送的一字节数据
output reg uart_tx,∥串口发送端
output reg tx_flag∥串口发送标志位,串口在发送期间一直为高电平
);
reg[7:0] tx_data_temp;∥待发送数据的寄存器
reg start_tx;∥发送数据使能信号,高有效
reg[3:0] num;∥移位次数
regstart_bps;∥波特率时钟启动信号置位
wire start_bps_sig=start_bps;
wire sampling_clk; ∥数据采样时钟
/*控制发送和更新发送数据*/
always@(en_tx or rst_n)
begin
if(!rst_n)
begin
start_bps <=1′b0;
start_tx<=1′b0;
tx_data_temp <=8′d0;
end
else if(en_tx==1′b1)∥使能串口发送
begin
start_bps<=1′b1;∥开启波特率采样
start_tx<=1′b1;∥开启发送
tx_data_temp <=tx_data; ∥把接收到的数据存入发送数据寄存器
end
else
begin
start_bps <=1′b0;
start_tx<=1′b0;
tx_data_temp <=tx_data; ∥把接收到的数据存入发送数据寄存器
end
end
/*发送数据*/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
num <=′d0;
uart_tx <=1′b1;
tx_flag <=1′b0;
end
else if(start_tx)
begin
if(num < 4′d11)
begin
tx_flag <=1′b1;∥进入发送数据状态中
if(sampling_clk)
begin
num <= num+1′b1;
case(num)
4′d0: uart_tx <=1′b0;
4′d1: uart_tx <=tx_data[0];
4′d2: uart_tx <=tx_data[1];
4′d3: uart_tx <=tx_data[2];
4′d4:uart_tx <=tx_data[3];
4′d5: uart_tx <=tx_data[4];
4′d6: uart_tx <=tx_data[5];
4′d7:uart_tx <=tx_data[6];
4′d8:uart_tx <=tx_data[7];
4′d9: uart_tx <=1′b1;
default: uart_tx <=1′b1;
endcase
end
end
else if(num==4′d11)
tx_flag<=1′b0;∥从低位到高位发送结束
end
else
num<=4′d0;∥复位
end
endmodule
一般时序仿真是必选步骤,它是在QuartusⅡ中通过综合、布局布线,将各种延时信息考虑在内后进行的仿真,能够验证逻辑代码的时序情况及实际电路的运行情况,保证设计的可靠性[13]。本文采用仿真软件为ModelSim,QuartusⅡ开发软件给其预留了接口,发送/接收数据时UART仿真波形图如图2和图3所示。
图2 发送器模块的时序仿真
图3 接收器模块的时序仿真
从图2可以看出,tx_data是将要发送出去的并行数据,uart_tx是发送出去的串行数据。当前要发送的数据序列为53H(01010011b)。由起始位开始发送,信息数据位由低位到高位逐位进行发送,采集完成8位数据位之后,就进行停止位的采集,停止位为1。可以看到uart_tx的输出波形为:起始位为0,数据位为“1”“1”“0”“0”“1”“0”“1”“0”,停止位为“1”。说明发送器模块的设计正确。
从图3可以看出,uart_rx是待接收的串行数据,tx_data是接收到的并行数据。系统复位后,首先检测起始位,对uart_rx进行下降沿的检测,检测到下降沿,并经过8个sampling_clk时钟采样周期后,表明起始位到来,开始接收数据,观察uart_rx波形,起始位为“0”,数据位由低位到高位,依次为“1”“0”“1”“1”“1”“0”“1”“1”,采集完成8位数据位之后,就进行停止位的采集,停止位为“1”。观察rx_data存储的并行数据为11011101b,证明接收器模块的设计正确。
经ModelSim仿真验证确认了UART功能模块设计无误后,还需将程序下载到电路板上的目标器件中进行硬件验证以作进一步的确认[14]。实验板上使用的是Cyclone系列EP2C5T144C8N芯片,配有复位按键、电源指示灯和LED控制灯,引入50 MHz的有源晶振,下载口使用AS配置口,供电电压为5 V,使用电脑的USB口供电。
使用Quartus Ⅱ软件将编译好的POF格式文件通过USB-Blaster下载到EP2C5T144C8N的配置芯片EPS4中。在本次板级验证中选用串口通信调试助手sscom3.2,如图4所示,设置波特率为9 600,数据位为8,停止位为1,校验位为none,流控制为none。在sscom3.2的字符输入框中输入53 4d,选择随机手动发送输入数据,可以发现窗口显示了所发送的有效数据53 4d,异步串行通信是正常的,证明本次模块设计是正确的。
图4 板级下载验证
本文采用Verilog HDL语言在FPGA上实现了UART的功能,可以有效地进行数据的接收和发送。用软件的方法实现了硬件的功能,有效地减少了系统的pcb面积,降低了系统的功耗,提高了设计的稳定性和可移植性。
[1]吴厚航.深入浅出玩转FPGA[M].北京:北京航空航天大学出版社,2010.
[2]贾亮,冀源.基于FPGA的串口通信控制器设计[J].微型机与应用,2016,35(22):33-35.
[3]董大成,张建东,史国庆.基于FPGA的UART IP核设计与实现[J].计算机测量与控制,2012,20(8):2251-2253.
[4]陈仁,王海英,华建文,等.基于FPGA的星载UART通讯设计与实现[J].科学技术与工程,2015,5(15):212-217.
[5]谢谢.基于FPGA的UART设计[J].电子设计工程,2016,20(16):51-53.
[6]王敬美,杨春玲.基于FPGA和UART的数据采集器设计[J].电子器件,2009,2(32):386-393.
[7]蒋艳红.基于FPGA的UART设计与应用[J].计算机工程,2008(21):225-229.
[8]周建华,万书芹,薛忠杰.一种新颖的UART自适应波特率发生器的设计[J].半导体技术,2007,12(32):1052-1054.
[9]李向军.一种变波特率异步串口通信电路设计[J].电声技术,2016,40(12):55-57.
[10] 杨宗国,李艳萍.基于FPGA的UART模块的设计[J].现代电子技术,2009(2):19-22.
[11] 李盛杰.UART测试技术研究[J].计算机与数字工程,2017,329(3):598-602.
[12] 韩德红,张显才,李向东.基于FPGA的串口控制器设计与实现[J].空军雷达学院学报,2008,22(2):113-116.
[13] 于斌,谢龙汉.ModelSim电子系统分析及仿真[M].北京:电子工业出版社,2014.
[14] 刘伟峰,庄奕琪,刘锋,等.高性能嵌入式UART IP核的设计[J].电子器件,2007,30(4):1275-1278.