实际系统中常用的按键大部分都是轻触式按键,如下图所示。该按键内部由一个弹簧片和两个固定触点组成,当弹簧片被按下,则两个固定触点接通,按键闭合。弹簧片松开,两个触点断开,按键也就断开了。根据这种按键的机械特性,在按键按下时,会先有一段时间的不稳定期,在这期间,两个触点时而接通,时而断开,我们称之为抖动,当按键大约按下20ms后,两个触点才能处于稳定的闭合状态,按键松开时和闭合时情况类似。而我们的FPGA工作在很高的频率,按键接通或断开时任何一点小的抖动都能轻易的捕捉到,如果不加区分的将每一次闭合或断开都当做一次按键事件,那么势必一次按键动作会被FPGA识别为很多次按键操作,从而导致系统工作稳定性下降。
 轻触按键实物图
一次按键动作的大致波形如下图所示:
      因此,我们所需要做的工作,就是滤除按键按下和释放时各存在的20ms的不稳定波形。做法思路是:检测按键按下---》等待20Ms ----》检测此时按键键值,若为按下值则按下有效,否则按下无效(后面可以检测亦可以不检测,据具体情况而定----》检测到按键松开----》延迟20Ms ----》检测此时的键值,若为按下值则松开无效,否则按键松开)
硬件电路:    
        独立按键属于一种输入设备,其与FPGA连接的IO口被接上了10K的上拉电阻,在按键没有按下时,FPGA会检测到高电平;当按键按下后,FPGA的IO口上则将呈现低电平。因此,按键检测的实质就是读取FPGA的IO上的电平。




独立按键典型电路
 verilog 程序如下所示:

