UART 协议

异步通信以一个字符为传输单位,通信中两个字符间的时间间隔多少是不固定的,然而在同一个字符中的两个相邻位间的时间间隔是固定的。
串行接口是一种可以将接受来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接受的串行数据流转换为并行的数据字符供给CPU的器件。
在这里插入图片描述
起始位:先发出一个逻辑”0”信号,表示传输字符的开始。
数据位:可以是5~8位逻辑”0”或”1”。如ASCII码(7位),扩展BCD码(8位)。小端传输
校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验)
停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。
空闲位:处于逻辑“1”状态,表示当前线路上没有资料传送。

发送
在串口通信中波特率表示每秒能传输的数据位,9600就是每秒能传输9600位
在这里插入图片描述
在这里插入图片描述
字节的发送

//-------1字节数据的发送-------
module uart_tx(
    input clk,
    input rst_n,
    input cnt_start,                                        //发送使能
	input [7:0]tx_data,
    output reg tx,
    output reg tx_done                                      //传输一个字节完成标志
    );
    
    reg [12:0]cnt_bps; 
    parameter bps_t = 13'd5207;                             //传输1bit所需计数值 
    always @(posedge clk or negedge rst_n)
    begin
       if(!rst_n) 
          cnt_bps <= 13'd0;
       else if(cnt_bps == bps_t) 
          cnt_bps <= 13'd0;
       else if(cnt_start) 
          cnt_bps <= cnt_bps + 1'b1;
       else 
          cnt_bps <= 1'b0;
    end
    wire bps_sig;
    assign bps_sig = (cnt_bps ==  13'd2604) ? 1'b1 : 1'b0;  //将采集数据的时刻放在波特率计数器每次循环计数的中间位置
       
    reg [3:0]state;	
    always @(posedge clk or negedge rst_n)
    begin
       if(!rst_n) begin
          state <= 4'd0;
          tx <= 1'b1;
          tx_done <= 1'b0;
		  end
       else begin
          case(state)
			0: if(cnt_start & bps_sig) begin
				state <= state + 1'b1;
				tx <= 1'b0;
				end
			else begin
				state <= state;
				tx <= 1'b1;
				end
			1,2,3,4,5,6,7,8: if(bps_sig) begin
					tx <= tx_data[state - 1'b1]; //注意,从低位依次往高位发送
					state <= state + 1'b1;
					end
				else begin
					state <= state;
					tx <= tx;
					end
			9,10: if(bps_sig) begin
					state <= state + 1'b1;
					tx <= 1'b1;
					end
			11: begin
					state <= state + 1'b1;
					tx_done <= 1'b1;
				end
			12: begin
					state <= 1'b0;
					tx_done <= 1'b0;
				end
          endcase
		  end
    end
endmodule

数据的接收
,字节传输形式:1-0-x-x-x-x-x-x-x-x-0-1,检测到下降沿即-1-0-(起始标志)后开始进行接收字节,将接收到的一一存入寄存器中,8个bit后结束接收,就是简单的1个字节的接收。
值得注意的是,虽然1字节=8bit,但是因为有起始标志(2bit:-1-0-)和结束标志(2bit:-0-1-),所以在发送和接收过程中,都需要考虑到这一点。

//-------1字节的接收-------
module uart_rx(
    input clk,
    input rst_n,
	input data_rx,
    output [7:0] data_tx,
    output reg rx_int                                       //接收字节时状态为1
    );
    
    reg [12:0]cnt_bps;
	reg bps_start;
    parameter bps_t = 13'd5207;                             //传输1bit所需计数值 
    always @(posedge clk or negedge rst_n)
    begin
       if(!rst_n) 
          cnt_bps <= 13'd0;
       else if(cnt_bps == bps_t) 
          cnt_bps <= 13'd0;
       else if(bps_start) 
          cnt_bps <= cnt_bps + 1'b1;
       else 
          cnt_bps <= 1'b0;
    end
    wire bps_sig;
    assign bps_sig = (cnt_bps ==  13'd2604) ? 1'b1 : 1'b0;  //将采集数据的时刻放在波特率计数器每次循环计数的中间位置
	
	reg	[1:0]	rx;
	always @(posedge	clk	or	negedge	rst_n)begin
		if(!rst_n)	rx <= 2'b11;
		else	begin
			rx[0]	<=	data_rx;
			rx[1]	<=	rx[0];
		end
	end
	wire nege_edge;
	assign nege_edge= rx[1]	& ~rx[0];						//检测下降沿

	reg	[3:0]num;	
	always@(posedge	clk	or	negedge	rst_n)begin
		if(!rst_n)	begin	
			bps_start <= 1'b0;	
			rx_int <= 1'b0;
		end
		else	if(nege_edge)begin
			bps_start <= 1'b1;
			rx_int <= 1'b1;
		end
		else if(num == 4'd10)begin
			bps_start <= 1'b0;	
			rx_int <= 1'b0;
		end
	end

	reg	[7:0]	rx_data_temp_r;								//当前数据接收寄存器
	reg	[7:0]	rx_data_r;									//用来锁存数据
	always@(posedge	clk	or	negedge	rst_n)begin
		if(!rst_n)	begin	
			rx_data_r	<= 8'd0;
			rx_data_temp_r	<= 8'd0;
			num <= 4'd0;
			end
		else if(rx_int) begin
			if(bps_sig) begin
				num <= num + 1'b1;
				case(num)
					4'd1: rx_data_temp_r[0] <= data_rx;		//锁存第0bit
					4'd2: rx_data_temp_r[1] <= data_rx;		//锁存第1bit
					4'd3: rx_data_temp_r[2] <= data_rx;		//锁存第2bit
					4'd4: rx_data_temp_r[3] <= data_rx;		//锁存第3bit
					4'd5: rx_data_temp_r[4] <= data_rx;		//锁存第4bit
					4'd6: rx_data_temp_r[5] <= data_rx;		//锁存第5bit
					4'd7: rx_data_temp_r[6] <= data_rx;		//锁存第6bit
					4'd8: rx_data_temp_r[7] <= data_rx;		//锁存第7bit
					default: ;
				endcase
			end
			else if(num == 4'd10)begin
				rx_data_r <= rx_data_temp_r;
				num <= 4'd0;
			end
		end
	end

	assign	data_tx = rx_data_r;							
	
endmodule

tb

module tb_uart_rx;

	// Inputs
	reg clk;
	reg rst_n;
	reg data_rx;

	// Outputs
	wire [7:0] data_tx;
	wire rx_int;

	// Instantiate the Unit Under Test (UUT)
	uart_rx uut (
		.clk(clk), 
		.rst_n(rst_n), 
		.data_rx(data_rx), 
		.data_tx(data_tx), 
		.rx_int(rx_int)
	);

	always #10 clk = ~clk;
	initial begin
		clk = 0;
		rst_n = 0;
		data_rx = 0;
		// Wait 20 ns for global reset to finish
		#20
		rst_n = 1;
		data_rx = 1;
		#104160
		rst_n = 1;
		data_rx = 0;	//起始位:-1-0-
		#104160			//传输11001011 (倒序)
		rst_n = 1;
		data_rx = 1;
		#104160
		rst_n = 1;
		data_rx = 1;
		#104160
		rst_n = 1;
		data_rx = 0;
		#104160
		rst_n = 1;
		data_rx = 1;
		#104160
		rst_n = 1;
		data_rx = 0;
		#104160
		rst_n = 1;
		data_rx = 0;
		#104160
		rst_n = 1;
		data_rx = 1;
		#104160
		rst_n = 1;
		data_rx = 1;
		#104160			//结束位 -0-1-
		rst_n = 1;
		data_rx = 0;
		#104160
		rst_n = 1;
		data_rx = 1;
		
		#104160			//复位
		rst_n = 0;
		data_rx = 0;
	end
      
endmodule

ref

https://blog.csdn.net/qq_40789587/article/details/84073419?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5

ref
https://blog.csdn.net/zjy900507/article/details/79789671

发布了452 篇原创文章 · 获赞 271 · 访问量 73万+

猜你喜欢

转载自blog.csdn.net/qq_35608277/article/details/105286695