前言????????
????????UART(通用異步收發傳輸器)是一種串行通信協議,用于在電子設備之間進行數據傳輸。RS232是UART協議的一種常見實現標準,廣泛應用于計算機和外圍設備之間的通信。它定義了串行數據的傳輸格式和電氣特性,以確保不同設備之間的兼容性和可靠性。RS232協議采用異步串行通信方式,通過數據線將并行數據轉換為串行數據進行傳輸,接收端再將串行數據恢復為并行數據。RS232的標準包括信號電平、連接器類型和數據格式等規范,確保了設備之間的正確通信。它的常見應用包括計算機串口、調制解調器、打印機等設備的連接。
????????UART通信實現與驗證(RS232)
正文
一、UART雙向通信實現(序列機)的設計驗證
? ? ? ? 1.項目需求
????????完成9600波特率串口的數據收發實驗
? ? ? ? 2.技術介紹
????????采用序列機架構,使用鎖相環產生一個16倍9600波特率的時鐘,當該時鐘計數到16時,表示串口數據發送的1bit數據傳輸完成(即1bit數據在計數0時放置與txd數據線上,在16時完成該數據傳輸,下次計數0時傳輸下1bit數據)。為保證數據接收正常,數據接收需要在9600波特率的時鐘的周期中心接收,對應16倍時鐘,在計數器到7或8的時刻進行數據接收。
? ? ? ? 為完成數據收發實驗,將接收的數據在發送出去,完成數據回環,可以通過上位機去觀察接收的數據是否完整以此驗證實驗成功。
? ? ? ? 涉及到數據傳遞,雖然時鐘相同但是正常情況需要進行數據緩存(建議,如果是異步時鐘,必須進行數據緩存),常用的數據緩存有異步fifo,雙口ram(本實驗實驗異步fifo)
? ? ? ? 3.頂層架構
????????
? ? ? ? 4.端口描述
clk | 時鐘接口(50Mhz) |
rst_n | 復位按鍵(低電平有效) |
rxd | 數據接收接口 |
txd | 數據發送接口 |
二、代碼驗證
頂層連線
module uart_tx_rx(input clk ,input rst_n ,input rxd ,output txd
);wire clk_01536;wire rst_en;clk_uart clk_uart_inst (.areset ( ~rst_n ),.inclk0 ( clk ),.c0 ( clk_01536 ),.locked ( rst_en ));wire[7:0]data,q_sig;wire rdempty,rdreq,down;uart_rx rx(.clk (clk_01536 ),.rst_n (rst_en ),.rxd (rxd ),//數據接收.data (data ),//接收數據打包.down (down ) //輸出有效);fifo fifo_inst (.data (data ),.rdclk (clk_01536 ),.rdreq (rdreq ),.wrclk (clk_01536 ),.wrreq (down ),.q (q_sig ),.rdempty (rdempty ),.wrfull ( ));uart_txd_v1 tx(.clk (clk_01536 ),.rst_n (rst_en ),.data (q_sig ),.done (rdempty ),.txd (txd ),.rd_en (rdreq ));
endmodule
收數據模塊
module uart_rx(input clk ,input rst_n ,input rxd ,//數據接收output reg[7:0]data ,//接收數據打包output reg down //輸出有效
);reg state;reg [7:0]temp;reg [7:0]cnt;always@(posedge clk,negedge rst_n)//cnt在工作狀態計數beginif(!rst_n)cnt <= 0;else if(state == 1)cnt <= cnt + 1;elsecnt <= 0;endalways@(posedge clk,negedge rst_n)beginif(!rst_n)state <= 0;elsecase(state)0: if(rxd == 0)//等待起始信號state <= 1;elsestate <= 0;1: if(cnt == 153)//完成一包數據接收state <= 0;elsestate <= 1;default:state <= 0;endcaseendalways@(posedge clk,negedge rst_n)beginif(!rst_n)begintemp <= 0;down <= 0;data <= 0;endelsecase(cnt)0:begintemp <= 0;down <= 0;data <= data;end1*16+7:temp[0] <= rxd;//在每個時序的中間收數據,數據在N*16時放在rxd上,保證數據穩定,在N*16 + 7時讀2*16+7:temp[1] <= rxd;3*16+7:temp[2] <= rxd;4*16+7:temp[3] <= rxd;5*16+7:temp[4] <= rxd;6*16+7:temp[5] <= rxd;7*16+7:temp[6] <= rxd;8*16+7:temp[7] <= rxd;9*16+7:begindown <= 1;data <= temp;end9*16+7+1:down <= 0;endcaseendendmodule
發數據模塊
module uart_txd(//fifo不為空時發input clk ,//0.1536 = 9600 * 16 = 153600hz = 0.1536Mhz input rst_n ,input [7:0] data ,input done ,output reg txd ,output reg rd_en
);reg [7:0]temp;reg [7:0]cnt;reg state;always@(posedge clk,negedge rst_n)//計數器在工作時進行計數beginif(!rst_n)cnt <= 0;else if(state == 1)//fifo不空,開始發送if(cnt < 10*16)cnt <= cnt + 1;elsecnt <= 0;elsecnt <= 0;endalways@(posedge clk,negedge rst_n)beginif(!rst_n)state <= 0;else case(state)0: if(done == 0)state <= 1;elsestate <= 0;1: if(cnt == 10*16)state <= 0;elsestate <= 1;default:state <= 0;endcaseendalways@(posedge clk,negedge rst_n)beginif(!rst_n)rd_en <= 0;elsecase(cnt)0:rd_en <= 0;1:rd_en <= 1;2:rd_en <= 0;endcaseendalways@(posedge clk,negedge rst_n)beginif(!rst_n)txd <= 1;elsecase(cnt)0:txd <= 1;1:txd <= 0;//起始位3:temp <= data;1*16:txd <= temp[0];//數據在時序開始時放在txd,2*16:txd <= temp[1];3*16:txd <= temp[2];4*16:txd <= temp[3];5*16:txd <= temp[4];6*16:txd <= temp[5];7*16:txd <= temp[6];8*16:txd <= temp[7];9*16:txd <= 1;endcaseendendmodule