串口收发之ram存取

项目名称

串口收发之ram存取

具体要求

串口发送6个数据到FPGA,通过双端口ram将数据缓存,每按下一个按键,上位机接收一个数据,按下按键6次接收5位数据完毕

设计说明

下图为设计框架,除了ram_ctrl模块,剩下的模块在前面都介绍过,将前设计的模块进行调用总体比较简单。

串口收发之ram存取_第1张图片

这里将前面设计的串口发送模块重新设计一下,根据以下的时序图可以很轻松设计出串口发送模块。

串口收发之ram存取_第2张图片

 需要注意的是笔者在进行ram控制模块设计的时候遇到了一个问题,在进行读地址的时候,如果按以下的方式进行设计,也是没有问题的,问题是当发送使能为1的时候,下一个时钟上升沿才执行if下的语句,而在这期间就开始读出0地址的数据,在下一个时钟上升沿读出1地址的数据,但是0地址的数据并没有被读出,应该是在时钟上升沿的时候才开始被执行吧。

always@(posedge clk or negedge rst_n)
   if(!rst_n)    
        rdaddr<=0;
    else if(send_en)begin
        if(rdaddr==5)
            rdaddr<=0;
        else
            rdaddr<=rdaddr+1;
    end
   else 
     rdaddr<=rdaddr;

笔者将上面的代码进行修改用状态机来实现可以正常读取出存入的5位数据。 

reg state;                                                
always@(posedge clk or negedge rst_n)
    if(!rst_n)    begin
        rdaddr<=0;
        state<=0;
    end
    else if(send_en)begin
            case(state)
                0:    begin
                        rdaddr<=0;
                        state<=1;
                    end
                1:begin
                        if(rdaddr==5)begin
                            rdaddr<=0;
                            state<=1;
                        end
                        else
                            rdaddr<=rdaddr+1;
                    end
            endcase
        end
            else 
        rdaddr<=rdaddr;

代码设计

 顶层模块

module uart_top(
	input			clk,
	input			rst_n,
	input			rs232_data,
	input			key_in,
	output 	 	rs232_tx
);

wire [7:0] data;
wire flag;
wire key_flag;
wire key_state;

uart_rx 	uart_rx(
	.clk(clk),
	.rst_n(rst_n),
	.rs232_data(rs232_data),
	.data(data),
	.flag(flag)
);

key_filter key_filter(
	.	clk(clk),
	.	rst_n(rst_n),
	.	key_in(key_in),
	.	key_flag(key_flag),
	.	key_state(key_state)
);

wire send_en;
wire wren;
wire [7:0] wraddr;
wire [7:0] rdaddr;
wire [7:0] q;
wire tx_done;

ram_ctrl  ram_ctrl(
	.clk(clk),
	.rst_n(rst_n),
	.flag(flag),
	.key_flag(key_flag),
	.key_state(key_state),
	.send_en(send_en),
	.tx_done(tx_done),
	.wren(wren),
	.wraddr(wraddr),
	.rdaddr(rdaddr)
);

 my_ram  my_ram(
	.clock(clk),
	.data(data),
	.rdaddress(rdaddr),
	.wraddress(wraddr),
	.wren(wren),
	.q(q)
);
	
uart_tx  uart_tx(
	.clk(clk),
	.rst_n(rst_n),
	.send_en(send_en),
	.data_byte(q),
	.rs232_tx(rs232_tx),
	.tx_done()
);	


endmodule

串口接收模块

 module uart_rx(
	input 			clk,
	input				rst_n,
	input				rs232_data,
	output 	reg [7:0]data,
	output reg		flag
);
localparam bps_cnt_end=5207;
//串口数据同步处理
reg rx_data1;
reg rx_data2;
reg rx_data3;
always@(posedge clk or negedge rst_n)
	if(!rst_n)begin
		rx_data1<=0;
	   rx_data2<=0;
	   rx_data3<=0;
	end
	else begin
		rx_data1<=rs232_data;
		rx_data2<=rx_data1;
		rx_data3<=rx_data2;
	end
	
//下降沿起始位检测
wire nedge= !rx_data2 & rx_data3;

