FPGA按键消抖实验

模块框图:
在这里插入图片描述
top代码:

module key_led_top(
    input sys_clk,
    input sys_rst_n,
    input key_in0,
    input key_in1,

    output [3:0] led

    );
 
 wire key_flag0,key_flag1;
 wire key_state0,key_state1;


    key_filter u_key_filter0(
    .clk      (sys_clk)  ,
    .Rst_n    (sys_rst_n)  ,
    .key_in   (key_in0)  ,
    .key_flag (key_flag0)  ,
    .key_state(key_state0)
    );

    key_filter u_key_filter1(
    .clk      (sys_clk)  ,
    .Rst_n    (sys_rst_n)  ,
    .key_in   (key_in1)  ,
    .key_flag (key_flag1)  ,
    .key_state(key_state1)
    );

    led_ctrl(
    .clk        (sys_clk),
    .rst_n      (sys_rst_n),
    .key_flag0  (key_flag0),    //按键1
    .key_flag1  (key_flag1),
    .key_state0 (key_state0),   //按键1
    .key_state1 (key_state1),

    .led(led)
    );

endmodule

模块代码:

module key_filter(
    clk,
    Rst_n,
    key_in,
    key_flag,
    key_state
    );
	input clk;
	input Rst_n;
	input key_in;
	output reg key_flag;
	output reg key_state;
	
	localparam
		IDEL 	 = 4'b0001,
		FILTER0  = 4'b0010,
		DOWN 	 = 4'b0100,
		FILTER1  = 4'b1000;
		
		reg [3:0]state;
		reg [19:0]cnt;
		reg en_cnt;
		reg cnt_full;//计数满标志信号
		
		reg key_tmp0,key_tmp1;
		wire pedge,nedge;
 
		//异步信号同步处理
		reg key_in_s0;
		reg key_in_s1;
		always @(posedge clk or negedge Rst_n)
		begin
			if(!Rst_n)
				key_in_s0 <= 0 ;
				key_in_s1 <= 0 ;
			else 
				key_in_s0 <= key_in ;
				key_in_s1 <= key_in_s0 ;
		end
		
		assign key_in_s1   = key_in_s1 ;

		always @(posedge clk or negedge Rst_n)
		begin 
			if(!Rst_n)
			begin 
				key_tmp0 <= 1'b0;
				key_tmp1 <= 1'b0;
			end
			else
			begin 
				key_tmp0 <= key_in;
				key_tmp1 <= key_tmp0;
			end
		end
		assign nedge = (!key_tmp0)&key_tmp1;
		assign pedge = key_tmp0&(!key_tmp1);
		
	always @(posedge clk or negedge Rst_n)
	
		if(!Rst_n)
		begin
			state <= IDEL;
			en_cnt <= 1'b0;
			key_flag <= 1'b0;
			key_state <= 1'b1;
			end
		else begin
			case(state)
				IDEL:
					begin
						key_flag <= 1'b0;
					if(nedge)begin
						state <= FILTER0;
						en_cnt<=1'b1;
						end
					else
						state <= IDEL;
					end
					
				FILTER0:
					if(cnt_full)begin 
						key_flag <= 1'b1;
						key_state <= 1'b0;
						state <= DOWN;
						en_cnt <= 1'b0;
					end
					else if(pedge)begin 
						state <= IDEL;
						en_cnt <= 1'b0;
					end
					else 
						state <= FILTER0;
						
				DOWN:
					begin
						key_flag <= 1'b0;
						if(pedge)begin 
						state <= FILTER1;
						en_cnt <= 1'b1;
					end
					else 
					begin
						state <= DOWN;
					end
					end
					
				FILTER1:
					if(cnt_full)begin 
						key_flag <= 1'b1;
						key_state <= 1'b1;
						state <= IDEL;
					end
					else if(nedge)
						begin
							en_cnt <= 1'b0;
							state <= DOWN;
						end
					else
						begin
							state <= FILTER1;
						end
				default:
				begin 
					state <= IDEL;
					en_cnt <= 1'b0;
					key_flag <= 1'b0;
					key_state <= 1'b1;
					
				end
				endcase
 
	end
	
	always @(posedge clk or negedge Rst_n)
	if(!Rst_n)
		cnt <= 20'd0;
	else if(en_cnt)
		cnt <= cnt+1'b1;
	else
		cnt <= 20'd0;
		
		
	always @(posedge clk or negedge Rst_n)
	if(!Rst_n)
		cnt_full <= 1'b0;
	else if(cnt == 999_999)
		cnt_full <= 1'b1;
	else
		cnt_full <= 1'b0;
		
 endmodule
module led_ctrl(
    input clk,
    input rst_n,
    input key_flag0,    //按键1
    input key_flag1,
    input key_state0,   //按键1
    input key_state1,

    output  reg [3:0] led
    );

// wire key_flag0,key_flag1;
// wire key_state0,key_state1;
wire  led0;
always @(posedge clk or negedge rst_n)   //两个按键按下部分
begin
    if(!rst_n)
        led <= 4'b0000;
    else if(key_flag0 & (!key_state0))
        led <= 4'b0000 + 1 ;
    else if(key_flag1 & (!key_state1))
        led <= 4'b0000 + 1 ;
    else 
        led <= led;
end


assign led0 = led ; 

endmodule


task写法:

//task 写法

//目的:函数调用   取代了写50次的模拟按键与释放
reg [15:0] myrand;
tassk press_key;
begin
	repeat(50) begin    //模拟50次的抖动现象
		myrand = {&random} %65536 ; //引入随机生成数
		#myrand key_in =~ key_in;
	end
	key_in = 0 ;
	#50000000  ;     //最后趋向于稳定
	 
	repeat(50) begin    //模拟50次的抖动现象
		myrand = {&random} %65536 ; //引入随机生成数
		#myrand key_in =~ key_in;
	end
	key_in = 1 ;
	#50000000  ;     //最后趋向于稳定
end


//然后调用函数
initial begin
   key_in = 1;
   press_key;
   #100000;
   press_key;
   #100000;
   press_key;
   $stop;
end

学习心得:
1.异步信号转同步:两个寄存器打拍(异步信号与系统时钟无关)
2.状态机的一段式
3.多个模块的学习

因为我的板子是ZYNQ 7020,原理图上的N15 N16 按键的引脚貌似出问题了……

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值