【verilog】按键消抖(FPGA,低电平有效按键,状态机法)

    • 在按键信号的首尾加上计数器,以达到去抖的效果。
    • testbench
    • 功能仿真
    • 测试

在按键信号的首尾加上计数器,以达到去抖的效果。

module key (in,clk,rst_n,outkey,outflag);

        input in;       //按键输入(物理)
		input clk;
		input rst_n;

        output reg outkey; //按键输出(同步)
        output reg outflag;//按下/松开标志

//--------------------------------------------------------------------
    wire down;//检测到下降沿
    wire up;  //检测到上升沿

    reg temp1,temp2;
	always@(posedge clk or negedge rst_n)
			if(!rst_n)
			begin
				temp1 <= 1'b0;
				temp2 <= 1'b0;					
			end
			
			else
			begin
				temp1 <= in ;
				temp2 <= temp1;
			end
	assign up = temp1 & (!temp2);
	assign down = (!temp1) & temp2;
//-------------------------------------------------------------------
    reg en_cnt;//去抖模块送进来的
    
    reg  cnt_full;
    reg [19:0]cnt;
	 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 ;
	  else 
	  		cnt_full <= 1'b0;

//---------------------------------------------------------------------
        

    	localparam
		     DENGXIA    = 4'b0001,
		     YANSHI  = 4'b0010,
		     WENDING    = 4'b0100,
		     YANSHI2  = 4'b1000;
   	 	
   	 	reg [3:0]state; //状态寄存器
       
always@(posedge clk or negedge rst_n)

	if(!rst_n) begin
        state  <= DENGXIA;
	    en_cnt <= 1'b0;
        outkey <= 1'b1;
        outflag <=1'b0;
        
	end
	 else  begin
		case(state)
        
			DENGXIA :
                begin
                  outflag <= 1'b0; //flag
			      if(down) begin 		
			         state  <= YANSHI; 
			         en_cnt <= 1'b1;      
			      end
			      else					
			         state <= DENGXIA;
                end
            YANSHI :
			      if(cnt_full)begin  
                     outflag <=1'b1; //flag
                     outkey <= 1'b0; //out
			         state <= WENDING;  
			         en_cnt <= 1'b0; 
			       end
			      else if (up) begin  
			         state <= DENGXIA;   
			         en_cnt <= 1'b0;  
			      end
			      else 
			         state  <= YANSHI;  
			WENDING :
			    begin
			    	outflag <=1'b0;	//flag
	 				if(up) begin 	
			         state  <= YANSHI2; 
			         en_cnt <= 1'b1;   
			         end
			        else					
			          state  <= WENDING; 
			    end
			YANSHI2 :
			      if(cnt_full)begin
                     outflag <=1'b1; //flag
                     outkey <= 1'b1; //out
			         state  <= DENGXIA; 
			         en_cnt <= 1'b0; 
			       end
			      else if (down) begin  
			         state <= WENDING;   
			         en_cnt <= 1'b0;  
			      end
			      else 
			         state  <= YANSHI2;  
			default :  
					  
				begin
					state <= DENGXIA;
					en_cnt <= 1'b0;
                    outkey <=1'b1; //out
                    outflag <=1'b0;//flag
					
				end

	  endcase
	  end

endmodule

testbench

模拟按键抖动

`timescale 1ns/1ns
`define shizhong 20
module key_tb;

    reg clk2;
    reg rst_n2;
    reg in2;
    
    wire outflag2;
    wire outkey2;
    
			key f1(
				  .clk(clk2),
				  .rst_n(rst_n2),
				  .in(in2),
				  .outflag(outflag2),
                  .outkey(outkey2)
				  );
    initial clk2 = 1;
    always#(`shizhong/2) clk2 = ~clk2;

	initial begin 
			rst_n2 = 1'b0;
			in2 = 1'b1;
			#(`shizhong*10);
			rst_n2 = 1'b1;
			
			//模拟出按键的抖动过程  按下抖动
			#(`shizhong*10 + 1);
			in2 = 0 ;
			#1000;
			in2 = 1 ;
			#2000;
			in2 = 0 ;
			#1400;
			in2 = 1 ;
			#2600;
			in2 = 0 ;
			#1300;
			in2 = 1 ;
			#200;
			
			in2 = 0 ;
			#2_000_000_00;   //按键稳定

			//释放时抖动
			in2 = 1 ;
			#2000;
			in2 = 0 ;
			#1000;
			in2 = 1 ;
			#2000;
			in2 = 0 ;
			#1000;
			in2 = 1 ;
			#2600;
			in2 = 0 ;
			#1300;
			
			in2 = 1 ;
			#2_000_000_00; //按键稳定松开

			$stop;		
	end
endmodule

功能仿真

在这里插入图片描述
生成了同步于当前时钟域的信号以供其他模块使用

测试

用按键改变数码管的显示内容,查看是否有抖动!
【verilog】按键消抖(FPGA,低电平有效按键,状态机法)_第1张图片

module top(
    input clk,
    input rst_n,
    input key1,

    output  [5:0] dig, 
    output  [7:0] dict
);

dig8_6 f0(
     .clk(clk),
     .rst(rst_n),

     .set_data(data),

     .dig(dig),  //六位独热码表示六个数码管
     .dict(dict) //位选数码管
);
         
key  f1(
         .in(key1),
         .clk(clk),
         .rst_n(rst_n),
         .outkey(outkey1),
         .outflag1()
         );

//对outkey1进行上升沿检测,检测成功说明一次有效按键。——___——
wire outkey1; 
reg dout;
wire out2dig;
always@(posedge clk or negedge rst_n)
        if(!rst_n)
            dout <= 1'b0;
        else
            dout <= outkey1;

assign out2dig = outkey1 & (!dout);

//将只能维持一个时钟周期的out2dig,转化为一个开关量。
reg switch;
always@(posedge clk or negedge rst_n)
        if(!rst_n)
            switch <= 1'b0;
        else
        begin 
            if(out2dig == 1'b1)
                switch <= ~switch;
            else 
                switch <= switch;
        end

//数码管指示
reg [23:0]data;
always@(posedge clk or negedge rst_n)
        if(!rst_n)
            data <= 1'b0;
        else
            begin
                if(switch == 1'b1)
                    data <= 24'hffffff;
                else
                    data <= 24'h000000;
            end

endmodule

测试平台(正点原子开拓者开发板)

clk		Input	PIN_E1	
key1		Input	PIN_E16	
rst_n		Input	PIN_M1		
dict[7]		Output	PIN_D9	
dict[6]		Output	PIN_P11	
dict[5]		Output	PIN_N11	
dict[4]		Output	PIN_M10
dict[3]		Output	PIN_N13	
dict[2]		Output	PIN_C9	
dict[1]		Output	PIN_N12	
dict[0]		Output	PIN_M11	
dig[5]		Output	PIN_T15	
dig[4]		Output	PIN_R16	
dig[3]		Output	PIN_P15	
dig[2]		Output	PIN_P16
dig[1]		Output	PIN_N15	
dig[0]		Output	PIN_N16	

你可能感兴趣的:(Verilog,verilog,fpga)