手写一个uart协议——rs232

先了解一下关于uart和rs232的基础知识

文章目录

  • 一、RS232的回环测试
    • 1.1模块整体架构
    • 1.2 rx模块设计
      • 1.2.1 波形设计
      • 1.2.2代码实现与tb
      • 1.2.4 仿真
    • 1.3 tx模块设计
      • 1.3.1 波形设计
      • 1.3.2 代码实现与tb
      • 1.3.4 顶层设计
      • 1.3.3 仿真

本篇内容:

一、RS232的回环测试

上位机由串口助手通过 rx 线往 FPGA 发 8 比特数据,当 FPGA接收到 8 比特数据后,再通过 tx 线把接收到的 8 比特数据给上位机发回去,要求上位机接收到的数据和上位机发送的数据一样,并且保证连续发送也没问题。

在这里插入图片描述

1.1模块整体架构

在这里插入图片描述
在这里插入图片描述

1.2 rx模块设计

1.2.1 波形设计

在这里插入图片描述

1.2.2代码实现与tb

代码:

module uart_rx(
    input wire clk,
    input wire rst,
    input wire rx,
    output reg [7:0]po_data,
    output reg po_flag
    );

parameter CNT_END=100;  //9600bps cnt=5207  sim时,cnt=100;
parameter CNT_END_HALF=CNT_END/2;

