14.菜鸟初入FPGA之按键消抖(二段式状态机)
0赞
发表于 4/10/2016 5:18:29 PM
阅读(5170)
按键消抖通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开
消抖是为了避免在按键按下或是抬起时电平剧烈抖动带来的影响
结合上节笔记的边沿检测,我们看一下按键消抖例程
代码:
module Key_filter(
clk,
rst_n,
key_in,
key_flag,
key_state
);
input clk,rst_n;
input key_in;
output reg key_state;//按键状态
output reg key_flag;//按键标志输出
// localparam
// idel = 4'b0001, //空闲态
// filter0 = 4'b0010, //抖动滤波
// down = 4'b0100, //按下稳定态
// filter1 = 4'b1000;
////////////////处理外部输入信号////////////////////////
reg key_in1,key_in2;//
//外部输入的异步信号同步化 消除亚稳态
always @(posedge clk or negedge rst_n)
if(!rst_n)begin
key_in1 <= 1'b0;
key_in2 <= 1'b0;
end
else begin
key_in1 <= key_in;
key_in2 <= key_in1;
end
reg key_tmp1,key_tmp2;
//使用两级寄存器,边沿检测
always @(posedge clk or negedge rst_n)
if(!rst_n)begin
key_tmp1 <= 1'b0;
key_tmp2 <= 1'b0;
end
else begin
key_tmp1 <= key_in2;
key_tmp2 <= key_tmp1;
end
wire p_edge,n_edge;
//产生跳变沿信号
assign n_edge = !key_tmp1 & key_tmp2;
assign p_edge = key_tmp1 & (!key_tmp2);
/////////////////计数信号输出//////////////////////
reg [3:0]cnt;
reg en_cnt;//使能计数
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt <= 4'd0;
else if(en_cnt)
cnt <= cnt + 1'b1;
else if(!en_cnt)
cnt <= 4'd0;
//计数满标志
always @(posedge clk or negedge rst_n)
if(!rst_n)
key_flag <= 1'd0;
else if(cnt == 4'd9)
key_flag <= 1'b1;
else
key_flag <= 1'd0;
////////////////状态机模块///////////////////////
reg [3:0]state,NS;//两段式状态机
always @(posedge clk or negedge rst_n)
if(!rst_n) begin
state <= 4'b1;
end
else begin
state <= NS;
end
always @(state or n_edge or p_edge or key_flag)
begin
//en_cnt <= 1'b0;
key_state <= 1'b1;
case(state)
4'd1 : begin
if(n_edge)begin
en_cnt <= 1'b1;
NS <= 4'd2;
end
else
NS <= 4'd1;
end
4'd2 : begin
if(key_flag)begin
NS <= 4'd3;
en_cnt <= 1'b0;
end
else
NS <= 4'd2;
end
4'd3 : begin
key_state <= 1'b0;
if(p_edge)begin
en_cnt <= 1'b1;
NS <= 4'd4;
end
else
NS <= 4'd3;
end
4'd4 : begin
if(key_flag)begin
en_cnt <= 1'b0;
key_state <= 1'b1;
NS <= 4'd1;
end
else
NS <= 4'd4;
end
default : begin
NS <= 4'd1;
en_cnt <= 1'b0;
key_state <= 1'b1;
end
endcase
end
endmodule
`timescale 1ns/1ns
`define clk_period 20
module Key_tb;
reg clk;
reg rst_n;
reg key_in;
wire key_flag;
wire key_state;
Key_filter key_filter0(
.clk(clk),
.rst_n(rst_n),
.key_in(key_in),
.key_flag(key_flag),
.key_state(key_state)
);
initial clk = 1;
always #(`clk_period/2)clk = ~clk;
// always @(posedge clk)//随机函数使用
// begin
// #(`clk_period*100);
// key_in ={$random}%2;
// end
initial begin
rst_n = 0;
key_in = 1;
#(`clk_period*5);
rst_n = 1;
#(`clk_period + 1);
press_key;
#(`clk_period*200);
press_key;
#(`clk_period*200);
press_key;
#(`clk_period*500);
$stop;
end
task press_key;//任务函数的使用
begin
#500 key_in = 0;
#500 key_in = 1;
#500 key_in = 0;
#500 key_in = 1;
#500 key_in = 0;
#500 key_in = 1;
#500 key_in = 0;
#500 key_in = 1;
#500 key_in = 0;
#500 key_in = 1;
#500 key_in = 0;
#500 key_in = 1;
end
endtask
endmodule仿真波形:

关于仿真模型
此时可以使用仿真模型,Augus会使用...但是讲不明白==,很伤情的
需要了解的请查看
发烧友小梅哥专版 http://bbs.elecfans.com/zhuti_fpga_1.html
视频讲的很容易懂
