通常的所用开关按键为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开,因而在闭合及断开的瞬间均伴随有一连串的抖动。抖动时间的长短由按键的机械特性决定,一般为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对按键的一次闭合仅作一次处理,不会出现因按键抖动而产生的错误控制。