FPGA学习笔记_串口收发与存取双口ram简易应用

FPGA学习笔记

串口收发与存取双口ram简易应用

1 原理图
2 Verilog 代码
3 Modelsim仿真
4. FPGA板级验证

串口收发与存取双口ram简易应用

  • 实验现象:在pc机上通过串口发送数据到FPGA中,FPGA收到的数据后,将数据存储在双口ram的一段连续空间中,当需要时,按下按键0,FPGA将ram中存储的数据通过串口发送出去。
    知识点:
  1. cyclone iv系列器件的内部结构
  2. 存储器IP核的使用
  3. 串口收发+按键+双口ram组成建议系统设计

1. 原理图

FPGA学习笔记_串口收发与存取双口ram简易应用_第1张图片

  • 模块组成:
    1. uart_rx(uart接收端)
    2. dual_ram(双口ram)
    3. uart_tx(uart发送端)
    4. key_filter(按键消抖)

2. Verilog 代码

//----top---------------------------------------
module uart_dual_ram(
	input clk,
	input rst_n,
	input  rs232_rx,
	input key_in,
	
	output   rs232_tx
);
	
	wire [7:0] rx_data;
	wire [7:0] tx_data;
	wire		  tx_done;
	wire		  rx_done;
	wire		  key_flag;
	wire		  key_state;
	wire [7:0] rdaddress;
	wire [7:0] wraddress;
	wire 		  wren;
	wire 		  send_en;
	
	
	fsm_key_filter uut_key_filter(
			.clk(clk), 
			.rst_n(rst_n),
			.key(key_in),
			.key_flag(key_flag),
			.key_state(key_state)
	);
	
	uart_rx_r0 uut_uart_rx(
			.clk(clk),
			.rst_n(rst_n),
			.rs232_rx(rs232_rx),
			.baud_set(3'd0),
			.rx_done(rx_done),
			.data_byte(rx_data)
);
	
	uart_tx_r0 uut_uart_tx(
		.clk(clk), 
		.rst_n(rst_n),
		.send_en(send_en),
		.baud_set(3'd0),
		.data_byte(tx_data),
		.rs232_tx(rs232_tx),
		.tx_done(tx_done),
		.uart_state()
);
		ip ram_dual(
		.clock(clk),
		.data(rx_data),
		.rdaddress(rdaddress),
		.wraddress(wraddress),
		.wren(wren),
		.q(tx_data)
);

	uart_ctrl uut_controller(
		.clk(clk),
		.rst_n(rst_n),
		.key_flag(key_flag),
		.key_state(key_state),
		.rx_done(rx_done),
		.tx_done(tx_done),
	
		.rdaddress(rdaddress),
		.wraddress(wraddress),
		.wren(wren),
		.send_en(send_en)

);
endmodule
//--------------------------------------------------------------
//----controller------------------------------------------------
module uart_ctrl(
	input clk,
	input rst_n,
	input key_flag,
	input key_state,
	input rx_done,
	input tx_done,
	
	output reg [7:0] rdaddress,
	output reg [7:0] wraddress,
	output 		  wren,
	output 	reg	  send_en

);
	reg read_send; //
	reg reg1_done;
	reg reg2_done;
	assign wren = rx_done;
//----wraddress-------------------------	
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			wraddress <= 8'd0;
		else if(rx_done)
			wraddress <= wraddress +8'd1;
		else
			wraddress <= wraddress;
//----rdaddress-------------------------			
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			read_send <= 1'd0;
		else if(key_flag && !key_state)
			read_send <= ~read_send;
		else
			read_send <= read_send;
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			rdaddress <= 8'd0;
		else if(read_send && tx_done)
			rdaddress <= rdaddress +8'd1;
		else
			rdaddress <= rdaddress;		
			
//----send_en---------------------------
	always@(posedge clk or negedge rst_n)
		if(!rst_n)begin
			reg1_done <= 1'd0;
			reg2_done <= 1'd0;
		end
		else begin
			reg1_done <= (read_send && tx_done);
			reg2_done <= reg1_done;
		end
			
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			send_en <= 1'd0;
		else if(key_flag && !key_state)
			send_en <= 1'd1;
		else if(reg2_done)
			send_en <= 1'd1;
		else
			send_en <= 1'd0;

endmodule
//---------------------------------------------------------------------
//----uart_rx----------------------------------------------------------
//请看上一节文章
//---------------------------------------------------------------------
//----uart_tx----------------------------------------------------------
//请看上一节文章
//---------------------------------------------------------------------
//----key_filter-------------------------------------------------------
module fsm_key_filter#(
	parameter IDLE = 4'b0001,
	parameter FILTER1 = 4'b0010,
	parameter DOWN = 4'b0100,
	parameter FILTER2 = 4'b1000
)
(
	input clk, //50MHz 20us
	input rst_n,
	input key,
	
	output  key_flag,
	output reg  key_state
);
	reg		cnt_en;
	reg		cnt_full;
	reg [19:0] cnt1;
	//reg [19:0] cnt2;
	reg [3:0] state;
	reg		key_syn1;
	reg		key_syn2;
	reg 		key_reg1;
	reg		key_reg2;
	wire 		pos_edge;
	wire 		neg_edge;
	
	always@(posedge clk or negedge rst_n)
		if(!rst_n)begin
			state <= IDLE;
			cnt_en <= 1'b0;
		end else 
		begin
			case(state)
				IDLE:
					begin
						if(neg_edge)begin
							state <= FILTER1;
							cnt_en <= 1'b1;
						end else
						begin
							state <=	IDLE;	
							cnt_en <= 1'b0;
						end
					end
					
				FILTER1:
					begin
							if(cnt_full)//20ms
							begin
								state <= DOWN;
								cnt_en <= 1'b0;
							end 
							else if(pos_edge)
							begin
								state <= IDLE;
								cnt_en <= 1'b0;
							end else
							begin
								state <= FILTER1;
								cnt_en <= cnt_en;
							end
					end
					
				DOWN:
					begin
						if(pos_edge)begin
							cnt_en <= 1'b1;
							state <= FILTER2;
						end else 
						begin
							cnt_en <= 1'b0;
							state <= DOWN;
						end
					end
					
				FILTER2:
					begin
							if(cnt_full)
								state <=	IDLE;	
							else if(neg_edge)begin
								cnt_en <= 1'b0;
								state <= DOWN;
							end 
							else
								state <= FILTER2;
					end
				default: begin
					state <= IDLE;
					cnt_en <= 1'b0;
				end
			endcase
		end
//----cnt--------------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt1 <= 20'd0;
		else if(cnt_en)
			cnt1 <= cnt1 + 20'd1;
			else 
			cnt1 <= 20'd0;
	end
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt_full <= 1'b0;
		else if(cnt1 == 20'd999_999)
			cnt_full <= 1'b1;
			else 
			cnt_full <= 1'b0;
	end
//----asyn_key-->syn---------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			key_syn1 <= 1'b0;
			key_syn2 <= 1'b0;
		end else
		begin
			key_syn1 <= key;
			key_syn2 <= key_syn1;
		end	
	end
//----key edge detect--------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			key_reg1 <= 1'b0;
			key_reg2 <= 1'b0;
		end else
		begin
			key_reg1 <= key_syn2;
			key_reg2 <= key_reg1;
		end	
	end
	assign neg_edge = (!key_reg1) & key_reg2;
	assign pos_edge = key_reg1 & (!key_reg2);
	
//----key_flag---------------------------------------
	assign key_flag = (cnt1 == 20'd999_999)? 1'b1:1'b0;
//----key_state--------------------------------------
		always@(posedge clk or negedge rst_n)
			if(!rst_n)
				key_state <= 1;
			else if(cnt_full)
				key_state <= ~key_state;
			else
				key_state <= key_state;	
endmodule

3. Modelsim仿真

FPGA学习笔记_串口收发与存取双口ram简易应用_第2张图片

4. FPGA板级验证

FPGA学习笔记_串口收发与存取双口ram简易应用_第3张图片


----学习内容来自小梅哥FPGA视频

【注】:个人学习笔记,如有错误,望不吝赐教,这厢有礼了~~~


你可能感兴趣的:(FPGA学习笔记,verilog,fpga/cpld,串口通信)