欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

UART 协议

程序员文章站 2024-02-24 23:24:16
...

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

发送
在串口通信中波特率表示每秒能传输的数据位,9600就是每秒能传输9600位
UART 协议
UART 协议
字节的发送

//-------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;	
	aaa@qq.com(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;									//用来锁存数据
	aaa@qq.com(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

相关标签: ARM