------------Restore content start------------
Universal Asynchronous Receiver/Transmitter (UART) is an asynchronous transceiver, which converts parallel data into serial data for transmission when sending data, and converts the received serial data into parallel data when receiving data, which can realize full duplex transmission and reception. It includes RS232, RS449, RS423, RS422, RS485 and other interface standards and bus standards. In other words, UART is the general term of asynchronous serial communication. RS232, RS449, RS423, RS422 and RS485 are interface standards and bus standards corresponding to various asynchronous serial communication ports. They specify the electrical characteristics, transmission rate, connection characteristics and mechanical characteristics of the communication port.
Figure 1 # serial port transmission sequence diagram
Figure 2 logic block diagram of serial port transmission
Calculate the corresponding baud rate clock according to the selected baud rate. For example, the baud rate clock cycle corresponding to the baud rate of 115200 is 8680ns, and the clock timing number corresponding to the 50M clock is 433. Baud rate clock cycle timer is div_cnt. The baud rate clock counter is bps_cnt, record the number of baud rate clocks. send_en is the send flag, when send_en, start sending data according to bps_cnt. Since the serial port needs to be 1 before sending the protocol start bit, BPS_ When CNT = 0, uart_tx=1; bps_ When CNT = 1-10, uart_tx is equal to the start bit, data bit and stop bit in turn. In order to ensure that the stop bit maintains a high level of one bit, BPS_ When CNT = 11, uart_tx = 1, so bps_cnt circulates within 0-11, BPS_ Reset immediately when CNT = 11. To make send_ After the en signal appears, it can immediately start sending data and set Div_ Every time CNT is 0, bps_cnt is + 1. After ten bit data transmission is completed, TX_ Do pull up and send at the same time_ EN is pulled down and the flag is sent.
The serial port sending module is used to realize a counter that counts and adds 1 every 10ms. Counting starts from 0 and passes send_en and tx_done signal cooperation, when count_ When 10ms starts counting, send_ The en signal is pulled high until TX_ When the done signal comes, it is pulled down whenever TX_ When the done signal arrives, the timing number is + 1.
Serial port sending module code:
module urat_tx( input wire clk , input wire rstn , input wire [ 2:0] baudrate , input wire [ 7:0] data , input wire ena , output reg tx , output reg tx_done ); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++\ //++++++++++++++++ Parameter & Signal +++++++++++++++++ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++/ reg [ 12:0] baud_clock ; reg [ 12:0] div_cnt ; reg [ 3:0] bps_cnt ; //reg ena ; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++\ //++++++++++++++++ Main code ++++++++++++++++++++++++++ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++/ always @(*) begin //baudrate choose case (baudrate) 3'd0:baud_clock<=13'd433; 3'd1:baud_clock<=13'd867; 3'd2:baud_clock<=13'd1301; 3'd3:baud_clock<=13'd2603; 3'd4:baud_clock<=13'd5207; default: baud_clock<=13'd433; endcase end always @(posedge clk or negedge rstn) begin //div_cnt if(!rstn) div_cnt<=0; else if(ena)begin if(div_cnt==baud_clock) div_cnt<=0; else div_cnt<=div_cnt+1'b1; end else div_cnt<=0; end always @(posedge clk or negedge rstn) begin //bps_cnt if(!rstn) bps_cnt<=0; else if(ena)begin if(div_cnt==0) begin if(bps_cnt==11) bps_cnt<=0; else bps_cnt<=bps_cnt+1'b1; end end else bps_cnt<=0; end always @(posedge clk or negedge rstn) begin if(!rstn) tx<=0; else begin case (bps_cnt) 0:tx<=1; 1:tx<=0; 2:tx<=data[0]; 3:tx<=data[1]; 4:tx<=data[2]; 5:tx<=data[3]; 6:tx<=data[4]; 7:tx<=data[5]; 8:tx<=data[6]; 9:tx<=data[7]; 10:tx<=1; 11:tx<=1; default:tx<=1; endcase end end always @(posedge clk or negedge rstn) begin //tx_done if(!rstn) tx_done<=0; else if((bps_cnt==11)&&(div_cnt==1)) tx_done<=1; else tx_done<=0; end /*always @(posedge clk or negedge rstn) begin //ena if(!rstn) ena<=0; else if(bps_cnt==0) ena<=1; else if(tx_done) ena<=0; end*/ endmodule
Counter code every 10ms:
module uart_tx_count( clk, rstn, tx ); input clk ; input rstn ; output tx ; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++\ //++++++++++++++++ Parameter & Signal +++++++++++++++++ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++/ reg [ 7:0] data ; wire tx_done ; reg ena ; reg [ 18:0] count_10ms ; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++\ //++++++++++++++++ Main code ++++++++++++++++++++++++++ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++/ urat_tx urat_tx_inst( .clk (clk ), .rstn (rstn ), .baudrate (3'd0 ), .data (data ), .ena (ena ), .tx (tx ), .tx_done (tx_done ) ); always @(posedge clk or negedge rstn) begin //count_10ms if(!rstn) count_10ms<=0; else if(count_10ms==499999) count_10ms<=0; else count_10ms<=count_10ms+1'b1; end always @(posedge clk or negedge rstn) begin //ena if(!rstn) ena<=0; else if(count_10ms==1) ena<=1; else if(tx_done) ena<=0; end always @(posedge clk or negedge rstn) begin if(!rstn) data<=0; else if(tx_done) data<=data+1'b1; end endmodule
testbench Code:
`timescale 1ns / 1ns module urat_tx_count_tb(); reg clk; reg rstn; wire tx; uart_tx_count u_uart_tx_count( .clk (clk ), .rstn (rstn ), .tx (tx ) ); initial clk=1; always#10 clk=!clk; initial begin rstn=0; #201; rstn=1; #10000000; $stop; end endmodule
Vivado simulation results:
It can be seen that in the 10ms counting cycle, the ena signal is high only when the signal is transmitted, and the transmission end flag signal TX_ When done arrives, pull it down and add 1 to the count value.