reg rx_t;
reg rx_tt;
reg rx_tt_reg;
reg [12:0] cnt;
reg cnt_flag;
reg bit_flag;
reg [3:0]bit_cnt;
// rx_t
always @(posedge clk) begin 
    if(rst==1'b1) begin
        rx_t <= 'd1;
    end 
    else begin
         rx_t<=rx ;
    end
end

// rx_tt
always @(posedge clk) begin 
    if(rst==1'b1) begin
        rx_tt <= 'd1;
    end 
    else begin
         rx_tt<=rx_t ;
    end
end

// rx_tt_reg
always @(posedge clk) begin 
    if(rst==1'b1) begin
        rx_tt_reg <= 'd1;
    end 
    else begin
         rx_tt_reg<=rx_tt ;
    end
end

//cnt
always @(posedge clk) begin 
    if(rst==1'b1) begin
         cnt<= 'd0;
    end 
    else if (cnt_flag==1'b1 && cnt==CNT_END) begin
        cnt<='d0;
    end
    else if (cnt_flag==1'b1) begin
        cnt<=cnt+1'b1;
    end
    else if (bit_cnt=='d8 && bit_flag==1'b1) begin
        cnt<='d0;
    end
end

//bit_flag
always @(posedge clk) begin 
    if(rst==1'b1) begin
        bit_flag <= 'd0;
    end 
    else if (cnt_flag==1'b1 && cnt==CNT_END_HALF) begin
        bit_flag<='d1;
    end
    else 
        bit_flag<='d0;
end

// cnt_flag
always @(posedge clk) begin 
    if(rst==1'b1) begin
        cnt_flag <= 'd0;
    end 
    else if (rx_tt==1'b0 && rx_tt_reg==1'b1) begin
        cnt_flag<='d1;
    end
    else if (bit_cnt=='d8 && cnt==CNT_END_HALF) begin
        cnt_flag<='d0;
    end
end

// bit_cnt
always @(posedge clk) begin 
    if(rst==1'b1) begin
       bit_cnt  <= 'd0;
    end 
    else if (bit_cnt=='d8 && bit_flag==1'b1) begin
        bit_cnt<='d0;
    end
    else if (bit_flag==1'b1) begin
        bit_cnt<=bit_cnt+1'b1;
    end
  
end

// po_data
always @(posedge clk) begin 
    if(rst==1'b1) begin
        po_data <= 'd0;
    end 
    else if (bit_cnt>0 && bit_flag==1'b1) begin
        po_data<={rx,po_data[7:1]};
    end
end

// po_flag
always @(posedge clk) begin 
    if(rst==1'b1) begin
         po_flag<= 'd0;
    end 
    else if (bit_cnt=='d8 && bit_flag==1'b1) begin
        po_flag<='d1;
    end
    else 
        po_flag<='d0;
end
endmodule

tb:

`timescale 1ns / 1ps

module tb_rx();
	reg clk;
	reg rst;
	reg rx;
	wire [7:0] po_data;
	wire po_flag;

	initial begin
		clk=0;
		rst=1;
		#100
		rst=0;
	end

	initial begin
		rx=1;//空闲状态
		#100
		gen_rx();
		
	end


//这里模拟发送20帧数据,每次发送80~1的任意数,发送前rx拉低,表示起始位
//由于9600波特率需要计数5207次,为了仿真方便,假设只需要计数100次。
	task gen_rx;
		integer i;
		integer j;
		begin		
			for (j = 0; j < 20; j=j+1) begin
				rx=0;
				for ( i = 0; i < 8; i=i+1) begin  
					repeat(100) begin //每隔100周期发送1bit数据;
						@(posedge clk);  
					end
					rx={$random};
				end
				rx=1; //每发送完一帧数据后,rx恢复空闲状态,维持10个周期后继续发送数据,直到发够20帧数据。
			repeat(10) begin
				@(posedge clk);
			end		
			end
	    end
			
	endtask 

	always #5 clk=~clk;

		uart_rx inst_uart_rx (
			.clk     (clk),
			.rst     (rst),
			.rx      (rx),
			.po_data (po_data),
			.po_flag (po_flag)
		);

endmodule

1.2.4 仿真

在这里插入图片描述

1.3 tx模块设计

1.3.1 波形设计

在这里插入图片描述

1.3.2 代码实现与tb

module uart_tx(
	input wire clk,
	input wire rst,
	input wire[7:0] po_data,
	input wire po_flag,
	output reg tx
    );

parameter CNT_END=100; // bps为9600时,这里为:5207, 为仿真方便设为100。

reg [7:0] po_data_reg;
reg [12:0]cnt;
reg cnt_flag;
reg bit_flag;
reg [3:0] bit_cnt;
// po_data_reg
always @(posedge clk) begin 
	if(rst==1'b1) begin
		 po_data_reg<= 'd0;
	end
	else 
		po_data_reg<=po_data;
end

// cnt
always @(posedge clk) begin 
	if(rst==1'b1) begin
		cnt <= 'd0;
	end 
	else if (cnt_flag==1'b1 && cnt==CNT_END) begin
		cnt <= 'd0;
	end
	else if (cnt_flag==1'b1) begin
		cnt<=cnt+1'b1;
	end

end

//cnt_flag
always @(posedge clk) begin 
	if(rst==1'b1) begin
		cnt_flag <= 'd0;
	end 
	else if (po_flag==1'b1) begin
		cnt_flag<='d1;
	end
	else if (bit_cnt=='d8 && bit_flag==1'b1) begin
		cnt_flag<='d0;
	end	
end

// bit_flag
always @(posedge clk) begin 
	if(rst==1'b1) begin
		bit_flag <= 'd0;
	end 
	else if (cnt==CNT_END-1 && cnt_flag==1'b1) begin
		bit_flag<='d1;
	end
	else 
		bit_flag<='d0;
end

// bit_cnt
always @(posedge clk) begin 
	if(rst==1'b1) begin
		bit_cnt <= 'd0;
	end 
	else if (bit_flag==1'b1 && bit_cnt=='d8) begin
		bit_cnt<='d0;
	end
	else if (bit_flag==1'b1) begin
		bit_cnt<=bit_cnt+1'b1;
	end
end
// tx
always @(posedge clk) begin 
	if(rst==1'b1) begin
		tx <= 'd1;
	end 
	else if (po_flag==1'b1) begin
		tx<='d0;
	end
	else if (bit_flag==1'b1 && bit_cnt=='d8) begin
		tx<='d1;
	end
	else if (bit_flag==1'b1) begin
		tx<=po_data_reg[bit_cnt];
	end
end
endmodule

tb:

`timescale 1ns / 1ps
module tb_rx();
	reg clk;
	reg rst;
	reg rx;
	wire tx;

	initial begin
		clk=0;
		rst=1;
		#100
		rst=0;
	end

	initial begin
		rx=1;//空闲状态
		#100
		gen_rx();
		
	end


//这里模拟发送20次数据,每次发送80~1的任意数,发送前rx拉低,表示起始位
//由于9600波特率需要计数5207次,为了仿真方便,假设只需要计数100次。
	task gen_rx;
		integer i;
		integer j;
		begin		
			for (j = 0; j < 20; j=j+1) begin
				rx=0;
				for ( i = 0; i < 8; i=i+1) begin  
					repeat(100) begin //每隔100周期发送1bit数据;
						@(posedge clk);  
					end
					rx={$random};
			end
			rx=1; //每发送完一帧数据后,rx恢复空闲状态,维持100个周期(方便tx端完整传输完一帧数据)后继续发送数据,直到发够20帧数据。
			repeat(1000) begin
				@(posedge clk);
			end		
			end
	    end
			
	endtask 

	always #5 clk=~clk;

	top_uart inst_top_uart (.clk(clk), .rst(rst), .rx(rx), .tx(tx));


endmodule

1.3.4 顶层设计

module top_uart(
	input wire clk,
	input wire rst,
	input wire rx,
	output wire tx
    );

wire [7:0] po_data;
wire po_flag;

	uart_rx inst_uart_rx (
			.clk     (clk),
			.rst     (rst),
			.rx      (rx),
			.po_data (po_data),
			.po_flag (po_flag)
		);

	uart_tx  inst_uart_tx (
			.clk     (clk),
			.rst     (rst),
			.po_data (po_data),
			.po_flag (po_flag),
			.tx      (tx)
		);


endmodule

1.3.3 仿真

在这里插入图片描述
可以看到,rx和tx波形一致,则能实现传输要求。

上一篇:内网安全-代理Socks协议&路由不出网&后渗透通讯&CS-MSF控制上线简单总结


下一篇:【Python可视化】pyecharts