通用異步收發傳輸器(Universal Asynchronous Receiver/Transmitter),通常稱作UATR,是一種異步收發傳輸器。將數據由串行通信與並行通信間做傳輸轉換,作為並行輸入稱為串行輸出的芯片。UART是一種通用串行數據總線,用於異步通信。該總線雙向通信,可以實現全雙工傳輸和接收。
異步串行通信數據格式
UART作為異步串口通信協議的一種,工作原理是將傳輸數據的每個字符一位接一位地傳輸。其中各位的意義如下:
1、起始位:先發出一個邏輯”0”的信號,表示傳輸字符的開始。
2、數據位:起始位之后。資料位的個數可以是4、5、6、7、8等,構成一個字符。通常采用ASCII碼。從最低位開始傳送,靠時鍾定位。
3、奇偶校驗位:資料位加上這一位后,使得“1”的位數應為偶數(偶校驗)或奇數(奇校驗),以此來校驗資料傳送的正確性。
4、停止位:它是一個字符數據的結束標志。可以是1位、1.5位、2位的高電平。 由於數據是在傳輸線上定時的,並且每一個設備有其自己的時鍾,很可能在通信中兩台設備間出現了小小的不同步。因此停止位不僅僅是表示傳輸的結束,並且提供計算機校正時鍾同步的機會。適用於停止位的位數越多,不同時鍾同步的容忍程度越大,但是數據傳輸率同時也越慢。
5、空閑位:處於邏輯“1”狀態,表示當前線路上沒有數據傳輸。
發送一個字節數據的時序圖
波特率(Baud):是指從一設備發到另一設備的波特率,即每秒鍾可以通信的數據比特個數。典型的波特率有300, 1200, 2400, 9600, 19200, 115200等。一般通信兩端設備都要設為相同的波特率,但有些設備也可設置為自動檢測波特率。
假設需要的波特率為9600bps,那么波特率時鍾周期約為 104167ns,板載時鍾頻率為50MHz,周期為20ns,要計數到104167ns,需要5208個板載時鍾周期。
發送模塊的代碼:

1 module UART_TX( 2 clk, 3 rst_n, 4 5 send_en, 6 tx_done, 7 8 data_in, 9 10 uart_tx 11 ); 12 13 input clk; 14 input rst_n; 15 input[7:0] data_in; // 輸入數據 16 input send_en; // 發送使能 17 18 output reg tx_done; // 發送完成標志信號 19 output reg uart_tx; // 目標信號輸出 20 21 reg[15:0] bps_cnt; // 波特率計數寄存器 22 reg[3:0] lsm_cnt; // 序列機計數 23 reg flag; // 發送標志信號 24 25 always@(posedge clk or negedge rst_n) // flag 信號設計 26 if(!rst_n) 27 flag <= 1'b0; 28 else if(send_en) // 檢測到 發送使能信號,則flag信號拉高 29 flag <= 1'b1; 30 else if(lsm_cnt == 10) // 發送完一個字節后,flag信號拉低 31 flag <= 1'b0; 32 33 always@(posedge clk or negedge rst_n) // bps_cnt 信號設計 34 if(!rst_n) 35 bps_cnt <= 16'd0; 36 else if(flag) begin 37 if(bps_cnt == 5207) //從0開始計數,計數到5207后停止計數,則計數5208次 38 bps_cnt <= 16'd0; 39 else 40 bps_cnt <= bps_cnt + 1'b1; 41 end 42 else 43 bps_cnt <= 16'd0; 44 45 always@(posedge clk or negedge rst_n) // lsm_cnt 信號設計 46 if(!rst_n) 47 lsm_cnt <= 4'd0; 48 else if(bps_cnt == 5207) // 在 bps_cnt == 5207 時,則剛好計數滿9600bps的一個周期 49 lsm_cnt <= lsm_cnt + 1'b1; 50 else if(lsm_cnt == 10) 51 lsm_cnt <= 4'd0; 52 53 always@(posedge clk or negedge rst_n) // 信號轉換 54 if(!rst_n) 55 uart_tx <= 1'b1; 56 else if(flag) begin 57 case(lsm_cnt) 58 0 : uart_tx <= 1'b0; //起始位 59 1 : uart_tx <= data_in[0]; 60 2 : uart_tx <= data_in[1]; 61 3 : uart_tx <= data_in[2]; 62 4 : uart_tx <= data_in[3]; 63 5 : uart_tx <= data_in[4]; 64 6 : uart_tx <= data_in[5]; 65 7 : uart_tx <= data_in[6]; 66 8 : uart_tx <= data_in[7]; 67 9 : uart_tx <= 1'b1; //停止位 68 default: uart_tx <= 1'b1; 69 endcase 70 end 71 else 72 uart_tx <= 1'b1; 73 74 always@(posedge clk or negedge rst_n) // tx_done 信號設計 75 if(!rst_n) 76 tx_done <= 1'b0; 77 else if(flag && lsm_cnt == 10) // 發送完一個字節數據后拉高tx_done信號 78 tx_done <= 1'b1; 79 else 80 tx_done <= 1'b0; 81 82 endmodule
testbench代碼:

