按下和松开机械按钮有一个抖动过程,大约10ms到15ms具体取决于实际情况。如果我们不消除这种抖动,我们想要的效果将得到一个非常不确定的值。例如,我想要的是按下数字管显示1,然后按下数字管显示2,依次显示3、4、5、6;如果我不摇晃,我可以按下上面的每个值,所以我不能达到我想要的目的。
真实按键效果如下:
如下:
当然,也有机械按钮不需要抖动的设计,比如复位按钮。复位按钮要求我在按下复位按钮后将系统恢复到原始状态或设定状态。在按钮和松开过程中抖动多少次对结果没有影响,因此无需抖动。
现在我们很清楚,按下按钮,没有松开等待过程和松开过程,只有按下和松开有机械抖动的效果。所以我们所要做的就是判断按下按钮的那一刻ms的延时,然后等待按键松开的那一刻,再做一个延时,整个过程就完成了。
下面给出Verilog(50系统时钟M,低电平复位,按下低电平按钮)
module shake1( input clk, //系统时钟 input rstn, ///低电平复位 input key, //按键 output reg shape //输出消抖波形 ); reg [17:0]t10ms; //10毫秒计数 reg t; always@(posedge clk or negedge rstn) begin if(!rstn) t<=0; else t<=key; end wire thl=(!rstn) t<=0; else t<=key; end wire thl=(!key)&&t; ///检测下降边缘 wire tlh=key&&(!t); ///上升沿检测 reg [1:0]cm; always@(posedge clk or negedge rstn) begin if(!rstn) ///复位清零 begin shape<=0; t10ms<=0; cm<=0; end else case(cm) 0:begin if(thl&&(t10ms==0)) //下降沿到来(按下按钮),计数为零 cm<=1; end 1:begin if(t10ms>=249999) //10毫秒延迟结束,shape为高电平 begin t10ms<=0; cm<=2; shape<=1; end else //起始值shape为低电平 begin t10ms<=t10ms 1; shape<=0; end end 2:begin if(tlh&&(t10ms==0)) ///上升沿到来(松开按钮),计数为零 begin t10ms<=1; cm<=3; end shape<=0; //设shape为低电平 end 3:begin if(t10ms>=249999) //10毫秒延迟结束 begin t10ms<=0; cm<=0; end else t10ms<=t10ms 1; end default:cm<=0; endcase end endmodule
如果要按键,加计数器,可以shape波形是计数器的时钟。
下面给出Verilog(50系统时钟M,低电平复位,按下低电平按钮)
module shake1( input clk, //系统时钟 input rstn, ///低电平复位 input key, //按键 output reg [3:0]count ///输出计数(按键数) ); reg [17:0]t10ms; //10毫秒计数 reg t; always@(posedge clk or negedge rstn) begin if(!rstn) t<=0; else t<=key; end wire thl=(!rstn) t<=0; else t<=key; end wire thl=(!key)&&t; ///检测下降边缘 wire tlh=key&&(!t); ///上升沿检测 reg [1:0]cm; reg shape; //消抖波形 always@(posedge clk or negedge rstn) begin if(!rstn) ///复位清零 begin shape<=0; t10ms<=0; cm<=0; end else case(cm) 0:begin if(thl&&(t10ms==0)) //下降沿到来(按下按钮),计数为零 cm<=1; end 1:begin if(t10ms>=249999) //10毫秒延迟结束,shape为高电平 begin t10ms<=0; cm<=2; shape<=1; end else //起始值shape为低电平 begin t10ms<=t10ms 1; shape<=0; end end 2:begin if(tlh&&(t10ms==0)) begin ///上升沿到来(松开按钮),计数为零 t10ms<=1; cm<=3; end shape<=0; //设shape为低电平 end 3:begin if(t10ms>=249999) //10毫秒延迟结束 begin t10ms<=0; cm<=0; end else t10ms<=t10ms 1; end default:cm<=0; endcase end always@(posedge shape or negedge rstn) begin if(!rstn) count<=0; else if(count>=9) //设置按钮计数的最大值为9,需要修改的值为9 count<=0; else count<=count 1; end endmodule