劉 博
(航空工業集團公司洛陽電光設備研究所,河南 洛陽 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??梢钥吹絬art_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.