按键消抖原理
通常情况下解决按键消抖可以采用当将上图中的第一个实际图转换成第二个方便处理分析的图,在第一次检测到电平波动从上生沿变化下降沿的时候开始计时20ms,下后面的都判断为按下状态;反之在按下状态时检测到上升状态也开始计时20ms将之后的判断为释放状态;以上的思路存在的问题即很可能抖动的时间不止20ms则会判断出错,所以采用下面的方法对按下维持的时间进行判断,若维持20ms及以上则为按下,释放也同理
课程重点:学会状态分析
1:空闲态:等待按键按下(等待下降沿),一旦出现下降沿就开始20ms的计时
2:按下消抖状态:20ms的计时状态,在这个状态里一边计时,一边检测有没有上升沿出现,如果有上升沿,回到空闲态;如果计时满20ms,没有出现上升沿,发出按键按下的通知信号
3:等待释放:等待按键释放(等待上升沿),一旦出现上升沿,就开始20ms的计时
4:释放消抖状态:20ms的计时状态,在这个状态里,一边计时,一边检测有没有出现下降沿,如果有下降沿,回到等待释放状态;如果计时满20ms,没有出现下降沿,发出按键释放的通知信号
源代码:
//此模块为按键消抖模块~
module key_filter(
input Clk,
input Reset,
input Key,
// output reg Key_P_Flag,
// output reg Key_R_Flag,
output Key_Flag,
output reg Key_State
);
reg Key_P_Flag;
reg Key_R_Flag;
assign Key_Flag = (Key_P_Flag | Key_R_Flag);
reg [1:0]r_Key;
always@(posedge Clk)
r_Key<={r_Key[0],Key};
wire pegedge_key;
wire negedge_key;
assign negedge_key=(r_Key==2'b10);
assign pegedge_key=(r_Key==2'b01);
reg [19:0]cnt;
reg [1:0]state;
parameter IDLE=2'b00,P_FILTER=2'b01,WAIT_R=2'b10,R_FILTER=2'b11;
always@(posedge Clk or negedge Reset)begin
if(!Reset)begin
state<=IDLE;
cnt<=0;
Key_P_Flag<=0;
Key_R_Flag<=0;
Key_State<=1;
end
else begin
case(state)
IDLE:begin
Key_R_Flag<=0;
if(negedge_key)
state<=P_FILTER;
else
state<=IDLE;
end
P_FILTER:begin
if(cnt<1000000-1)begin
if(pegedge_key)begin
state<=IDLE;
cnt<=0;
end
else
cnt<=cnt+1;
end
else if(cnt>=1000000-1)begin
Key_P_Flag<=1;
state<=WAIT_R;
cnt<=0;
Key_State<=0;
end
end
WAIT_R:begin
Key_P_Flag<=0;
if(pegedge_key)
state<=R_FILTER;
else
state<=WAIT_R;
end
R_FILTER:begin
if(cnt<1000000-1)begin
if(negedge_key)begin
state<=WAIT_R;
cnt<=0;
end
else
cnt<=cnt+1;
end
else if(cnt>=1000000-1)begin
Key_R_Flag<=1;
state<=IDLE;
cnt<=0;
Key_State<=1;
end
end
endcase
end
end
endmodule
测试文件:
`timescale 1ns / 1ps
module key_filter_tb(
);
reg Clk;
reg Reset;
reg Key;
wire Key_Flag;
wire Key_State;
key_filter key_filter(
Clk,
Reset,
Key,
Key_Flag,
Key_State
);
initial Clk=0;
always#10 Clk=!Clk;
initial begin
Reset=0;
#201
Reset=1;
press_key(2);
$stop;
end
reg [31:0]rand;
task press_key;
input [3:0]seed;
begin
Key=1;
#20000000;
repeat(5)begin
rand={$random(seed)}%10000000;
#rand Key=~Key;
end
Key=0;
#40000000;
repeat(5)begin
rand={$random(seed)}%10000000;
#rand Key=~Key;
end
Key=1;
#40000000;
end
endtask
endmodule
附:下面这个手册比较好用,自己有时间还要再找找!