UART(通用異步收發器)是廣泛使用的串行數據傳輸協議。UART允許在串行鏈路上進行全雙工的通信。專用的UART集成電路如8250,8251,NS16450等已經相當復雜,有些含有許多輔助的模塊(如FIF0),在實際應用中,往往只需要用到UART的幾個基本功能,使用專用芯片會造成資源浪費和成本提高,我們可以將所需要的UART功能集成到FPGA內部,從而簡化了整個系統電路,提高了可靠性、穩定性和靈活性。
l 、UART簡介
基本的UART通信只需要兩條信號線(RXD,TXD)就可以完成數據的相互通信,接收與發送是全雙工形式,其中TXD是UART發送端,RXD是UART接收端。UART的基本特點是:在信號線上有2種狀態,可分別用邏輯1(高電平)和邏輯0(低電平)來區分。在發送器空閑時,數據線應保持在邏輯高電平狀態。發送器是通過發送起始位而開始一個字符傳送,起始位使數據線處于邏輯0狀態,提示接收器數據傳輸即將開始。數據位一般為8位一個字節的數據(也有6位、7位的情況),低位(LSB)在前,高位(MSB)在后。校驗位一般用來判斷接收的數據位有無錯誤,一般是奇偶校驗。停止位在最后,用以標志一個字符傳送的結束,它對應于邏輯1狀態。UART數據幀格式如表1所示。
2 、UART功能實現
基于FPGA的UART由3個子模塊組成:波特率發生器模塊;發送模塊;接收模塊。
2.1 波特率發生器模塊
波特率發生器實際上就是一個分頻器。波特率發生器的功能是產生和RS-232通信所采用的波特率同步的時鐘,這樣才能按照RS-232串行通信的時序要求進行數據接收或發送。實現波特率時鐘的基本思路就是設計一個計數器,該計數器工作在速度很高的系統時鐘下,當計數到某數值時將輸出置為高電平,再計數一定數值后將輸出置為低電平,如此反復就能得到所需的波特率時鐘。例如FPGA的系統時鐘為50MHz,RS-232通信的波特率為9600,則波特率時鐘的每個周期約相當于5208個系統時鐘的周期。假如要得到占空比為50%的波特率時鐘,只要使計數器在計數到5208 50%=2604時將輸出置為高電平,之后在計數到5208時輸出低電平并重新計數,就能得到和9600波特率同步的時鐘。
波特率發生器VHDL實現的關鍵代碼如下:
entity baud is
Port (clk,resetb:in std_logic;
bclk:out std_logic);
end baud;
architecture Behavioral of baud is
begin
process(clk,resetb)
variable cnt:integer;
begin
if resetb=‘1’ then cnt:=0; bclk《=‘0’; --復位
elsif rising_edge(clk) then
if cnt》=208 then cnt:=0; bclk《=‘1’; --設置分頻系數
else cnt:=cnt+1; bclk《=‘0’;
end if;
end if;
end process;
end Behavioral;
2.2 發送模塊
在發數據寄存器被寫入一幀數據之后,發送過程被啟動。發送過程啟動后,發送串行移位寄存器被啟動。同時發送使能標志被清空。首先發送的是起始位,同時啟動發數據計算器,記錄發送數據的個數。根據工作模式寄存器的要求,將要發送的一幀數據串行發送出去,如果需要校驗,則產生校驗位并發送出去。最后需要發送的是停止位,根據停止位個數的要求,發送停止位。最后設置發送完畢標志位。圖2為發送模塊狀態機示意圖。
圖2 發送狀態機示意圖
發送模塊VHDL程序關鍵代碼如下:
architecture Behavioral of transfer is
type states is (x_idle,x_start,x_wait,x_shift,x_stop); --定義各子狀態
signal state:states:=x_idle;
signal tcnt:integer:=0;
begin
process(bclkt,resett,xmit_cmd_p,txdbuf) --主控時序、組合進程
variable xcnt16:std_logic_vector(4 downto 0):=“00000”; --定義中間變量
variable xbitcnt:integer:=0;
variable txds:std_logic;
begin
if resett=‘1’ then state《=x_idle; txd_done《=‘0’; txds:=‘1’; --復位
elsif rising_edge(bclkt) then
case state is
when x_idle=》 --狀態1,等待數據幀發送命令
if xmit_cmd_p=‘1’ then state《=x_start; txd_done《=‘0’;
else state《=x_idle;
end if;
when x_start=》 --狀態2,發送信號至起始位
if xcnt16》=“01111” then state《=x_wait; xcnt16:=“00000”;
else xcnt16:=xcnt16+1; txds:=‘0’; state《=x_start;
end if;
when x_wait=》 --狀態3,等待狀態
if xcnt16》=“01110” then
if xbitcnt=framlent then state《=x_stop; xbitcnt:=0;
else state《=x_shift;
end if;
xcnt16:=“00000”;
else xcnt16:=xcnt16+1; state《=x_wait;
end if;
when x_shift=》txds:=txdbuf(xbitcnt); xbitcnt:=xbitcnt+1; state《=x_wait; --狀態4,將待發數據進行并串轉換
when x_stop=》 --狀態5,停止位發送狀態
if xcnt16》=“01111” then
if xmit_cmd_p=‘0’ then state《=x_idle; xcnt16:=“00000”;
else xcnt16:=xcnt16; state《=x_stop;
end if; txd_done《=‘1’;
else xcnt16:=xcnt16+1; txds:=‘1’; state《=x_stop;
end if;
when others=》state《=x_idle;
end case;
end if;
txd《=txds;
end process;
end Behavioral;
UART發送器的仿真波形如圖3所示。
2.3 接收模塊
在接收數據寄存器被讀出一幀數據或系統開始工作之后,接收過程被啟動。接收過程啟動之后,等待檢測起始位。檢測到有效的起始位后,根據高于數據速率的時鐘同步開始接收數據。根據數據位數的設定,計數器統計接收位數。一幀數據接收完畢之后,如果使用校驗位,則檢測校驗位,否則接收停止位。停止位接收完畢,則設定接收狀態寄存器中接收完畢寄存器,同時產生接收中斷,通知控制器讀取。接收狀態機的實現與發送部分類似,限于篇幅,在這里不再敘述。
在具體實現接收部分電路的時候,我們采用的是基于高速多倍率采樣的方法。比如將采樣速率設置在三倍信息速率上,就是以三倍于波特率的頻率對接收引腳Rx進行采樣,這樣既保證檢測到“起始位”,又可以調整采樣的時間間隔。將有效數據位的采樣點控制在碼元的中間1/3處,最大限度地減少誤碼,提高接收的準確性。圖4是該方法的示意圖,在圖中為了分析方便,將起始位和部分數據位放大,把每個信息位分為三等份,每等份的時間寬度設為TS 。以三倍頻對信息位進行采樣時,每個信息位都將可能被采樣到三次。當處于空閑狀態并檢測起始位時,盡管每次具體的采樣點會在S0區。檢測到起始位低電平后,間隔4×TS時間,正好是第一位數據位的中間1/3部分S1區,即箭頭所指部位。此后的數據位、校驗位和停止位的采樣間隔都是3×TS,當所有采樣點均落在碼元的中間1/3部分時,采樣數據最可靠。
3 、結束語
用FPGA實現UART功能,可以減小系統的面積,降低系統的功耗,提高系統的穩定性,這種硬件軟件化的方法已經成為當今電子設計領域中的主導趨勢。在實際應用中,我們將文中實現的UART電路作為一個功能塊嵌入到一個FPGA實現的數據采集與處理系統中,成功地實現了和遠端PC機間的異步串行通信。實驗證明了該UART電路設計簡單、工作穩定。
本文作者創新觀點:本文將UART系統結構進行了模塊化分解,使之適應自頂向下的設計方法,并采用狀態機對核心電路部分進行了描述,使控制邏輯直觀簡單,大幅度提高了設計效率,特別是對接收電路采用了高速多倍率采樣法進行實現,降低了誤碼率,使采樣數據更為可靠。
責任編輯:gt
評論
查看更多