由于最近论坛课程安排时间比较久,就去看了一些FPGA大神们的文章,最近看了一位大神的关于按键消抖的文章,很受益,就自己写了个工程来加深对按键消抖的理解,由于代码比较简单就没有写testbench,如有谬误,恭请指正。
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer: Charles Wang
//
// Create Date: 10/27/2014
// Design Name: keyinput
// Module Name: keyinput
// Project Name: keyinput
// Target Devices: EP4CE6E22C8
// Tool versions: Quartus II 12.0
// Description: 根据按键的单击与长击,分别点亮一个Led
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module keyinput(key,sys_clk,sys_rst_n,led);
input key;//按键输入
input sys_clk;//
input sys_rst_n;//异步复位,低电平有效
output [1:0]led;//LED 输出驱动
reg [27:0]cnt;
reg rst_n_r1;
reg rst_n_r2;
reg P1,P2;
wire isH2L;
wire isL2H;
parameter T50MS= 28'd2_500_000,
T5S = 28'd250_000_000;
//////////////////////////////////////////////////////////////////////////////////
//将sys_rst_n 同步化
always@(posedge sys_clk)
begin
{rst_n_r2,rst_n_r1} <= {rst_n_r1,sys_rst_n};
end
//////////////////////////////////////////////////////////////////////////////////
//用P2,P1分别保存第一和第二个时钟的按键值
always@(posedge sys_clk or negedge rst_n_r2)
begin
if(!rst_n_r2)
begin
{P2,P1} <= 2'b11;
end
else
begin
{P2,P1} <= {P1,key};
end
end
assign isH2L = (P2 == 1'b1) && (P1 == 1'b0);
assign isL2H = (P2 == 1'b0) && (P1 == 1'b1);
reg [3:0]i;
reg isLClick;//用isLClick 作为长按标志,isSClick 作为单击
reg isSClick;
reg [1:0]flag;
//////////////////////////////////////////////////////////////////////////////////
always@(posedge sys_clk or negedge rst_n_r2)
begin
if(!rst_n_r2)
begin
i <= 4'd0;
isLClick <= 1'b0;
isSClick <= 1'b0;
flag <= 2'd0;
cnt <= 28'd0;
end
else
case(i)
4'd0: //等待按键按下
if(isH2L)
begin
i <= i + 1'b1;
end
4'd1://按下后消抖
if(cnt == T50MS - 1'b1)
begin
cnt <= 28'd0;
i <= i + 1'b1;
end
else
cnt <= cnt + 1'b1;
4'd2://判断是否是长按
if({P2,P1} == 2'b00 && cnt >= T5S - 1'b1)
begin
cnt <= 28'd0;
i <= i + 1'b1;
flag <= 2'd1;
end
else if(isL2H)
begin
cnt <= 28'd0;
i <= i + 1'b1;
flag <= 2'd2;
end
else
cnt <= cnt + 1'b1;
4'd3://步骤3和4是为了产生一组高脉冲isLClick,isSClick
if(flag == 2'd1)
begin
isLClick <= 1'b1;
i <= i + 1'b1;
end
else if(flag == 2'd2)
begin
isSClick <= 1'b1;
i <= i + 1'b1;
end
4'd4:
begin
isLClick <= 1'b0;
isSClick <= 1'b0;
i <= i + 1'b1;
end
4'd5://等待按键释放
if(isL2H)
begin
i <= i + 'b1;
end
4'd6://释放后消抖
if(cnt == T50MS - 1'b1)
begin
cnt <= 28'd0;
i <= 4'd0;
flag<= 2'd0;
end
else
cnt <= cnt + 1'b1;
default: i <= 4'd0;
endcase
end
//////////////////////////////////////////////////////////////////////////////////
//让led2,led1 根据isLClick,isSClick高脉冲不停的反转
reg led1,led2;
always@(posedge sys_clk or negedge rst_n_r2)
begin
if(!rst_n_r2)
begin
{led2,led1} <= 2'b11;
end
else if(isSClick)
begin
led1 <= ~led1;
end
else if(isLClick)
begin
led2 <= ~led2;
end
end
assign led = {led2,led1};//使用led1,led2驱动led
endmodule
现象如下链接:
http://v.youku.com/v_show/id_XODEyODcxOTEy.html
我要赚赏金