1 `timescale 1ns/1ps 2 module UART_TX_tb; 3 reg clk; 4 reg rst_n; 5 reg send_en; 6 7 reg[7:0] data_in; 8 9 wire uart_tx; 10 wire tx_done; 11 12 UART_TX_TEST u0( 13 .clk(clk), 14 .rst_n(rst_n), 15 .send_en(send_en), 16 .tx_done(tx_done), 17 18 .data_in(data_in), 19 .uart_tx(uart_tx) 20 ); 21 22 initial 23 clk = 0; 24 always #10 clk = ~clk; 25 26 initial 27 begin 28 rst_n = 1'b0; 29 data_in = 8'd0; 30 send_en = 1'b0; 31 #21; 32 33 rst_n = 1'b1; 34 #1000; 35 data_in = 8'haa; 36 send_en = 1'b1; 37 #20; 38 send_en = 1'b0; 39 @(posedge tx_done) 40 41 #1000000; 42 data_in = 8'h55; 43 send_en = 1'b1; 44 #20; 45 send_en = 1'b0; 46 @(posedge tx_done) 47 48 #1000000; 49 $stop; 50 end 51 endmodule
2020.04.28
修訂版代碼:
發送模塊:uart_tx

1 // Time : 2020.04.23 2 // Describe : uart_tx 3 4 module uart_tx( 5 input clk, 6 input rst_n, 7 8 input send_en, 9 input [7:0] data_in, 10 11 output reg rs232_tx 12 ); 13 14 localparam BAUD_END = 5207; 15 16 localparam BAUD_M = BAUD_END/2 - 1; 17 localparam BIT_END = 8; 18 19 reg [7:0] data_in_r; 20 reg [12:0] baud_cnt; 21 reg tx_flag; 22 reg bit_flag; 23 reg [3:0] bit_cnt; 24 25 always@(posedge clk or negedge rst_n) begin 26 if(!rst_n) 27 data_in_r <= 8'd0; 28 else if(send_en == 1'b1 ) // tx_flag == 1'b0 && tx_flag == 1'b1 29 data_in_r <= data_in; 30 end 31 32 always@(posedge clk or negedge rst_n) begin 33 if(!rst_n) 34 tx_flag <= 1'b0; 35 else if(send_en == 1'b1) 36 tx_flag <= 1'b1; 37 else if(bit_cnt == BIT_END && bit_flag == 1'b1) 38 tx_flag <= 1'b0; 39 end 40 41 always@(posedge clk or negedge rst_n) begin 42 if(!rst_n) 43 baud_cnt <= 13'd0; 44 else if(baud_cnt == BAUD_END) 45 baud_cnt <= 13'd0; 46 else if(tx_flag == 1'b1) 47 baud_cnt <= baud_cnt + 1'b1; 48 else 49 baud_cnt <= 13'd0; 50 end 51 52 always@(posedge clk or negedge rst_n) begin 53 if(!rst_n) 54 bit_flag <= 1'b0; 55 else if(baud_cnt == BAUD_END) 56 bit_flag <= 1'b1; 57 else 58 bit_flag <= 1'b0; 59 end 60 61 always@(posedge clk or negedge rst_n) begin 62 if(!rst_n) 63 bit_cnt <= 4'd0; 64 else if(bit_flag == 1'b1 && bit_cnt == BIT_END) 65 bit_cnt <= 4'd0; 66 else if(bit_flag == 1'b1) 67 bit_cnt <= bit_cnt + 1'b1; 68 end 69 70 always@(posedge clk or negedge rst_n) begin 71 if(!rst_n) 72 rs232_tx <= 1'b1; 73 else if(tx_flag == 1'b1) 74 case(bit_cnt) 75 0: rs232_tx <= 1'b0; 76 1: rs232_tx <= data_in_r[0]; 77 2: rs232_tx <= data_in_r[1]; 78 3: rs232_tx <= data_in_r[2]; 79 4: rs232_tx <= data_in_r[3]; 80 5: rs232_tx <= data_in_r[4]; 81 6: rs232_tx <= data_in_r[5]; 82 7: rs232_tx <= data_in_r[6]; 83 8: rs232_tx <= data_in_r[7]; 84 default: rs232_tx <= 1'b1; 85 endcase 86 else 87 rs232_tx <= 1'b1; 88 end 89 90 endmodule
發送模塊Modelsim仿真代碼:

1 `timescale 1ns/1ns 2 module uart_tx_tb; 3 reg clk; 4 reg rst_n; 5 6 reg send_en; 7 reg [7:0] data_in; 8 9 wire rs232_tx; 10 11 uart_tx u0( 12 .clk(clk), 13 .rst_n(rst_n), 14 15 .send_en(send_en), 16 .data_in(data_in), 17 18 .rs232_tx(rs232_tx) 19 20 ); 21 22 initial 23 clk = 1'b1; 24 always #10 clk = ~clk; 25 26 initial 27 begin 28 rst_n = 1'b0; 29 data_in = 8'd0; 30 send_en = 1'b0; 31 #100; 32 33 rst_n = 1'b1; 34 #100; 35 send_en = 1'b1; 36 data_in = 8'h55; 37 #20; 38 send_en = 1'b0; 39 40 #1000000; 41 $stop; 42 43 end 44 45 endmodule
發送模塊仿真截圖:
接收模塊:uart_rx

