1. 实验目标
本章节中,我们要根据机械按键的构造与原理,设计并实现按键消抖模块。以开发板上的物理按键作为输入信号,使用设计的按键消抖模块对输入的按键信号进行消抖处理, 输出能够正常使用的按键触发信号。
2. 理论学习
我们所使用的按键开关为机械弹性开关,当机械触点断开、闭合时, 由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而做的措施就是按键消抖。
抖动时间的长短由按键的机械特性决定,一般为 5ms~10ms。按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。按键抖动会引起一次按键被误读多次。为确保控制器对按键的一次闭合仅作一次处理,必须去除按键的抖动。在按键闭合稳定时读取按键的状态,并且必须判别到按键释放稳定后再作处理。
消抖是为了避免在按键按下或是抬起时电平剧烈抖动带来的影响。按键的消抖,可用硬件或软件两种方法。
2.1 硬件消抖
通过加一个RS触发器来进行按键消抖,但硬件消抖会使用一些额外的器件占用电路板上的空间,从而在一定程度上增加了 PCB 布局布线的复杂度。
2.2 软件消抖
如果按键个数较多,常用软件方法去抖,即检测出按键闭合后执行一个延时程序,根据抖动的时间为 5ms~10ms,我们产生一个 20ms 的延时,让前沿抖动消失后再一次检测键的状态,如果仍保持闭合状态电平,则确认为真正有键按下。
用软件消抖的方式来实现去抖动的操作,去抖动后的效果是当按键按下后能够准确检测到按键被按下了一次,而不会因机械抖动发生按键重复多次按下的现象。
3. 实战演练
设计并实现一个按键消抖模块,将外部输入的单比特按键信号做消抖处理后输出,输出信号正常可被其他模块调用。
3.1 按键消抖模块框图
一个输入信号就是按键的输入 key_in,输出信号为去抖动后的稳定的按键信号 key_flag(去抖后按键被按下的标志信号)。
3.2 波形图
CLK 50MHZ = 20ns 计数20ms 计数值为M = 999_999
4 代码编写
module key_filter
#(
parameter CNT_MAX = 20'd999_999
)
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire key_in ,
output reg key_flag
);
reg [19:0] cnt_20ms;
always @ (posedge sys_clk or negedge sys_rst_n)
if (sys_clk == 1'b0)
cnt_20ms <= 20'b0;
else if (key_in == 1'b1)
cnt_20ms <= 20'b0;
else if ((cnt_20ms == CNT_MAX)&&(key_in == 1'b0))
cnt_20ms <= cnt_20ms;
else
cnt_20ms <= cnt_20ms + 1'b1;
always @ (posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
key_flag <= 1'b0;
else if (cnt_20ms == CNT_MAX - 1'b1)
key_flag <= 1'b1;
else
key_flag <= 1'b0;
endmodule
5. 仿真验证
`timescale 1ns / 1ns
module tb_key_filter();
//parameter define
//为了缩短仿真时间,我们将参数化的时间值改小
//但位宽依然定义和参数名的值保持一致
//也可以将这些参数值改成和参数名的值一致
parameter CNT_1MS = 20'd19 ,
CNT_11MS = 21'd69 ,
CNT_41MS = 22'd149 ,
CNT_51MS = 22'd199 ,
CNT_60MS = 22'd249 ;
reg sys_clk;
reg sys_rst_n;
reg key_in;
reg [7:0] tb_cnt;
wire key_flag;
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
always #10 sys_clk = ~sys_clk;
//tb_cnt:按键过程计数器,通过该计数器的计数时间来模拟按键的抖动过程
always @(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
tb_cnt <= 8'd0;
else if (tb_cnt == CNT_60MS)
tb_cnt <= 8'd0;
else
tb_cnt <= tb_cnt + 8'd1;
//key_in:产生输入随机数,模拟按键的输入情况
always @(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
key_in <= 1'b1;
else if ((tb_cnt >= CNT_1MS && tb_cnt <= CNT_11MS)||(tb_cnt >= CNT_41MS&&tb_cnt <= CNT_51MS))
key_in <= {$random} % 2;
else if ((tb_cnt >= CNT_11MS)&&(tb_cnt <= CNT_41MS))
key_in <= 1'b0;
else
key_in <= 1'b1;
key_filter
#(
.CNT_MAX (20'd24)
//修改的 CNT_MAX 值一定要小于(CNT_41MS - CNT_11MS)
//否则就会表现为按键一直处于“抖动状态”而没有“稳定状态”
//无法模拟出按键消抖的效果
)
key_filter_inst
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key_in (key_in),
.key_flag (key_flag)
);
endmodule
5. 仿真波形分析