reg data_flag;
reg [12:0]bps_cnt;
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		bps_cnt<=0;
	else if(data_flag)begin
		if(bps_cnt<5207)
			bps_cnt<=bps_cnt+1;
		else
			bps_cnt<=0;
	end
	else
		bps_cnt<=0;

reg [3:0] data_cnt;		
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		data_flag<=0;
	else if(nedge)
		data_flag<=1;
	else if(bps_cnt==5205 && data_cnt==10)
		data_flag<=0;

reg data_sample;
reg [12:0] bps_cnt_mid=bps_cnt_end/2+1;
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		data_sample<=0;
	else if(data_flag && bps_cnt==bps_cnt_mid)
		data_sample<=1;
	else	
		data_sample<=0;
		
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		data_cnt<=0;
	else if(data_sample)begin
		if(data_cnt<10)
			data_cnt<=data_cnt+1;
		else
			data_cnt<=1;
	end
	else
		data_cnt<=data_cnt;
		
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		flag<=0;
	else if(data_cnt==9 && bps_cnt==bps_cnt_mid+3)
		flag<=1;
	else
		flag<=0;
		
//接收数据
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		data<=0;
	else if(data_sample && data_cnt>=1 && data_cnt<=8)
		data<={rx_data3,data[7:1]};
	else 
		data<=data;


endmodule


按键消抖模块

module key_filter(
	input				clk,
	input				rst_n,
	input				key_in,
	output	reg		key_flag,
	output	reg		key_state
);

//异步信号处理
reg key_s0,key_s1;
always@(posedge clk or negedge rst_n)
	if(!rst_n)begin
		key_s0<=0;
		key_s1<=0;
	end
	else begin
		key_s0<=key_in;
		key_s1<=key_s0;
	end

//上升沿与下降沿检测
reg key_in0;
reg key_in1;
always@(posedge clk or negedge rst_n)
	if(!rst_n)begin
		key_in0<=0;
		key_in1<=0;
	end
	else begin
		key_in0<=key_s1;
		key_in1<=key_in0;
	end
wire nedge=key_in1 && (!key_in0);//下降沿检测
wire podge=(!key_in1) && key_in0;//上升沿检测

//20ms的计数
reg [24:0] cnt;
reg en_cnt;//使能计数
always@(posedge clk or negedge rst_n)
	if(!rst_n)begin
		cnt<=0;
	end
	else if(en_cnt)begin
		if(cnt<25'd1_000_000-1)
			cnt<=cnt+1'b1;
		else
			cnt<=0;
	end
	else
		cnt<=0;
wire delay_20ms_done=(cnt==25'd1_000_000-1) && (en_cnt);//计满标志信号

//状态机的设计
reg [2:0] state; 
localparam IDLE   =3'd0;
localparam FILTER1=3'd1;
localparam DOWM   =3'd2;
localparam FILTER2=3'd3;
always@(posedge clk or negedge rst_n)
	if(!rst_n)begin
		key_flag<=0;
		key_state<=1;
		state<=IDLE;
		en_cnt<=0;
	end
	else begin
		case(state)
			IDLE	 :	begin
							if(nedge)begin
								state<=FILTER1;
								en_cnt<=1;
							end
							else
								state<=IDLE;
						end
			FILTER1:	begin
							if(delay_20ms_done)begin
								if(podge)begin
									state<=IDLE;
									en_cnt<=0;
								end
								else begin
									state<=DOWM;
									en_cnt<=0;
									key_flag<=1;
									key_state<=0;
								end
							end
							else
								state<=FILTER1;
						end
			DOWM	 :	begin
							key_flag<=0;
							if(podge)begin
								state<=FILTER2;
								en_cnt<=1;
							end
							else begin
								state<=DOWM;
							end	
						end
			FILTER2:	begin
							if(delay_20ms_done)begin
								if(nedge)begin
									state<=DOWM;
									en_cnt<=0;
								end
								else begin
									state<=IDLE;
									en_cnt<=0;
									key_state<=1;
								end
							end
							else begin
								state<=FILTER2;
							end
								
								
						end
			default:	begin
							key_flag<=0;
							key_state<=1;
							state<=IDLE;
							en_cnt<=0;
						end
		endcase
	end
		

endmodule

ram控制模块


module 	ram_ctrl(
	input			clk,
	input			rst_n,
	input			flag,
	input			key_flag,
	input			key_state,
	input			tx_done,
	output	reg	send_en,
	output		wren,
	output	reg[7:0]	wraddr,
	output	reg[7:0]	rdaddr
);

assign wren=flag;
		
//写地址,写使能一旦打开就开始写数据,从0地址开始写数据
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		wraddr<=0;
	else if(flag)begin
		if(wraddr==5)
			wraddr<=0;
		else
			wraddr<=wraddr+1;
	end
	else
		wraddr<=wraddr;
		
//读数据,检测到按键信号就开始发送数据(未检测到按键信号ram中q一直是0地址中的数据)	
reg state;	
always@(posedge clk or negedge rst_n)
	if(!rst_n)	begin
		rdaddr<=0;
		state<=0;
	end
	else if(send_en)begin
			case(state)
				0:	begin
						rdaddr<=0;
						state<=1;
					end
				1:begin
						if(rdaddr==5)begin
							rdaddr<=0;
							state<=1;
						end
						else
							rdaddr<=rdaddr+1;
					end
			endcase
		end
			else 
		rdaddr<=rdaddr;


//always@(posedge clk or negedge rst_n)
//	if(!rst_n)	
//		rdaddr<=0;
//	else if(send_en)begin
//		if(rdaddr==5)
//			rdaddr<=0;
//		else
//			rdaddr<=rdaddr+1;
//	end
//	else 
//		rdaddr<=rdaddr;

//发送使能		
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		send_en<=0;
	else if(key_flag && (!key_state))
		send_en<=1;
	else 
		send_en<=0;
		


endmodule

串口发送模块

module uart_tx(
	input				clk,
	input				rst_n,
	input				send_en,
	input	[7:0]		data_byte,
	output	reg	rs232_tx,
	output	reg	tx_done
);

//数据同步,消除亚稳态
reg [7:0] data_byte_r;
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		data_byte_r<=0;
	else
		data_byte_r<=data_byte;
		
//波特率计数
reg [15:0] bps_cnt;
reg bps_cnt_en;//波特率使能计数
reg [3:0] bps_clk_cnt;//波特率时钟计数
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		bps_cnt_en<=0;
	else if(send_en)
		bps_cnt_en<=1;
	else if(bps_clk_cnt==11)
		bps_cnt_en<=0;
	else
		bps_cnt_en<=bps_cnt_en;
		
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		bps_cnt<=0;
	else if(bps_cnt_en)begin
		if(bps_cnt==5207)
			bps_cnt<=0;
		else
			bps_cnt<=bps_cnt+1;
	end
	else
		bps_cnt<=0;
		
//生成波特率时钟
reg bps_clk;
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		bps_clk<=0;
	else if(bps_cnt_en && bps_cnt==1)
		bps_clk<=1;
	else
		bps_clk<=0;
		
//波特率时钟计数
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		bps_clk_cnt<=0;
	else if(bps_cnt_en)begin
		if(bps_clk)
			bps_clk_cnt<=bps_clk_cnt+1;
		else
			bps_clk_cnt<=bps_clk_cnt;
	end
	else
		bps_clk_cnt<=0;
		
//数据发送完成标志
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		tx_done<=0;
	else if(bps_clk_cnt==11)
		tx_done<=1;
	else
		tx_done<=0;
	
//发送数据
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		rs232_tx<=0;
	else begin
		case(bps_clk_cnt)
			1:	rs232_tx<=0;
			2:	rs232_tx<=data_byte_r[0];
			3:	rs232_tx<=data_byte_r[1];
			4:	rs232_tx<=data_byte_r[2];
			5:	rs232_tx<=data_byte_r[3];
			6:	rs232_tx<=data_byte_r[4];
			7:	rs232_tx<=data_byte_r[5];
			8:	rs232_tx<=data_byte_r[6];
			9:	rs232_tx<=data_byte_r[7];
			10:rs232_tx<=1;
			11:rs232_tx<=1;
			default:rs232_tx<=1;
		endcase
	end
		
		
endmodule

实验结果

通过串口发送11,22,33,44,55,66到fpga,按下按键发现数据可以正常被读出。

               串口收发之ram存取_第3张图片

你可能感兴趣的:(verilog)