1 // Time : 2020.04.22 2 // Describe : uart_rx 3 4 module uart_rx( 5 input clk, 6 input rst_n, 7 8 input rs232_rx, 9 10 output reg rx_done, 11 output reg[7:0] data_out 12 ); 13 14 localparam BAUD_END = 5207; 15 localparam BAUD_M = BAUD_END/2 - 1; 16 localparam BIT_END = 8; 17 18 reg rx_r1,rx_r2,rx_r3; 19 reg rx_flag; 20 21 reg bit_flag; 22 23 reg [12:0] baud_cnt; 24 reg [3:0] bit_cnt; 25 26 wire rx_neg; 27 28 assign rx_neg = ~rx_r2 & rx_r3; // 檢測rs232_rx的下降沿 29 30 always@(posedge clk) begin 31 rx_r1 <= rs232_rx; 32 rx_r2 <= rx_r1; 33 rx_r3 <= rx_r2; 34 end 35 36 always@(posedge clk or negedge rst_n) begin 37 if(!rst_n) 38 rx_flag <= 1'b0; 39 else if(rx_neg == 1'b1) 40 rx_flag <= 1'b1; 41 else if(bit_cnt == 4'd0 && baud_cnt == BAUD_END) 42 rx_flag <= 1'b0; 43 end 44 45 always@(posedge clk or negedge rst_n) begin 46 if(!rst_n) 47 baud_cnt <= 13'd0; 48 else if(baud_cnt == BAUD_END) 49 baud_cnt <= 13'd0; 50 else if(rx_flag == 1'b1) 51 baud_cnt <= baud_cnt + 1'b1; 52 else 53 baud_cnt <= 13'd0; 54 end 55 56 always@(posedge clk or negedge rst_n) begin 57 if(!rst_n) 58 bit_flag <= 1'b0; 59 else if(baud_cnt == BAUD_M) 60 bit_flag <= 1'b1; 61 else 62 bit_flag <= 1'b0; 63 end 64 65 always@(posedge clk or negedge rst_n) begin 66 if(!rst_n) 67 bit_cnt <= 4'd0; 68 else if(bit_flag == 1'b1 && bit_cnt == BIT_END) 69 bit_cnt <= 4'd0; 70 else if(bit_flag == 1'b1) 71 bit_cnt <= bit_cnt + 1'b1; 72 end 73 74 always@(posedge clk or negedge rst_n) begin 75 if(!rst_n) 76 data_out <= 8'd0; 77 else if(bit_flag == 1'b1 && bit_cnt >= 4'd1) 78 data_out <= {rx_r2,data_out[7:1]}; 79 end 80 81 always@(posedge clk or negedge rst_n) begin 82 if(!rst_n) 83 rx_done <= 1'b0; 84 else if(bit_cnt == BIT_END && bit_flag == 1'b1) 85 rx_done <= 1'b1; 86 else 87 rx_done <= 1'b0; 88 end 89 90 endmodule
接收模塊Modelsim仿真代碼:

1 `timescale 1ns/1ns 2 module uart_rx_tb; 3 reg clk; 4 reg rst_n; 5 6 reg rs232_rx; 7 8 wire rx_done; 9 wire[7:0] data_out; 10 11 reg send_en; 12 reg [7:0] data_in; 13 wire rs232_tx; 14 15 uart_tx uart_tx_inst( 16 .clk(clk), 17 .rst_n(rst_n), 18 .send_en(send_en), 19 .data_in(data_in), 20 .rs232_tx(rs232_tx) 21 ); 22 23 uart_rx uart_rx_inst( 24 .clk(clk), 25 .rst_n(rst_n), 26 .rs232_rx(rs232_tx), 27 .rx_done(rx_done), 28 .data_out(data_out) 29 ); 30 31 initial 32 clk = 1'b0; 33 always #10 clk = ~clk; 34 35 initial 36 begin 37 send_en = 1'b0; 38 data_in = 8'h0; 39 rst_n = 1'b0; 40 #100; 41 rst_n = 1'b1; 42 43 #100; 44 send_en = 1'b1; 45 data_in = 8'h55; 46 #20; 47 48 #1000000; 49 50 $stop; 51 52 end 53 endmodule 54

回環測試代碼:

1 module uart_loop( 2 input clk, 3 input rst_n, 4 input rs232_rx, 5 6 output rs232_tx 7 ); 8 9 wire en; 10 wire[7:0] data; 11 12 uart_tx u0( 13 .clk (clk ), 14 .rst_n (rst_n ), 15 .send_en (en ), 16 .data_in ( data ), 17 .rs232_tx (rs232_tx ) 18 ); 19 20 uart_rx u1( 21 .clk (clk ), 22 .rst_n (rst_n ), 23 .rs232_rx (rs232_rx ), 24 .rx_done (en ), 25 .data_out ( data ) 26 ); 27 28 endmodule
回環測試效果: