基于FPGA的检测按键抖动次数的Verilog程序(两段式写法)

通常的所用开关按键为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开,因而在闭合及断开的瞬间均伴随有一连串的抖动。抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。按键抖动会引起一次按键被误读多次。为确保CPU对按键的一次闭合仅作一次处理,必须去除按键抖动。在按键闭合稳定时读取按键的状态,并且必须判别到按键释放稳定后再作处理。查阅资料得知,现在去抖方法分为软件去抖和硬件去抖,硬件去抖通常使用RS触发器,软件去抖一般采用检测按键闭合后延时5ms~10ms,再一次检测按键的状态。这两种方法已经很成熟,但是硬件去抖不适用于按键较多的情况,延时去抖有一定的不准确性。基于fpga的有限状态机,设计一种新的去抖电路。
多次按键后真实按键次数(左边两个)与未去抖按键次数(右边两个)

有限状态机:去抖部分(采用两段式写法)
always @(posedge clk or posedge reset)
   if(~reset)               //按下复位按键,回到初始状态
      state_reg <= zero;
   else 
      state_reg <=state_next;
 always @ *
   begin
      state_next = state_reg;
	  db = 1'b0;           //输出信号
	  case(state_reg)
	     zero:             //0状态,低电平
		    if(sw)
			  state_next = wait1_1;
		 wait1_1:          // 中间状态wait1_1:等待状态变为1
		    if(~sw)
			  state_next = zero;
			else 
			 if(dou)      //计数器跟踪信号
			  state_next = wait1_2;
		 wait1_2:         // 中间状态wait1_2:等待状态变为1
		    if(~sw)
			  state_next = zero;
			else
             if(dou)			
			  state_next = wait1_3;
		 wait1_3:          // 中间状态wait1_3:等待状态变为1
		    if(~sw)
			  state_next = zero;
			else 
			 if(dou)
			  state_next = one;
		 one:              //1状态,高电平,由0-1-0为按键的一次按下与释放
		  begin
		    db = 1'b1;      //输出信号
		    if(~sw)
			  state_next = wait0_1;
		  end
		 wait0_1:           // 中间状态wait0_1:等待状态变为0
		  begin
		    db = 1'b1;
		    if(sw)
			  state_next = one;
			else
			 if(dou)
			  state_next = wait0_2;
		  end
		 wait0_2:                  // 中间状态wait0_2:等待状态变为0
		  begin
		    db = 1'b1;
		    if(sw)
			  state_next = one;
			else
			 if(dou)
			  state_next = wait0_3;
		  end
		 wait0_3:                   // 中间状态wait0_3:等待状态变为0
		  begin
		    db = 1'b1;
		    if(sw)
			  state_next = one;
			else
			 if(dou)
			  state_next = zero;
		  end
		 default: state_next = zero;    //出现遗漏情况,回到初始状态
	endcase
  end

数码管片选,高电平有效
always @ *
  case (q_reg[N-1:N-2])    //采用2-4译码器电路
      2'b00:
	     begin
		   an = 4'b0010;  //数码管片选
		   hex_in = hex0;  //数码管位选对应的数字
		   dp = dp_in[0];  //小数点(数码管第八位)独自控制
		 end
	  2'b01:
		 begin
		   an = 4'b0001;
		   hex_in = hex1;
		   dp = dp_in[1];
		 end
	  2'b10:
		 begin
		   an = 4'b1000;
		   hex_in = hex2;
		   dp = dp_in[2];
		 end
	 default:
		 begin
		   an = 4'b0100;
		   hex_in = hex3;
		   dp = dp_in[3];
		 end
	endcase

上升沿检测电路
always@(posedge clk)   //两个上升沿检测电路,分别检测去抖和未去抖的上升沿信号
    begin
       btn_reg<=btn[1];
	   db_reg<=db_level;
    end
assign btn_tick = ~btn_reg & btn[1];
assign db_tick = ~db_reg & db_level;

计数器,统计上升沿个数并传递给数码管显示
assign clr = btn[0];            //计数器清零按键
always @ (posedge clk)       //两个计数器,分别用于去抖按键与不去抖按键
    begin
	   b_reg<=b_next;
	   d_reg<=d_next;
	end
assign b_next = (clr) ?8'b0:   //两个条件运算符语句连用
                (btn_tick) ?b_reg+1:b_reg;
assign d_next = (clr) ?8'b0:
                (db_tick) ?d_reg+1:d_reg;		

此去抖方法可以更准确的滤除抖动,确保了CPU对按键的一次闭合仅作一次处理,不会出现因按键抖动而产生的错误控制。

猜你喜欢

转载自blog.csdn.net/qq_40942280/article/details/107742880