UART即通用異步收發(fā)器,是一種通用串行數(shù)據(jù)總線,用于異步通信。該總線為雙向通信,可以實(shí)現(xiàn)數(shù)據(jù)的接收與發(fā)送。
在數(shù)據(jù)傳輸過程中,我們需要解釋一下串行通信。假設(shè)現(xiàn)在我們傳輸數(shù)據(jù)的雙方為A和B,每次傳輸8bit數(shù)據(jù),這8bit的數(shù)據(jù)在傳輸時(shí)按照A與B之間的連線分為串行通信和并行通信。串行通信即A與B之間僅有一根數(shù)據(jù)線,在傳輸數(shù)據(jù)時(shí)需要一次發(fā)送1bit,總共發(fā)送8次。并行通信即A與B之間有8根線,傳輸數(shù)據(jù)時(shí),將8bit數(shù)據(jù)通過8根線一起傳輸,這樣一次就可以全部傳輸完成。
數(shù)據(jù)傳輸時(shí),接收方和發(fā)送方使用的時(shí)鐘不是同一個(gè)時(shí)鐘域,這也就是異步傳輸。
在通信雙方傳輸數(shù)據(jù)之前,需要通過串口線進(jìn)行連接,然后再傳輸數(shù)據(jù),常用的串口線為DB9接口,但是由于這種接口體積大,不易攜帶等缺點(diǎn)而慢慢淘汰。我們?cè)贐04的開發(fā)板上使用到的是一個(gè)USB轉(zhuǎn)串口的芯片,這樣我們的MINI USB接口不僅可以給開發(fā)板供電,還可以進(jìn)行串口數(shù)據(jù)傳輸。芯片為CP2102(USB <-->UART(LVCMOS/LVTTL)),對(duì)于開發(fā)者來說,就不需要關(guān)注電平標(biāo)準(zhǔn)了。
芯片電路圖如圖所示:
在電路圖中我們可以發(fā)現(xiàn),串口接口只有兩根數(shù)據(jù)線,分別為RXD和TXD。那么在進(jìn)行通信之前,我們需要先了解一下串口的傳輸規(guī)則。
在發(fā)送者沒有發(fā)送數(shù)據(jù)時(shí),接收方如果一直接收數(shù)據(jù),那就會(huì)導(dǎo)致數(shù)據(jù)出錯(cuò),所以,接收方在接收數(shù)據(jù)時(shí)需要有標(biāo)志信號(hào),然后啟動(dòng)接收。在我們的串口協(xié)議中是這樣規(guī)定的:
1、空閑態(tài)數(shù)據(jù)線上為高電平。
2、發(fā)送數(shù)據(jù)時(shí),先發(fā)送起始位,邏輯電平為低。
3、起始位結(jié)束之后,發(fā)送8bit數(shù)據(jù),從低位開始傳輸。
4、數(shù)據(jù)傳輸完畢,是1bit的校驗(yàn)位,采用奇偶校驗(yàn)法。(可不使用)
5、停止位,為高電平,可以是1bit、1.5bit或者2bit。
那么我們清楚了數(shù)據(jù)傳輸規(guī)則之后,我們還需要明白一個(gè)內(nèi)容,那就是1bit數(shù)據(jù)的時(shí)間長度。在算這個(gè)時(shí)間之前,我們需要了解一下波特率。波特率的單位是bit/s,也就是1秒時(shí)間內(nèi),傳輸?shù)腷it數(shù)。我們串口常用的波特率有9600、14400、19200等等。這個(gè)波特率是傳輸數(shù)據(jù)的雙方,提前規(guī)定好的。那么在同一速度下傳輸數(shù)據(jù),就會(huì)簡(jiǎn)單很多。那么根據(jù)波特率我們可以計(jì)算出來1bit數(shù)據(jù)的時(shí)長為104166ns。在清楚這些之后,接下來我們做一個(gè)回環(huán)測(cè)試。
首先我們先新建一個(gè)工程:
選好代碼存放位置,修改工程名字為uart。
選擇我們的芯片型號(hào):XC7A35TFGG484-2。
新建好工程后,開始新建文件寫代碼。
點(diǎn)擊OK,頂層文件新建完成,后續(xù)各個(gè)模塊新建方式相同。接收代碼如下:
?
1 module uart_rx( 2 3 input wire clk, 4 input wire rst_n, 5 input wire RXD, 6 output reg [7:0] data, 7 output reg wr_en 8 ); 9 10 parameter t = 5208; 11 12 reg [14:0] cnt; 13 reg flag; 14 reg rxd_r, rxd_rr; 15 wire rx_en; 16 reg [3:0] num; 17 reg [7:0] data_r; 18 19 always @ (posedge clk) rxd_r <= RXD; 20 always @ (posedge clk) rxd_rr <= rxd_r; 21 22 assign rx_en = (~rxd_r) & rxd_rr; 23 24 always @ (posedge clk, negedge rst_n) 25 begin 26 if(rst_n == 1'b0) 27 cnt <= 15'd0; 28 else if(flag) 29 begin 30 if(cnt == t - 1) 31 cnt <= 15'd0; 32 else 33 cnt <= cnt + 1'b1; 34 end 35 else 36 cnt <= 15'd0; 37 end 38 39 always @ (posedge clk, negedge rst_n) 40 begin 41 if(rst_n == 1'b0) 42 flag <= 1'b0; 43 else if(rx_en) 44 flag <= 1'b1; 45 else if(num == 4'd10) 46 flag <= 1'b0; 47 else 48 flag <= flag; 49 end 50 51 always @ (posedge clk, negedge rst_n) 52 begin 53 if(rst_n == 1'b0) 54 num <= 4'd0; 55 else if(cnt == t / 2 - 1) 56 num <= num + 1'b1; 57 else if(num == 4'd10) 58 num <= 4'd0; 59 else 60 num <= num; 61 end 62 63 always @ (posedge clk, negedge rst_n) 64 begin 65 if(rst_n == 1'b0) 66 begin 67 data_r <= 8'd0; 68 data <= 8'd0; 69 end 70 else if(cnt == t / 2 - 1) 71 case(num) 72 4'd0 : ; 73 4'd1 : data_r[0] <= rxd_rr; 74 4'd2 : data_r[1] <= rxd_rr; 75 4'd3 : data_r[2] <= rxd_rr; 76 4'd4 : data_r[3] <= rxd_rr; 77 4'd5 : data_r[4] <= rxd_rr; 78 4'd6 : data_r[5] <= rxd_rr; 79 4'd7 : data_r[6] <= rxd_rr; 80 4'd8 : data_r[7] <= rxd_rr; 81 4'd9 : data <= data_r; 82 default : data <= data; 83 endcase 84 end 85 86 always @ (posedge clk, negedge rst_n) 87 begin 88 if(rst_n == 1'b0) 89 wr_en <= 1'b0; 90 else if(num == 4'd10) 91 wr_en <= 1'b1; 92 else 93 wr_en <= 1'b0; 94 end 95 96 endmodule
?
發(fā)送數(shù)據(jù)時(shí),跟接收基本類似,按照數(shù)據(jù)格式發(fā)送數(shù)據(jù),代碼如下:
?
1 module uart_tx( 2 3 input wire clk, 4 input wire rst_n, 5 input wire empty, 6 input wire [7:0] data, 7 output wire rd_en, 8 output reg TXD 9 ); 10 11 parameter t = 5208; 12 13 reg [14:0] cnt; 14 reg flag; 15 reg [3:0] num; 16 17 18 always @ (posedge clk, negedge rst_n) 19 begin 20 if(rst_n == 1'b0) 21 cnt <= 15'd0; 22 else if(flag) 23 begin 24 if(cnt == t - 1) 25 cnt <= 15'd0; 26 else 27 cnt <= cnt + 1'b1; 28 end 29 else 30 cnt <= 15'd0; 31 end 32 33 always @ (posedge clk, negedge rst_n) 34 begin 35 if(rst_n == 1'b0) 36 flag <= 1'b0; 37 else if(empty == 1'b0) 38 flag <= 1'b1; 39 else if(num == 4'd10) 40 flag <= 1'b0; 41 else 42 flag <= flag; 43 end 44 45 always @ (posedge clk, negedge rst_n) 46 begin 47 if(rst_n == 1'b0) 48 num <= 4'd0; 49 else if(cnt == t / 2 - 1) 50 num <= num + 1'b1; 51 else if(num == 4'd10) 52 num <= 4'd0; 53 else 54 num <= num; 55 end 56 57 assign rd_en = (num == 4'd0 && cnt == 15'd1) ? 1'b1 : 1'b0; 58 59 always @ (posedge clk, negedge rst_n) 60 begin 61 if(rst_n == 1'b0) 62 TXD <= 1'b1; 63 else if(cnt == t / 2 - 1) 64 case(num) 65 4'd0 : TXD <= 1'b0; 66 4'd1 : TXD <= data[0]; 67 4'd2 : TXD <= data[1]; 68 4'd3 : TXD <= data[2]; 69 4'd4 : TXD <= data[3]; 70 4'd5 : TXD <= data[4]; 71 4'd6 : TXD <= data[5]; 72 4'd7 : TXD <= data[6]; 73 4'd8 : TXD <= data[7]; 74 4'd9 : TXD <= 1'b1; 75 default : TXD <= 1'b1; 76 endcase 77 end 78 79 endmodule
?
其中讀使能我們只需在數(shù)據(jù)發(fā)送前將數(shù)據(jù)讀出即可。
在做完兩個(gè)模塊之后,我們還需要使用一個(gè)FIFO來做數(shù)據(jù)緩存,F(xiàn)IFO配置參數(shù)如下:
我們使用異步FIFO,深度選擇2048,位寬為8,復(fù)位信號(hào)暫時(shí)不使用。
生成FIFO后,將各個(gè)模塊例化到頂層當(dāng)中,代碼如下:
?
1 module uart( 2 3 input wire clk, 4 input wire rst_n, 5 input wire RXD, 6 output wire TXD 7 ); 8 9 wire [7:0] rx_data; 10 wire wr_en; 11 wire rd_en; 12 wire [7:0] tx_data; 13 wire empty; 14 15 uart_rx uart_rx_inst( 16 17 .clk (clk ), 18 .rst_n (rst_n), 19 .RXD (RXD ), 20 .data (rx_data), 21 .wr_en (wr_en) 22 ); 23 24 fifo fifo_inst ( 25 .wr_clk(clk), // input wire wr_clk 26 .rd_clk(clk), // input wire rd_clk 27 .din(rx_data), // input wire [7 : 0] din 28 .wr_en(wr_en), // input wire wr_en 29 .rd_en(rd_en), // input wire rd_en 30 .dout(tx_data), // output wire [7 : 0] dout 31 .full(), // output wire full 32 .empty(empty) // output wire empty 33 ); 34 35 uart_tx uart_tx_inst( 36 37 .clk (clk ), 38 .rst_n (rst_n ), 39 .empty (empty ), 40 .data (tx_data), 41 .rd_en (rd_en ), 42 .TXD (TXD ) 43 ); 44 45 endmodule
?
功能部分寫完之后,我們寫一個(gè)仿真進(jìn)行邏輯驗(yàn)證,寫仿真時(shí),我們按照數(shù)據(jù)順序模擬給值,每1bit持續(xù)104166ns的時(shí)間。代碼如下:
?
1 `timescale 1ns / 1ps 2 3 module uart_tb; 4 5 reg clk; 6 reg rst_n; 7 reg RXD; 8 wire TXD; 9 10 initial begin 11 clk = 0; 12 rst_n = 0; 13 RXD = 1; 14 #105; 15 rst_n = 1; 16 17 #1000; 18 RXD = 0; 19 #104166; 20 21 RXD = 1; 22 #104166; 23 RXD = 0; 24 #104166; 25 RXD = 1; 26 #104166; 27 RXD = 0; 28 #104166; 29 RXD = 1; 30 #104166; 31 RXD = 0; 32 #104166; 33 RXD = 0; 34 #104166; 35 RXD = 1; 36 #104166; 37 38 RXD = 1; 39 #104166; 40 41 #5000; 42 $stop; 43 end 44 45 always #10 clk = ~clk; 46 47 uart uart_inst( 48 49 .clk (clk ), 50 .rst_n (rst_n ), 51 .RXD (RXD ), 52 .TXD (TXD ) 53 ); 54 55 endmodule
?
打開仿真波形:
如圖,我們可以看到,當(dāng)我們的接收模塊接收到數(shù)據(jù)時(shí),會(huì)將數(shù)據(jù)寫入FIFO,F(xiàn)IFO中有數(shù)據(jù)時(shí),發(fā)送模塊就會(huì)將數(shù)據(jù)讀出并發(fā)送,仿真現(xiàn)象正確。
下板現(xiàn)象:
我們隨便寫入幾個(gè)數(shù)據(jù),會(huì)發(fā)現(xiàn)我們的發(fā)送模塊和接收模塊的數(shù)據(jù)完全一致,即接收和發(fā)送正常。
審核編輯:劉清
評(píng)論
查看更多