劉 博
(航空工業(yè)集團(tuán)公司洛陽(yáng)電光設(shè)備研究所,河南 洛陽(yáng) 471000)
在計(jì)算機(jī)通信過(guò)程中,如果計(jì)算機(jī)與外設(shè)直接相連,它們之間的信息交換會(huì)存在不匹配的問(wèn)題,表現(xiàn)在速度、信息類型和數(shù)據(jù)格式等方面[1]。為解決這個(gè)問(wèn)題,需要設(shè)計(jì)一個(gè)信息交換的中間接口。通用異步收發(fā)器(Universal Asynchronous Receiver/Transmitter,UART)就是其中一個(gè)常用的物理接口,用于計(jì)算機(jī)與鼠標(biāo)、打印機(jī)等串行外設(shè)或其他使用串行協(xié)議的設(shè)備之間的信息交換。
UART接口在計(jì)算機(jī)和外設(shè)的通信中完成兩方面的工作:① 電路板的工作電平和串口電平的轉(zhuǎn)換,功能實(shí)現(xiàn)采用的專用芯片有MAX232等;② 通信過(guò)程中計(jì)算機(jī)的并行數(shù)據(jù)和外設(shè)的串行數(shù)據(jù)的轉(zhuǎn)換,專用芯片有8250和8251等。
隨著對(duì)不同型號(hào)飛機(jī)產(chǎn)品上的電路板研究工作的深入,發(fā)現(xiàn)UART接口功能的實(shí)現(xiàn)方法也有了轉(zhuǎn)變。帶有80C186處理器的電路板,其串口通信往往通過(guò)8251A/B芯片來(lái)實(shí)現(xiàn),隨著航空電子技術(shù)的發(fā)展,電路板的集成度越來(lái)越高,電路板上BGA器件越來(lái)越多,串口通信功能的實(shí)現(xiàn)多是將UART模塊集成在CPU里面,8251系列芯片在這些電路板上不再出現(xiàn)[2]。選擇專門的UART芯片,如8250、8251等來(lái)進(jìn)行串口通信,往往只用到這些芯片的基本功能,使用這些芯片會(huì)造成很大的資源浪費(fèi),而且芯片的數(shù)據(jù)傳輸速率慢并有不可移值的特點(diǎn)[3]。而選擇集成有UART模塊的處理器,不但簡(jiǎn)化了電路,還在一定程度上增加了系統(tǒng)的可靠性與穩(wěn)定性。
本文探討的內(nèi)容更進(jìn)一層,現(xiàn)階段FPGA在電路板上的應(yīng)用越來(lái)越廣泛,與其他數(shù)字系統(tǒng)的串行通信需求也在增加[4]。雖然大部分處理器集成了UART模塊,而多數(shù)FPGA芯片不具備這個(gè)特點(diǎn)。通過(guò)硬件描述語(yǔ)言將UART的功能集成在FPGA上,將方便后續(xù)FPGA與處理器或者其他設(shè)備的串口通信[5]。
異步通信傳輸?shù)膸袷揭话銥槠鹗嘉?位,數(shù)據(jù)位為5~8位,奇偶校驗(yàn)位可選奇校驗(yàn)、偶校驗(yàn)或無(wú)校驗(yàn),停止位為1位、1.5位或2位[5]。UART的數(shù)據(jù)幀格式如圖1所示。
為了加快開(kāi)發(fā)進(jìn)程,本文沒(méi)有設(shè)置奇偶校驗(yàn)位。采用的數(shù)據(jù)幀格式為1位起始位,8位數(shù)據(jù)位,無(wú)奇偶校驗(yàn)位,1位停止位。通信接口標(biāo)準(zhǔn)選擇RS-232,全雙工通信方式,波特率設(shè)置為9 600 bps。在整體設(shè)計(jì)中,采用自頂向下的設(shè)計(jì)方法設(shè)計(jì)接收器模塊、發(fā)送器模塊以及波特率模塊[6]。
圖1 UART數(shù)據(jù)幀格式
頂層模塊設(shè)計(jì)在整個(gè)模塊化設(shè)計(jì)中起著關(guān)鍵作用,需要設(shè)計(jì)者對(duì)設(shè)計(jì)總體進(jìn)行綜合與布局,充分發(fā)揮模塊化設(shè)計(jì)的優(yōu)勢(shì)。頂層設(shè)計(jì)實(shí)現(xiàn)了串口收發(fā)通信功能,這其中不包含任何邏輯設(shè)計(jì),將會(huì)方便以后進(jìn)行維護(hù)和移植操作[7]。
頂層模塊Verilog主要代碼及注釋如下:
module UART(
input clk, ∥50 MHz
input rst_n,∥低電平復(fù)位信號(hào)
input uart_rx,∥串口接收端
output uart_tx∥串口發(fā)送端
);
wire[7:0] rx_data_sig;
wire rx_flag_sig;
UART_RXUART_RX_Inst(
.clk(clk),∥50 MHz
.rst_n(rst_n),∥低電平復(fù)位信號(hào)
.uart_rx(uart_rx),∥串口接收端
.rx_data(rx_data_sig),∥串口接收到的一字節(jié)數(shù)據(jù)
.rx_flag(rx_flag_sig)∥接收數(shù)據(jù)中斷信號(hào),接收數(shù)據(jù)期間始終為高電平
);
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),∥低電平復(fù)位信號(hào)
.en_tx(en_tx_sig),∥使能串口發(fā)送,高有效
.tx_data(tx_data_sig),∥串口發(fā)送的一字節(jié)數(shù)據(jù)
.uart_tx(uart_tx),∥串口發(fā)送端
.tx_flag(tx_flag_sig)∥串口發(fā)送標(biāo)志位,串口在發(fā)送期間一直為高電平
);
……
endmodule
波特率是每秒傳輸二進(jìn)制代碼的位數(shù),是數(shù)據(jù)傳送速率的一種度量,單位為bps。假設(shè)一個(gè)字符是10位(包含1個(gè)起始位、8個(gè)數(shù)據(jù)位和1個(gè)停止位),每秒傳送960個(gè)字符,那么波特率就是:10位×960個(gè)/s=9 600 bps。異步串行通信中波特率通常設(shè)置為9 600 bps、19 200 bps和38 400 bps等。
設(shè)計(jì)波特率時(shí)鐘的基本思路就是設(shè)計(jì)一個(gè)計(jì)數(shù)器[8]。設(shè)計(jì)時(shí)首先設(shè)定好波特率,電路板上的晶振頻率CLK是已知量,需要算出分頻因子。這里將分頻因子設(shè)為BPS_PARA,計(jì)算公式為:
波特率分頻因子BPS_PARA=CLK/波特率。
(1)
為保證在每位數(shù)據(jù)傳輸?shù)闹虚g時(shí)刻采樣,根據(jù)分頻因子,設(shè)計(jì)占空比為50%的采樣時(shí)鐘[9]。具體做法為計(jì)數(shù)到BPS_PARA/2時(shí)輸出高電平,再計(jì)數(shù)到BPS_PARA/2時(shí)輸出低電平。
本文系統(tǒng)時(shí)鐘為50 MHz,要求波特率是9 600 bps,則波特率分頻因子BPS_PARA=50 M/9 600=5 208,則計(jì)數(shù)器取5 208/2=2 604時(shí),計(jì)數(shù)器溢出時(shí)輸出電平取反就可以得到約定波特率時(shí)鐘。
波特率模塊Verilog主要代碼及注釋如下:
module Baud_Rate_Generator(
input clk,∥50 MHz
input rst_n,∥低電平復(fù)位信號(hào)
input start,∥波特率使能信號(hào)
output reg sampling_clk∥數(shù)據(jù)采樣時(shí)鐘
);
Define BPS_PARA5208∥波特率為9600 bps時(shí)的分頻因子
Define BPS_PARA_22604∥波特率為9600 bps時(shí)的分頻因子值的一半,采樣數(shù)據(jù)點(diǎn)
reg[12:0] cnt;
/*設(shè)置使能信號(hào),已知波特率和系統(tǒng)時(shí)鐘,設(shè)計(jì)波特率時(shí)鐘*/
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
接收模塊的設(shè)計(jì)方法是當(dāng)檢測(cè)到數(shù)據(jù)幀的起始位時(shí),使能波特率發(fā)生器和移位寄存器,開(kāi)始采集數(shù)據(jù),接著對(duì)接收的數(shù)據(jù)進(jìn)行串并轉(zhuǎn)換,最后按照時(shí)序?qū)⒓拇嫫髦械臄?shù)據(jù)輸出[10]。
設(shè)計(jì)的重點(diǎn)是檢測(cè)數(shù)據(jù)幀的起始位。通常情況下每一幀的數(shù)據(jù)傳送之前,傳輸線處于邏輯高電平狀態(tài),為“1”,一旦檢測(cè)變?yōu)椤?”時(shí),可視為一幀數(shù)據(jù)起始位的到來(lái)。然而,通信線上的噪音也極有可能使邏輯1跳變到邏輯0,這樣就不能保證通信雙方交換信息的準(zhǔn)確性。本文采用下降沿的檢測(cè)來(lái)濾掉通信線上噪音的干擾[11]。設(shè)置了neg_uart_rx對(duì)發(fā)送器數(shù)據(jù)由1跳變0的情況進(jìn)行檢測(cè),確定輸入由1到0,經(jīng)過(guò)8個(gè)sampling_clk周期,才認(rèn)為是正常的起始位,而不是噪音引起的。捕捉到起始位后,將neg_uart_rx置1。
采到正確的起始位后,開(kāi)始接收數(shù)據(jù),當(dāng)采樣計(jì)數(shù)器計(jì)數(shù)結(jié)束后所有數(shù)據(jù)位都已經(jīng)輸入完成。程序中設(shè)置接收數(shù)據(jù)標(biāo)志位rx_flag,接收數(shù)據(jù)期間rx_flag始終為高電平,一幀數(shù)據(jù)接收完成后,rx_flag置低,數(shù)據(jù)轉(zhuǎn)存到數(shù)據(jù)寄存器rx_data [7:0]中以便輸出。
接收器模塊部分Verilog代碼及注釋如下:
module UART_RX(
input clk,∥50 MHz
input rst_n,∥低電平復(fù)位信號(hào)
input uart_rx,∥串口接收端
output reg[7:0] rx_data,∥串口接收到的一字節(jié)數(shù)據(jù)
output reg rx_flag∥接收數(shù)據(jù)標(biāo)志位,接收時(shí)高電平,接收完畢低電平
);
reg[3:0] num;∥移位次數(shù)
reg[7:0] rx_data_temp;∥當(dāng)前接收數(shù)據(jù)寄存器
reg uart_rx0,uart_rx1,uart_rx2,uart_rx3;∥接收數(shù)據(jù)寄存器,濾波用
reg start_bps;∥接收到數(shù)據(jù)后,波特率時(shí)鐘啟動(dòng)信號(hào)置位
wire start_bps_sig=start_bps;
wiresampling_clk; ∥數(shù)據(jù)采樣時(shí)鐘
/*濾掉通信信號(hào)線上的噪音*/
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
∥數(shù)據(jù)線接收到下降沿時(shí),neg_uart_rx為一個(gè)時(shí)鐘周期的高電平
wire neg_uart_rx=uart_rx3 & uart_rx2 & ~uart_rx1 & ~uart_rx0;
/*接收數(shù)據(jù)控制和數(shù)據(jù)接收部分*/
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)∥檢測(cè)uart_rx的下降沿信號(hào)
begin
start_bps <=1′b1;
rx_flag <=1′b1;∥開(kāi)始接收數(shù)據(jù)
end
else if(num==′d10) ∥一個(gè)字符接收完成
begin
start_bps <=1′b0;
rx_flag <=1′b0;∥數(shù)據(jù)接收完畢
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) ∥接收數(shù)據(jù)處理
begin
if(sampling_clk)
begin∥讀取并保存數(shù)據(jù),接收數(shù)據(jù)為1位起始位,8位數(shù)據(jù)位,1個(gè)結(jié)束位
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;∥把數(shù)據(jù)鎖存到數(shù)據(jù)寄存器rx_data中
end
end
end
endmodule
UART發(fā)送器的工作過(guò)程與接收器的工作過(guò)程相反,它將8位數(shù)據(jù)進(jìn)行并行到串行的轉(zhuǎn)換,同時(shí)加載上起始位和停止位,數(shù)據(jù)加載完成后重置波特率發(fā)生器,移位寄存器每隔一個(gè)發(fā)送周期按照幀格式及速率輸出數(shù)據(jù)[12]。
在本程序中tx_data[7:0]就是要發(fā)送出去的并行數(shù)據(jù)。接收到數(shù)據(jù)時(shí),發(fā)送標(biāo)志位tx_flag為邏輯高電平狀態(tài),數(shù)據(jù)接收完成后,tx_flag置為低電平,啟動(dòng)串口發(fā)送端uart_tx發(fā)送相應(yīng)的串行數(shù)據(jù)。
發(fā)送器模塊部分Verilog主要代碼及注釋如下:
module UART_TX(
input clk,∥50 MHz
input rst_n,∥低電平復(fù)位信號(hào)
input en_tx,∥使能串口發(fā)送,高有效
input[7:0] tx_data,∥串口發(fā)送的一字節(jié)數(shù)據(jù)
output reg uart_tx,∥串口發(fā)送端
output reg tx_flag∥串口發(fā)送標(biāo)志位,串口在發(fā)送期間一直為高電平
);
reg[7:0] tx_data_temp;∥待發(fā)送數(shù)據(jù)的寄存器
reg start_tx;∥發(fā)送數(shù)據(jù)使能信號(hào),高有效
reg[3:0] num;∥移位次數(shù)
regstart_bps;∥波特率時(shí)鐘啟動(dòng)信號(hào)置位
wire start_bps_sig=start_bps;
wire sampling_clk; ∥數(shù)據(jù)采樣時(shí)鐘
/*控制發(fā)送和更新發(fā)送數(shù)據(jù)*/
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)∥使能串口發(fā)送
begin
start_bps<=1′b1;∥開(kāi)啟波特率采樣
start_tx<=1′b1;∥開(kāi)啟發(fā)送
tx_data_temp <=tx_data; ∥把接收到的數(shù)據(jù)存入發(fā)送數(shù)據(jù)寄存器
end
else
begin
start_bps <=1′b0;
start_tx<=1′b0;
tx_data_temp <=tx_data; ∥把接收到的數(shù)據(jù)存入發(fā)送數(shù)據(jù)寄存器
end
end
/*發(fā)送數(shù)據(jù)*/
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;∥進(jìn)入發(fā)送數(shù)據(jù)狀態(tài)中
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;∥從低位到高位發(fā)送結(jié)束
end
else
num<=4′d0;∥復(fù)位
end
endmodule
一般時(shí)序仿真是必選步驟,它是在QuartusⅡ中通過(guò)綜合、布局布線,將各種延時(shí)信息考慮在內(nèi)后進(jìn)行的仿真,能夠驗(yàn)證邏輯代碼的時(shí)序情況及實(shí)際電路的運(yùn)行情況,保證設(shè)計(jì)的可靠性[13]。本文采用仿真軟件為ModelSim,QuartusⅡ開(kāi)發(fā)軟件給其預(yù)留了接口,發(fā)送/接收數(shù)據(jù)時(shí)UART仿真波形圖如圖2和圖3所示。
圖2 發(fā)送器模塊的時(shí)序仿真
圖3 接收器模塊的時(shí)序仿真
從圖2可以看出,tx_data是將要發(fā)送出去的并行數(shù)據(jù),uart_tx是發(fā)送出去的串行數(shù)據(jù)。當(dāng)前要發(fā)送的數(shù)據(jù)序列為53H(01010011b)。由起始位開(kāi)始發(fā)送,信息數(shù)據(jù)位由低位到高位逐位進(jìn)行發(fā)送,采集完成8位數(shù)據(jù)位之后,就進(jìn)行停止位的采集,停止位為1??梢钥吹絬art_tx的輸出波形為:起始位為0,數(shù)據(jù)位為“1”“1”“0”“0”“1”“0”“1”“0”,停止位為“1”。說(shuō)明發(fā)送器模塊的設(shè)計(jì)正確。
從圖3可以看出,uart_rx是待接收的串行數(shù)據(jù),tx_data是接收到的并行數(shù)據(jù)。系統(tǒng)復(fù)位后,首先檢測(cè)起始位,對(duì)uart_rx進(jìn)行下降沿的檢測(cè),檢測(cè)到下降沿,并經(jīng)過(guò)8個(gè)sampling_clk時(shí)鐘采樣周期后,表明起始位到來(lái),開(kāi)始接收數(shù)據(jù),觀察uart_rx波形,起始位為“0”,數(shù)據(jù)位由低位到高位,依次為“1”“0”“1”“1”“1”“0”“1”“1”,采集完成8位數(shù)據(jù)位之后,就進(jìn)行停止位的采集,停止位為“1”。觀察rx_data存儲(chǔ)的并行數(shù)據(jù)為11011101b,證明接收器模塊的設(shè)計(jì)正確。
經(jīng)ModelSim仿真驗(yàn)證確認(rèn)了UART功能模塊設(shè)計(jì)無(wú)誤后,還需將程序下載到電路板上的目標(biāo)器件中進(jìn)行硬件驗(yàn)證以作進(jìn)一步的確認(rèn)[14]。實(shí)驗(yàn)板上使用的是Cyclone系列EP2C5T144C8N芯片,配有復(fù)位按鍵、電源指示燈和LED控制燈,引入50 MHz的有源晶振,下載口使用AS配置口,供電電壓為5 V,使用電腦的USB口供電。
使用Quartus Ⅱ軟件將編譯好的POF格式文件通過(guò)USB-Blaster下載到EP2C5T144C8N的配置芯片EPS4中。在本次板級(jí)驗(yàn)證中選用串口通信調(diào)試助手sscom3.2,如圖4所示,設(shè)置波特率為9 600,數(shù)據(jù)位為8,停止位為1,校驗(yàn)位為none,流控制為none。在sscom3.2的字符輸入框中輸入53 4d,選擇隨機(jī)手動(dòng)發(fā)送輸入數(shù)據(jù),可以發(fā)現(xiàn)窗口顯示了所發(fā)送的有效數(shù)據(jù)53 4d,異步串行通信是正常的,證明本次模塊設(shè)計(jì)是正確的。
圖4 板級(jí)下載驗(yàn)證
本文采用Verilog HDL語(yǔ)言在FPGA上實(shí)現(xiàn)了UART的功能,可以有效地進(jìn)行數(shù)據(jù)的接收和發(fā)送。用軟件的方法實(shí)現(xiàn)了硬件的功能,有效地減少了系統(tǒng)的pcb面積,降低了系統(tǒng)的功耗,提高了設(shè)計(jì)的穩(wěn)定性和可移植性。
[1]吳厚航.深入淺出玩轉(zhuǎn)FPGA[M].北京:北京航空航天大學(xué)出版社,2010.
[2]賈亮,冀源.基于FPGA的串口通信控制器設(shè)計(jì)[J].微型機(jī)與應(yīng)用,2016,35(22):33-35.
[3]董大成,張建東,史國(guó)慶.基于FPGA的UART IP核設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)測(cè)量與控制,2012,20(8):2251-2253.
[4]陳仁,王海英,華建文,等.基于FPGA的星載UART通訊設(shè)計(jì)與實(shí)現(xiàn)[J].科學(xué)技術(shù)與工程,2015,5(15):212-217.
[5]謝謝.基于FPGA的UART設(shè)計(jì)[J].電子設(shè)計(jì)工程,2016,20(16):51-53.
[6]王敬美,楊春玲.基于FPGA和UART的數(shù)據(jù)采集器設(shè)計(jì)[J].電子器件,2009,2(32):386-393.
[7]蔣艷紅.基于FPGA的UART設(shè)計(jì)與應(yīng)用[J].計(jì)算機(jī)工程,2008(21):225-229.
[8]周建華,萬(wàn)書(shū)芹,薛忠杰.一種新穎的UART自適應(yīng)波特率發(fā)生器的設(shè)計(jì)[J].半導(dǎo)體技術(shù),2007,12(32):1052-1054.
[9]李向軍.一種變波特率異步串口通信電路設(shè)計(jì)[J].電聲技術(shù),2016,40(12):55-57.
[10] 楊宗國(guó),李艷萍.基于FPGA的UART模塊的設(shè)計(jì)[J].現(xiàn)代電子技術(shù),2009(2):19-22.
[11] 李盛杰.UART測(cè)試技術(shù)研究[J].計(jì)算機(jī)與數(shù)字工程,2017,329(3):598-602.
[12] 韓德紅,張顯才,李向東.基于FPGA的串口控制器設(shè)計(jì)與實(shí)現(xiàn)[J].空軍雷達(dá)學(xué)院學(xué)報(bào),2008,22(2):113-116.
[13] 于斌,謝龍漢.ModelSim電子系統(tǒng)分析及仿真[M].北京:電子工業(yè)出版社,2014.
[14] 劉偉峰,莊奕琪,劉鋒,等.高性能嵌入式UART IP核的設(shè)計(jì)[J].電子器件,2007,30(4):1275-1278.