/********************************Copyright**************************************
**----------------------------File information--------------------------
** File name :key_shake.v
** CreateDate :2015.03
** Funtions : 按键的消抖操作:在复位之后的100us内,不响应按键的操作,在之后有按键按下后,有20ms的延迟,之后输出按键输出.
** Operate on :M5C06N3L114C7
** Copyright :All rights reserved[F].
** Version :V1.0
**---------------------------Modify the file information----------------
** Modified by :
** Modified data :
** Modify Content:V1.1:clk-->clk_100M, 常数声明放到一起,便于修改。
*******************************************************************************/ module key_shake (
clk_100M,
rst_n, key_in,
key_out
);
input clk_100M; //100Mhz
input rst_n; input key_in;
output key_out; //--------------------------------------
//在复位之后的100us内,不响应按键的操作
localparam t_100us = 'd9999;
localparam t1ms = 'd99999; //定时1ms
localparam t_20ms = 'd20; reg [:] cnt;
reg key_en; //复位之后允许按键输入标志
always @(posedge clk_100M or negedge rst_n)
begin
if(!rst_n)
begin
cnt <= ;
key_en <=;
end
else
begin
if(cnt == t_100us)
begin
key_en <= ;
end
else
begin
key_en <= ;
cnt <= cnt + ;
end
end
end //--------------------------------------------------
wire HtoL_flag; //下降沿标志
wire LtoH_flag; //上升沿标志
reg [:] key_reg;
always @(posedge clk_100M or negedge rst_n)
begin
if(!rst_n)
begin
key_reg <= 'b111; //默认没按下状态为高,按下之后为低.反之则为3'b000;
end
else
begin
key_reg <= {key_reg[:],key_in};
end
end assign HtoL_flag = key_en?(key_reg[:] == 'b10):0; //下降沿检测,一个时钟的高电平
assign LtoH_flag = key_en?(key_reg[:] == 'b01):0; //上升沿检测,一个时钟的高电平
//---------------------------------------------
reg cnt_en; //计数使能标志 reg [:] cnt2;
always @(posedge clk_100M or negedge rst_n)
begin
if(!rst_n)
begin
cnt2 <= 'd0;
end
else if((cnt_en)&&(cnt2 == t1ms))
begin
cnt2 <= 'd0;
end
else if(cnt_en)
begin
cnt2 <= cnt2 + 'd1;
end
else
cnt2 <= 'd0;
end reg [:] cnt3;
always @(posedge clk_100M or negedge rst_n)
begin
if(!rst_n)
begin
cnt3 <= 'd0;
end
else if((cnt_en)&&(cnt2 == t1ms))
begin
if(cnt3 == t_20ms )
cnt3 <= t_20ms;
else
cnt3 <= cnt3 + ;
end
else if(!cnt_en)
cnt3 <= 'd0;
end //----------------------------------
//按键状态机
reg [:] i;
reg key_down; //按键按下标志
reg key_up; //按键释放标志
always @(posedge clk_100M or negedge rst_n)
begin
if(!rst_n)
begin
key_down <= ;
key_up <= ;
i <= ;
cnt_en <= ;
end
else
begin
case(i)
'd0:
begin
key_down <= ;
key_up <= ;
if(HtoL_flag) i <= 'd1; //检测到按下
else if(LtoH_flag) i <= 'd2; //检测到释放按键
else i <= 'd0;
end
'd1:
begin
if(cnt3 == t_20ms )
begin
if(!key_in) //检测到按键依然被按下
begin
key_down <= ; //按键按下成功
i <= 'd3;
cnt_en <= ;
end
else
begin
key_down <= ;
i <= 'd0;
cnt_en <= ;
end
end
else
cnt_en <= ;
end
'd2:
begin
if(cnt3 == t_20ms )
begin
if(key_in) //检测到按键被释放
begin
key_up <= ; //按键释放成功
i <= 'd3;
cnt_en <= ;
end
else
begin
key_up <= ;
i <= 'd0;
cnt_en <= ;
end
end
else
cnt_en <= ;
end
'd3:
begin
key_up <= ;
key_down <= ;
i <= 'd0;
end
default:i <= 'd0;
endcase
end
end assign key_out = key_down; //当按键被按下有效时
// assign key_out = key_up; //当按键被释放后才有效时
endmodule

测试代码如下:

/********************************Copyright**************************************
**----------------------------File information--------------------------
** File name :key_testbench.v
** CreateDate :2015.03
** Funtions :按键消抖的测试文件
** Operate on :M5C06N3L114C7
** Copyright :All rights reserved.
** Version :V1.0
**---------------------------Modify the file information----------------
** Modified by :
** Modified data :
** Modify Content:
*******************************************************************************/ module key_testbench; reg clk;
reg rst_n;
reg key_in;
wire key_out; key_shake key_shake_1(
.clk,
.rst_n, .key_in,
.key_out
); localparam tck = ;
localparam t = /tck; always #(t/) clk = ~clk; task key_in_down;
begin
#(*t) key_in = ;
#(*t) key_in = ;
#(*t) key_in = ;
#(*t) key_in = ;
#(*t) key_in = ;
#(*t) key_in = ;
end
endtask task key_in_up;
begin
#(*t) key_in = ;
#(*t) key_in = ;
#(*t) key_in = ;
#(*t) key_in = ;
#(*t) key_in = ;
#(*t) key_in = ;
end
endtask initial
begin
clk = ;
rst_n = ;
key_in = ; #(*t) rst_n = ; #(*t);
#(*t) key_in_down;
#(*t);
#(*t) key_in_up; #(*t);
#(*t) repeat() key_in_down; //按下时抖动 #(*t); //按下时间 #(*t) repeat() key_in_up; //释放时抖动 end endmodule

仿真结果:

1、在复位之后100us之前按下按键时,不响应。

2、抖动(按下后20ms之内释放)。

 

  3、按下之后检测以及释放之后的检测。
  

如果将按键按下有效时刻、按键释放有效时刻和按键所处状态全部表现出来,则代码稍作修改即可:

/********************************Copyright**************************************
**----------------------------File information--------------------------
** File name :key_shake.v
** CreateDate :2015.03
** Funtions : 按键的消抖操作:在复位之后的100us内,不响应按键的操作,在之后有按键按下后,有20ms的延迟,检测,然后松开时也有20ms的检测,之后输出按键输出.
** Operate on :M5C06N3L114C7
** Copyright :All rights reserved[F].
** Version :V1.0
**---------------------------Modify the file information----------------
** Modified by :
** Modified data :
** Modify Content:V1.1:clk-->clk_100M, 常数声明放到一起,便于修改。
*******************************************************************************/ module key_shake (
clk,
rst_n, key_in,
key_down_out,
key_up_out,
key_in_out
);
input clk; //24Mhz
input rst_n; input key_in;
output key_down_out; //按下输出
output key_up_out; //释放输出
output key_in_out; //跟随输入输出 //--------------------------------------
//在复位之后的100us内,不响应按键的操作
parameter t_20ms = 'd20; `define CLK_20M
// `define CLK_24M
// `define CLK_50M `ifdef CLK_20M
parameter t_100us = 'd1999;
parameter t1ms = 'd19999; //定时1ms
`endif `ifdef CLK_20M
parameter t_100us = 'd2399;
parameter t1ms = 'd23999; //定时1ms
`endif `ifdef CLK_20M
parameter t_100us = 'd4999;
parameter t1ms = 'd49999; //定时1ms
`endif reg [:] cnt;
reg key_en; //复位之后允许按键输入标志
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt <= ;
key_en <=;
end
else
begin
if(cnt == t_100us)
begin
key_en <= ;
end
else
begin
key_en <= ;
cnt <= cnt + ;
end
end
end //--------------------------------------------------
wire HtoL_flag; //下降沿标志
wire LtoH_flag; //上升沿标志
reg [:] key_reg;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
key_reg <= 'b111; //默认没按下状态为高,按下之后为低.反之则为3'b000;
end
else
begin
key_reg <= {key_reg[:],key_in};
end
end assign HtoL_flag = key_en?(key_reg[:] == 'b10):0; //下降沿检测,一个时钟的高电平
assign LtoH_flag = key_en?(key_reg[:] == 'b01):0; //上升沿检测,一个时钟的高电平
//---------------------------------------------
reg cnt_en; //计数使能标志
reg [:] cnt2;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt2 <= 'd0;
end
else if((cnt_en)&&(cnt2 == t1ms))
begin
cnt2 <= 'd0;
end
else if(cnt_en)
begin
cnt2 <= cnt2 + 'd1;
end
else
cnt2 <= 'd0;
end reg [:] cnt3;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt3 <= 'd0;
end
else if((cnt_en)&&(cnt2 == t1ms))
begin
if(cnt3 == t_20ms )
cnt3 <= t_20ms;
else
cnt3 <= cnt3 + ;
end
else if(!cnt_en)
cnt3 <= 'd0;
end //----------------------------------
//按键状态机
reg [:] i;
reg key_down; //按键按下标志
reg key_up; //按键释放标志
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
key_down <= ;
key_up <= ;
i <= ;
cnt_en <= ;
end
else
begin
case(i)
'd0:
begin
key_down <= ;
key_up <= ;
if(HtoL_flag) i <= 'd1; //检测到按下
else if(LtoH_flag) i <= 'd2; //检测到释放按键
else i <= 'd0;
end
'd1:
begin
if(cnt3 == t_20ms )
begin
if(!key_in) //检测到按键依然被按下
begin
key_down <= ; //按键按下成功
i <= 'd3;
cnt_en <= ;
end
else
begin
key_down <= ;
i <= 'd0;
cnt_en <= ;
end
end
else
cnt_en <= ;
end
'd2:
begin
if(cnt3 == t_20ms )
begin
if(key_in) //检测到按键被释放
begin
key_up <= ; //按键释放成功
i <= 'd3;
cnt_en <= ;
end
else
begin
key_up <= ;
i <= 'd0;
cnt_en <= ;
end
end
else
cnt_en <= ;
end
'd3:
begin
key_up <= ;
key_down <= ;
i <= 'd0;
end
default:i <= 'd0;
endcase
end
end //---------------------------
reg key_out;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
key_out <= ;
end
else
begin
if(key_down)
key_out <= ; //按下为低
else if(key_up)
key_out <= ; //释放为高
else
key_out <= key_out; //否则保持
end
end assign key_down_out = key_down; //当按键被按下有效时
assign key_up_out = key_up; //当按键被释放后才有效时
assign key_in_out = key_out;
endmodule

仿真:

按键消抖-----verilog的更多相关文章

  1. 强化版按键消抖Verilog实现

    介绍:按键的物理结构导致了会有抖动现象的出现,判断按键是否真正按下,需要把抖动的部分滤波.根据经验可知,抖动一般在20ms内,所以常规的消抖方法是从变化沿出现时刻开始,延时20ms后判断按键的状态.这 ...

  2. 按键消抖VERILOG实现

    对于消抖,有很多种写法.今天分享一下我的写法. 基本思路: 1. 看图                     图1                                           ...

  3. Verilog HDL那些事_建模篇笔记(实验三:按键消抖)

    实验三:按键消抖 首先将按键消抖功能分成了两个模块,电平检查模块和10ms延迟模块.电平检测模块用来检测按键信号的变化(是否被按下),10ms延迟模块用来稳定电平检查模块的输入,进而稳定按键信号,防止 ...

  4. 【代码】verilog之:按键消抖

    此模块完美运行 /*-------------------------------------------------------------------------------------- -- ...

  5. 09A-独立按键消抖实验01——小梅哥FPGA设计思想与验证方法视频教程配套文档

    芯航线--普利斯队长精心奉献   实验目的: 1.复习状态机的设计思想并以此为基础实现按键消抖 2.单bit异步信号同步化以及边沿检测 3.在激励文件中学会使用随机数发生函数$random 4.仿真模 ...

  6. FPGA学习笔记(八)—— 状态机设计实例之独立按键消抖

    ###### [该随笔中部分内容转载自小梅哥] ######### 独立按键消抖自古以来在单片机和FPGA中都是个不可避免的问题,首先,解释一下什么叫做按键抖动,如图,按键在按下和松开的那个瞬间存在大 ...

  7. 09B-独立按键消抖实验02——小梅哥FPGA设计思想与验证方法视频教程配套文档

    芯航线--普利斯队长精心奉献   实验目的: 1.复习按键的设计 2.用模块化设计的方式实现每次按下按键0,4个LED显示状态以二进制加法格式加1,每次按下按键1,4个LED显示状态以二进制加法格式减 ...

  8. 基于FPGA的数字秒表(数码管显示模块和按键消抖)实现

    本文主要是学习按键消抖和数码管动态显示,秒表显示什么的,个人认为,拿FPGA做秒表真是嫌钱多. 感谢 感谢学校和至芯科技,笔者专业最近去北京至芯科技培训交流了一周.老师的经验还是可以的,优化了自己的代 ...

  9. 按键消抖——task任务和仿真平台搭建

    一.按键抖动原理 按键抖动原理:按键存在一个反作用弹簧,因此当按下或者松开时均会产生额外的物理抖动,物理抖动会产生电平的抖动. 消抖方法:一般情况下,抖动的总时间会持续20ms以内,按下按键后,等20 ...

随机推荐

  1. html5的触摸事件

    1.触摸事件有哪些 touchstart,touchmove,touchend 2.分别什么时候触发 touchstart事件:当手指触摸屏幕时候触发,即使已经有一个手指放在屏幕上也会触发. touc ...

  2. 教你搭建SpringSecurity3框架( 更新中、附源码)

    源码下载地址:http://pan.baidu.com/s/1qWsgIg0 一.web.xml <?xml version="1.0" encoding="UTF ...

  3. 取得DIV的ID还是CLASS

    无论你想取得DIV的ID还是CLASS 最重要的是找到你想取值的DIV对象.要取得DIV对象的方法有很多.常用的有2个,一个是根据ID,用var div=document.getElementById ...

  4. 同级兄弟元素之间的CSS控制

    为了实现这个导航效果:选中菜单中某一项,隐藏掉自身的左边背景线条,同时让他的下一个兄弟元素也隐藏掉线条. 有一种选择器就叫兄弟元素选择器,分为临近兄弟和普通兄弟. 临近兄弟:用 + 表示,只匹配该元素 ...

  5. POJ 2121

    http://poj.org/problem?id=2121 一道字符串的转换的题目. 题意:就是把那个英文数字翻译成中文. 思路:首先打表,然后把每一个单独的单词分离出来,在组合相加相乘. #inc ...

  6. pypi 国内镜像 及修改全局方法

    PyPi的官方网站为https://pypi.python.org,有时访问中会很慢,使用pip命令安装带其他依赖包的安装包,会经常失败.解决办法,使用国内PyPi镜像网站,修改pip的源. 网上搜索 ...

  7. 初识 MySQL 5.6 新功能、参数

    摘要: 继上一篇的文章 初识 MySQL 5.5 新功能.参数 之后,现在MySQL5.6 针对 MySQL5.5 各个方面又提升了很多,特别在性能和一些新参数上面,现在看看大致提升了哪些方面(后续不 ...

  8. SaltStack之Master配置文件详解

    salt-master的配置文件位于/etc/salt/master,可用选项如下: #######################主配置 interface默认值:0.0.0.0(所有的网络地址接口 ...

  9. Match:Oulipo(POJ 3461)

     Oulipo 题目大意:给你一个字符串,要你找到字符串包含指定子串的个数 只要你知道了KMP,这一题简直不要太简单,注意STL的string是会超时的,还是乖乖用char吧 #include < ...

  10. 带中文的路径导致NSURL初始化一直为null的问题

    一.问题描述 在学习Ojective-C过程中,需要读取文件中的内容,但发现指针变量url的值一直为nil. 代码如下: NSString *strUrl=@"file:///Users/f ...