1. 程式人生 > 其它 >匯流排通訊協議-UART

匯流排通訊協議-UART

技術標籤:verilog 程式設計題

目錄

1. 簡介

UART:universal asynchronous receiver and transmitter通用非同步收發器,序列介面,適用於速度較慢的點對點通訊場景,由於是非同步通訊,沒有時鐘訊號,因此需要收發雙方的波特率相同、
USART:universal synchronous asynchronous receiver and transmitter通用同步/非同步收/發器,是UART的升級版,可以進行同步通訊

1.1 特點

非同步,序列介面,速度較慢,20Kbps,可以實現全雙工傳輸和接收

1.2. 介面

tx:傳送資料線
rx:接受資料線
一般還會加上VCC和GND
1對1傳輸,所以不用傳輸地址,I2C是要傳輸地址的,PSI由於有片選訊號,所以也不用傳輸地址。

2. 傳輸協議

預設:高電平
起始:1bit/低電平
資料:8bit
校驗位:1bit; 奇校驗表示資料中1的個數為奇數,則校驗位為0,如果為偶數,那麼校驗位為1,也就是說資料碼+校驗位共有奇數個1.
終止位 : 1bit/ 高電平

2.1 傳輸時序圖

TX:
image.png

2.2 模組實現

傳送模組

module tx #(

	parameter DATA_WIDTH = 8,
	parameter ODD_EVEN = 0 // 0 stand for the even 
)(

	input wire [DATA_WIDTH-1 : 0] data_in,
	input wire data_vld,

	input wire sys_clk,
	input wire sys_rst_n,

	output reg data_out

);

parameter IDLE		= 5'b00001;
parameter START 	= 5'b00010;
parameter DATA_TRA 	= 5'b00100;
parameter CHECK 	= 5'b01000;
parameter STOP 		= 5'b10000;

reg [4:0] cur_state;
reg [4:0] nxt_state;

always_ff @(posedge sys_clk or negedge sys_rst_n) begin
	if (!sys_rst_n)
		cur_state <= IDLE;
	else
		cur_state <= nxt_state;
end 
reg [7:0] data_in_reg;
always_ff @(posedge sys_clk or negedge sys_rst_n) begin : proc_data_in_reg
	if(~sys_rst_n) begin
		data_in_reg <= 0;
	end else if (data_vld)begin
		data_in_reg <= data_in;
	end
end

reg [2:0] data_cnt;

always_latch begin
	nxt_state = IDLE;
	case (cur_state)
		IDLE :
			if (data_vld)
				nxt_state = START;
		START : 
			nxt_state = DATA_TRA;
		DATA_TRA : 
			if(data_cnt == DATA_WIDTH-1)
				nxt_state = CHECK;
			else
				nxt_state = DATA_TRA;
		CHECK :
			nxt_state = STOP;
		STOP :
			nxt_state = IDLE;
	endcase 
end

always_ff @(posedge sys_clk or negedge sys_rst_n) begin : proc_data_cnt
	if(~sys_rst_n) begin
		data_cnt <= 'd0;
	end else if (cur_state == DATA_TRA)begin
		data_cnt <= data_cnt + 1'b1;
	end else
		data_cnt <= 'd0;
end

reg check_tmp;
always_ff @(posedge sys_clk or negedge sys_rst_n) begin : proc_check_tmp
	if(~sys_rst_n) begin
		check_tmp <= 'b0;
	end else if (cur_state == DATA_TRA)begin
		check_tmp <= check_tmp + (data_in_reg >> data_cnt); //calculate the number of 1
	end else if (cur_state == STOP)
		check_tmp <= 'b0;
end

always_ff @(posedge sys_clk or negedge sys_rst_n) begin : proc_data_out
	if(~sys_rst_n) begin
		data_out <= 'b1;
	end else if (cur_state == START) begin
		data_out <= 'b0;
	end else if (cur_state == DATA_TRA ) begin
		data_out <= data_in_reg >> data_cnt;
	end else if (cur_state == CHECK) begin
		data_out <= check_tmp ^ ODD_EVEN;
	end else
		data_out <= 'b1;
end



endmodule

整個程式碼的狀態機就是根據時序圖得到的,因為一般傳輸協議的時序圖都代表著一定的順序關係,所以用狀態機實現是最方便的。

2.3 模組測試

module tb_tx();

parameter DATA_WIDTH = 8;
parameter ODD_EVEN = 0;

reg [DATA_WIDTH-1 : 0] data_in;
reg data_vld;

reg sys_clk, sys_rst_n;

wire data_out;


initial begin
	sys_clk = 'b0;
	sys_rst_n = 'b0;

	# 15 
	sys_rst_n = 'b1;
end

always #5 sys_clk = ~sys_clk;

initial begin
	data_vld = 'b0;
	data_in = 'd0;

	repeat(2)
		@ (posedge sys_clk) ;
	data_vld = 'b1;
	data_in = 'b10010001;

	@(posedge sys_clk) ;
	data_vld = 'b0;
	data_in = 'd0;

	#10000
	$finish;
end

tx tx_dut(
	data_in,
	data_vld,
	sys_clk,
	sys_rst_n,

	data_out
	);

	initial begin
		$fsdbDumpfile("tb_tx.fsdb");
		$fsdbDumpvars(0, tb_tx);
		$fsdbDumpon;
	end



endmodule

image.png
從波形圖可以看出,和我們的時序圖幾乎一致,開始,資料傳輸10001001, 奇偶校驗位:採用的是偶校驗,所以校驗位為1,結束高電平。

3. 小結

  1. URRT是非同步的,因為它沒有時鐘訊號作為基準,它以一個低電平作為開始訊號,因為Tx預設是拉高的,然後通過設定波特率讓接受方和傳送方同步。

參考連結:https://blog.csdn.net/z123canghai/article/details/88411302