FPGA-09-独立按键的消抖(软件消抖未用状态机)

独立按键消抖在单片机和FPGA中都是个不可避免的问题,首先,解释一下什么叫做按键抖动,如图,按键在按下和松开的那个瞬间存在大概20ms的机械抖动:

  

  下面就是本篇的第一个重点 —— 什么时候需要按键消抖设计?如果是像复位按键这样,短时间内可以多次触发,就完全不需要设计消抖,但是如果是要设计按下按键使LED状态翻转,或者按下按键计数一次的话,就必须要设计消抖模块,否则就会带来不可预知的错误,因为在按下按键的那个时刻,可能已经触发了少则几次,多则几十次,可见按键消抖的必要性;

  那么,既然按键消抖如此重要,如何来进行消抖呢?

  1、硬件消抖 —— 0.1uF电容滤波

  

    这个104的电容就是起高频滤波的作用,在按键不是很多的情况下,可以使用这种设计,但是如果要做项目,会增加大量成本,所以接下来我们讲述如何进行软件消抖;

  2、软件消抖 —— delay

if(key_in == 0)
{
    deley(2000);
    if(key_in == 0)
    {
         //按键按下,执行相应操作 
     }   
}

  在单片机中用C语言,可以这样设计按键消抖,同样的思路,在FPGA中,我们依然可以采用这种思想,将按键的这20ms抖动“屏蔽”,但是FPGA没有delay(2000),该如何设计呢?

  FPGA中控制延时可以采用计数器,因为工作时钟是已知的50M,所以要延时20_000_000ns(20ms),只需要对计数1_000_000个clk就可以,这样延时问题就解决了,按照之前的思路,设计如下:只需要在检测到key_in变为0,启动定时器,定时器时间到,再次检测key_in是否为0,若为0,表明按键按下稳定,关闭计数器并清零,然后等待按键释放,也就是key_in出现上升沿,再次启动定时器,时间到后检测key_in,若为1,则证明按键已释放,一次完整的按键过程结束

module keys(ext_clk_25m,ext_rst_n,led,key_left,key_righ,key_upup,key_down,key_entr
    );
	input ext_clk_25m;
	input ext_rst_n;
	input key_down,key_entr,key_left,key_righ,key_upup;
	
	output reg [7:0]led;

抖动判断逻辑

这里用4位是为了和采样频率和基准时钟一致

//按键抖动判断逻辑
	wire key;  //所有的按键相与的结果,用于按键触发判断
	
	reg[3:0]keyr ; //按键值key的缓冲寄存器
	assign key =key_down & key_entr&key_left&key_righ&key_upup;
	
	always@(posedge ext_clk_25m or negedge ext_rst_n)
	begin
		if(!ext_rst_n)
			keyr <=4'b1111;
		else
			keyr <={keyr[2:0],key};
	end
	
	wire key_neg =~keyr[2] &keyr [3];//有按键被按下
	wire key_pos =keyr[2] &~keyr [3];//	有按键被释放

设置一个计数器定时20ms(这里是40ms)

//定时器计数逻辑,用于对按键的消抖的判断
	reg [19:0] cnt;
	always@(posedge ext_clk_25m or negedge ext_rst_n)
	begin
		if(!ext_rst_n)
			cnt <=20'd0;
		else if(key_pos||key_neg)
			cnt <=20'd0;
		else if(cnt <20'd999_999)
			cnt <= cnt +1'b1;
		else
			cnt <=20'd0;
	end

采集按键值

	//定时采取按键值
	always@(posedge ext_clk_25m or negedge ext_rst_n)
	begin
		if(!ext_rst_n)
		begin
			key_value[0] <=5'b11111;
			key_value[1] <=5'b11111;
		end
		else begin
			key_value[1] <=key_value[0];
			if(cnt ==20'd999_999)
				key_value[0] <={key_left,key_righ,key_upup,key_down,key_entr};
			else ;
		end	
	end
	wire [4:0]key_press =key_value[1] & ~key_value[0];

控制LED

	//LED切换控制
	always@(posedge ext_clk_25m or negedge ext_rst_n)
	begin
		if(!ext_rst_n)
			led <=8'hff;
		else if(key_press[0])
			led[0] <=~led[0];
		else if(key_press[1])
			led[1] <=~led[1];
		else if(key_press[2])
			led[2] <=~led[2];
		else if(key_press[3])
			led[3] <=~led[3];
		else if(key_press[4])
			led[4] <=~led[4];
		else ;
	end
endmodule

猜你喜欢

转载自blog.csdn.net/weixin_41445387/article/details/83218220