通用异步收发传输器(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
回环测试效果: