(17)CT137A- UART串口发送实验

发布于:2025-02-27 ⋅ 阅读:(11) ⋅ 点赞:(0)

(1)UART是一种串行、异步、全双工的通讯协议,其中串行指的是发送线和接收线一次都只能接收1bit的数据,异步指的是上位机和FPGA之间一个传输一个接收不需要统一的时钟,两边的工作时钟可以不一致,全双工指的是FPGA可以同时进行发送数据和接收数据。

(2)实验目标:显示设计一个按键消抖模块和串口发送驱动模块,四个按键按下后,分别可以产生“H”、“E”、“L”、“O”,以此实现FPGA向电脑PC端传输字符串HELLO的功能。

(3)代码实现:

  • 按键消抖模块:
module key_filter
(
	input		wire					clk				,
	input		wire					key_in			,
	input  	wire					reset_n			,
	
	output	wire					key_out			
);

//20ms = 20ns * 1_000_000; 
parameter MCNT 	= 20'd1_000_000;
parameter IDLE 	= 4'b0001;
parameter PRESS 	= 4'b0010;
parameter DOWN 	= 4'b0100;
parameter REPRESS = 4'b1000;

reg 	[19:0]  	cnt;
reg	[3:0]		state;
reg				en_cnt;

always@(posedge clk or negedge reset_n)
	if(!reset_n)
		cnt <= 20'd0;
	else if(!en_cnt)
		cnt <= 20'd0;
	else if(cnt == MCNT - 20'd1)
		cnt <= 20'd0;
	else 
		cnt <= cnt + 20'd1;
		
always@(posedge clk or negedge reset_n)
	if(!reset_n)begin
		state <= IDLE;
		en_cnt <= 1'd0;
	end
	else begin
		case(state)
			IDLE:begin
				if(key_in == 1'd0)begin
					state <= PRESS;
					en_cnt <= 1'd1;
				end
				else begin
					state <= state;
					en_cnt <= 1'd0;
				end
			end
			PRESS:begin
				if(key_in == 1'd1)begin
					state <= IDLE;
					en_cnt <= 1'd0;
				end				
				else if(cnt == MCNT - 20'd1)begin
					state <= DOWN;
					en_cnt <= 1'd0;
				end
				else begin
					state <= state;
					en_cnt <= en_cnt;
				end
			end
			DOWN:begin
				if(key_in == 1'd1)begin
					state <= REPRESS;
					en_cnt <= 1'd1;
				end
				else begin
					state <= state;
					en_cnt <= 1'd0;
				end
			end
			REPRESS:begin
				if(key_in == 1'd0)begin
					state <= DOWN;
					en_cnt <= 1'd0;
				end
				else if(cnt == MCNT - 20'd1)begin
					state <= IDLE;
					en_cnt <= 1'd0;
				end
				else begin
					state <= state;
					en_cnt <= en_cnt;
				end
			end
			default:begin
				state <= IDLE;
				en_cnt <= 1'd0;
			end
		endcase
	end

assign key_out = (state == DOWN);

endmodule 
  • 串口发送驱动模块:
module uart_rs232_tx
(
	input		wire				clk			,
	input		wire				reset_n		,
	input		wire	[16:0]	baud_set		,
	input		wire	[7:0]		tx_data		,
	input		wire				tx_start		,
	
	output	reg				tx				,
	output	reg				tx_done	
);

reg	[15:0]	BAUD_MAX;
reg				en_baud_cnt;
reg	[15:0]	baud_cnt;
reg	[3:0]		bit_cnt;

always@(posedge clk)begin
	case(baud_set)
		17'd4800		: BAUD_MAX <= 16'd10415;
		17'd9600		: BAUD_MAX <= 16'd5207;
		17'd14400	: BAUD_MAX <= 16'd3471;
		17'd115200  : BAUD_MAX <= 16'd433;
		default 	: BAUD_MAX <= 16'd5207;     //其余波特率一律视为9600
	endcase
end

always@(posedge clk or negedge reset_n)
	if(!reset_n)
		en_baud_cnt <= 1'd0;
	else if(tx_start)
		en_baud_cnt <= 1'd1;
	else if((bit_cnt == 4'd9)&&(baud_cnt == 16'd1))
		en_baud_cnt <= 1'd0;
	else 
		en_baud_cnt <= en_baud_cnt;
		
always@(posedge clk or negedge reset_n)
	if(!reset_n)
		baud_cnt <= 16'd0;
	else if(!en_baud_cnt||((bit_cnt == 4'd9)&&(baud_cnt == 16'd1)))
		baud_cnt <= 16'd0;
	else if(baud_cnt == BAUD_MAX)
		baud_cnt <= 16'd0;
	else 
		baud_cnt <= baud_cnt + 16'd1;
		
always@(posedge clk or negedge reset_n)
	if(!reset_n)
		bit_cnt <= 4'd0;
	else if((bit_cnt == 4'd9)&&(baud_cnt == 16'd1))
		bit_cnt <= 4'd0;
	else if(baud_cnt == BAUD_MAX)
		bit_cnt <= bit_cnt + 4'd1;
	else 
		bit_cnt <= bit_cnt;
		
always@(posedge clk or negedge reset_n)
	if(!reset_n)
		tx <= 1'd1;
	else if(!en_baud_cnt)
		tx <= 1'd1;
	else if(baud_cnt == 16'd1)begin
		case(bit_cnt)
			0: tx <= 1'd0;
			1: tx <= tx_data[0];
			2: tx <= tx_data[1];
			3: tx <= tx_data[2];
			4: tx <= tx_data[3];
			5: tx <= tx_data[4];
			6: tx <= tx_data[5];
			7: tx <= tx_data[6];
			8: tx <= tx_data[7];
			9: tx <= 1'd1;
			default :tx <= 1'd1;
		endcase
	end
	else
		tx <= tx;
	
always@(posedge clk or negedge reset_n)
	if(!reset_n)
		tx_done <= 1'd0;
	else if((bit_cnt == 4'd9)&&(baud_cnt == 16'd1))
		tx_done <= 1'd1;
	else 
		tx_done <= 1'd0;

endmodule
  • 顶层模块:
module uart_key
(
    input       wire                        clk         ,
    input       wire                        reset_n     ,
    input       wire        [3:0]           key_in      ,
    
    output      wire                        tx          ,
    output      wire                        led
);

localparam     IDLE 		= 4'b0001;
localparam     SEND 		= 4'b0010;
localparam     WAIT 		= 4'b0100;
localparam     REPRESS 	= 4'b1000;

wire    [3:0]   key_out;  
wire            tx_done;
reg     [7:0]   tx_data; 
reg     [3:0]   state;  
	    
reg             tx_start;  

key_filter      key_filter_inst0
(
	.clk			(clk        ),
	.key_in		(key_in[0]  ),
	.reset_n		(reset_n    ),
    
	.key_out		(key_out[0] )	
);

key_filter      key_filter_inst1
(
	.clk			(clk        ),
	.key_in		(key_in[1]  ),
	.reset_n		(reset_n    ),
    
	.key_out		(key_out[1] )	
);

key_filter      key_filter_inst2
(
	.clk			(clk        ),
	.key_in		(key_in[2]  ),
	.reset_n		(reset_n    ),
    
	.key_out		(key_out[2] )	
);

key_filter      key_filter_inst3
(
	.clk			(clk        ),
	.key_in		(key_in[3]  ),
	.reset_n		(reset_n    ),
    
	.key_out		(key_out[3] )	
);

always@(posedge clk or negedge reset_n)
    if(!reset_n)
        tx_data <= 8'h00;
    else begin
        case(key_out)
            4'b0001 : tx_data <= 8'h48;  //H
            4'b0010 : tx_data <= 8'h45;  //E
            4'b0100 : tx_data <= 8'h4C;  //L
            4'b1000 : tx_data <= 8'h4F;  //O
            default : tx_data <= 8'h00;
        endcase
    end
		  
always@(posedge clk or negedge reset_n)
    if(!reset_n)begin
        state <= IDLE;
        tx_start <= 1'd0;
    end
    else begin
        case(state)
            IDLE:begin
                tx_start <= 1'b0;
                if(|key_out)
                    state <= SEND;
                else
                    state <= state;
            end
            SEND:begin
                tx_start <= 1'b1;
                state <= WAIT;
            end
            WAIT:begin
                tx_start <= 1'b0;
					 if(tx_done && key_out == 4'b0000)
						state <= IDLE;
                else if(tx_done)
                  state <= REPRESS;
                else 
                  state <= state;
            end
				REPRESS:begin
					if(key_out == 4'b0000)
						state <=IDLE;
					else 
						state <= state;
				end
				default: state <= IDLE;
        endcase
    end
    
assign led = ~(state == IDLE);

uart_rs232_tx       uart_rs232_tx_inst
(
	.clk			   		(clk        ),
	.reset_n		  			(reset_n    ),
	.baud_set				(17'd115200 ),
	.tx_data		    		(tx_data    ),
	.tx_start				(tx_start   ),

	.tx						(tx         ),
	.tx_done	        		(tx_done    )
);


endmodule 

(3)实验现象: