如果按键较多,常用软件方法去抖,即检测出键闭合后执行一个延时程序,5ms~10ms的延时,让前沿抖动消失后再一次检测键的状态,如果仍保持闭合状态电平,则确认为真正有键按下。当检测到按键释放后,也要给5ms~10ms的延时,待后沿抖动消失后才能转入该键的处理程序。
一般来说,软件消抖的方法是不断检测按键值,直到按键值稳定。实现方法:假设未按键时输入1,按键后输入为0,抖动时不定。可以做以下检测:检测到按键输入为0之后,延时5ms~10ms,再次检测,如果按键还为0,那么就认为有按键输入。延时的5ms~10ms恰好避开了抖动期。
矩阵键盘原理:以4*4矩阵键盘开发板为例,默认4条列线上来高电平,4条行线默认接高电平。通常使用行扫描的方法来确认矩阵键盘上哪个按键被按下。检查方法如下:
(1)判断键盘中有无键按下:将全部行线置低,然后检查列线的状态。只要有一列为低,则证明有按键按下。
(2)逐次将行线设为低电平,当行线为低电平时,逐次检查列线,若状态为低,则列线与行线相交的地方则为按键位置
先令key_r为输出(可以随意赋值,为行线),另逐次检查的列线为输入key_c,由于列线按键为输入异步值,需打拍异步处理
assign key_r=4'b0000;
列线异步处理
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
key_c_ff0<=4'b1111;
key_c_ff1<=4'b1111;
end
else begin
key_c_ff0<=key_c;
key_c_ff1<=key_c_ff0;
end
end
if(rst_n==1'b0)begin
key_c_ff0<=4'b1111;
key_c_ff1<=4'b1111;
end
else begin
key_c_ff0<=key_c;
key_c_ff1<=key_c_ff0;
end
end
判断是否有按键按下,考虑消抖,需要判断延时20ms的情况,若只是单纯的在key_c_ff1!=4'b1111的情况下,计时20ms,再判断
key_c_ff1!=4'b1111则是典型的顺时设计方法,无法实现。分析该思路,有延时,在延时后的某个状态实现,需用到状态机。
延时20ms的计数器及计时20ms的标志设计如下
20ms计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)
cnt <= cnt;
else
cnt <= cnt + 1;
end
else begin
cnt<=0;//不连续则清0
end
end
assign add_cnt =key_c_ff1!=4'b1111 ;
assign end_cnt = add_cnt && cnt>=TIME_20US ;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
shake_cnt<=0;
end
else if(end_cnt) begin
shake_cnt<=1;
end
else begin
shake_cnt<=0;
end
end
//异步信号处理
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
shake_cnt_ff0<=1'b0;
shake_cnt_ff1<=1'b0;
end
else begin
shake_cnt_ff0<=shake_cnt;
shake_cnt_ff1<=shake_cnt_ff0;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)
cnt <= cnt;
else
cnt <= cnt + 1;
end
else begin
cnt<=0;//不连续则清0
end
end
assign add_cnt =key_c_ff1!=4'b1111 ;
assign end_cnt = add_cnt && cnt>=TIME_20US ;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
shake_cnt<=0;
end
else if(end_cnt) begin
shake_cnt<=1;
end
else begin
shake_cnt<=0;
end
end
//异步信号处理
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
shake_cnt_ff0<=1'b0;
shake_cnt_ff1<=1'b0;
end
else begin
shake_cnt_ff0<=shake_cnt;
shake_cnt_ff1<=shake_cnt_ff0;
end
end
在单片机设计中该算法是用顺序方法写的。FPGA使用并行算法,使用状态机进行设计。状态机的跳转条件涉及到时间一般使用计数器,状态的跳转和转变包括一些变量值的变化和输出。以明德扬例子为例
状态机设计
CHK_COL:检查列线是否有低电平,并且没有抖动,保持20ms以上
CHK_ROW: 逐个将行线置低电平,检查列线是否有低电平
DELAY: 由于输出行线,再得到列线,有一定延时
WAIT_END:等待结束,即列线全部为1
CHK_COL:检查列线是否有低电平,并且没有抖动,保持20ms以上
CHK_ROW: 逐个将行线置低电平,检查列线是否有低电平
DELAY: 由于输出行线,再得到列线,有一定延时
WAIT_END:等待结束,即列线全部为1