基础项目(6)基于尖峰脉冲的按键消抖程序设计讲解

 写在前面的话

我们通常所用的按键开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会马上断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了避免这种现象造成的干扰而作的措施就是按键消抖。

抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。键抖动会引起一次按键被误读多次。为确保智能单元对按键的一次闭合仅作一次处理,必须消除键抖动。在按键闭合稳定时读取键的状态,并且必须判别到按键释放稳定后再作处理。按键的消抖,可用硬件或软件两种方法,梦翼师兄这里主要介绍一下软件的消除方法。

基于尖峰脉冲的按键消抖

尖峰脉冲是电路设计中非常重要的一种信号,很多层次化设计中模块间的握手信号一般都会使用尖峰脉冲,正确的应用尖峰脉冲信号,可以有效的减少系统的逻辑冗余,提高系统稳定性和执行效率。本节,我们就来学习如何利用尖峰脉冲实现按键消抖。

项目需求

用一个按键控制数码管显示,数码管显示的数值为按键的次数,每按一次按键,数码管显示的数值加一,数值从0-F循环显示。

误区排除

由于数码管在之前的章节中已经有很详细的论述,所以这里我们忽略数码管驱动部分,把注意力放在按键次数的累加模块。说到这里,很多人的脑海中可能会出现下述代码:


always @ (posedge clk or negedge rst_n)

begin

if (!rst_n)

begin

sum <= 1‘b0; //赋初值

end

else

begin

if (!key_in) //有按键按下

sum <= sum + 1; //计数器加1

else

sum <= sum; //计数值不变

end

end

这个always块的主要意思是如果检测到按键变为低电平,则说明有按键按下,然后就开始计数累加。这是最容易想到的一种错误方式,假设我们按键按下的时间特别长,那么key_in就会一直保持为低电平,我们的sum计数值也就会因此而不断累加。这与我们每按键一次,计数值只加一的目标是不相符的,而且这种方式并不能处理电路中遇到的抖动。

那么,我们该如何是好呢?分析上述电路,我们发现计数值不断累积加的原因在于每次按键按下,key_in都会保持多个周期的低电平。那么我们是否能产生这样一个信号呢-每次按键按下,不管按键时间如何,该信号能且仅能维持一个时钟周期的高电平。如果可以产生出这样的尖峰脉冲,那么我们就可以实现每次按键,计数值加且只加一的结果。

设计思路

为了证实上述想法的可行性,接下来我们设计流程图如下:

结构说明:当检测到有按键按下时,为了消除抖动,我们启动延时计数器,如果按键保持低电平的时间足够长,那么计数值一定会满足我们设置好的延时条件,否则计数清零,等待下次按键到来。如果延时计数满足条件,说明确定有按键按下,那么我们就可以输出一个尖峰脉冲,从而控制sum累加。

系统框架

顶层端口描述


端口名


端口说明


Clk


系统50MHz时钟输入


rst_n


系统低电平复位


key_in


系统外部按键输入


Sum


输出按键累加值

6.6.8 代码解释


/****************************************************

*   Engineer      :   梦翼师兄

*   QQ             :   761664056

*   The module function:按键消抖模块 *****************************************************/

01  module pulse(

02                  //系统输入

03                  clk,//系统50MHZ时钟输入

04                  rst_n,//低电平复位信号输入

05                  key_in,//外部按键输入

06                  //系统输出

07                  sum//按键次数计数器

08               );

09

10  //-----------------系统输入---------------------

11  input clk;//系统50MHZ时钟输入

12  input rst_n;//低电平复位信号输入

13  input key_in;//外部按键输入

14

15  //-----------------系统输出---------------------

16  output reg [3:0]sum;//按键次数计数器

17

18  //------------------寄存器定义------------------

19  reg [10:0]counter;//消抖延时计数器

20  reg state;//状态寄存器

21  reg pos_flag;//尖峰脉冲寄存器

22

23  //----------按键消抖以后产生尖峰脉冲------------

24  always@(posedge clk or negedge rst_n)

25      begin

26          if(!rst_n)

27              begin

28                  counter<=0; //消抖延时计数器清零

29                  state<=0;   //状态寄存器清零

30                  pos_flag<=0;//尖峰脉冲寄存器清零

31              end

32          else

33              begin

34                  case(state)

35                  0:begin

36                      if(counter<10)//消抖延时计数器未开始计数

37                          begin /*key_in==0,说明有按键按下*/

38                              if(!key_in)

39                                  begin

40      /*消抖延时计数器开始计数*/       counter<=counter+1;

41                                  end

42          //key_in==1,说明按键放开,而此时计数值未满,

43          //说明刚才的“按键”是抖动

44                              else

45                                  begin

46          /*消抖延时计数器清零*/     counter<=0;

47                                  end

48                          end

49                      else//计数值满,说明确定有按键按下

50                          begin

51                      //尖峰脉冲寄存器置为高电平

52                              pos_flag<=1;

53                              counter<=0;//消抖延时计数器清零

54                              state<=1;//跳转到下一状态

55                          end

56                  end

57                  1:begin

58                      pos_flag<=0;//尖峰脉冲寄存器置为低电平

59          //key_in==1,说明按键放开(一次按键动作完整结束)

60                      if(key_in)

61                          state<=0;//状态返回,等待下次按键到来

62                  end

63                  default:state<=0;//状态返回

64                  endcase

65              end

66      end

67  //-----------------------累计尖峰脉冲出现次数-----------------------

68  always@(posedge clk or negedge rst_n)

69      begin

70          if(!rst_n)

71              begin

72                  sum<=0;//按键计数器清零

73              end

74          else

75              begin

76                  if(pos_flag)//尖峰脉冲到来,说明按键按下

77                      sum<=sum+1;//按键计数器累加

78              end

79      end

80  endmodule

当检测到有按键按下时,延时计数器开始计数,在计数的这段时间如果检测到按键是放开的,我们认为是按键抖动,计数器清零,等待下一次的按键按下,如果按键一直按下并满足我们预先设置的最大计数值,我们认为是真正有按键按下,延时计数器清零,pos_flag 信号拉高,状态向下跳转。在下一个状态  pos_flag 信号拉低,如果检测到按键放开,状态跳转到上一个状态等待下一次按键按下。这样就产生了一个周期的尖峰脉冲。从第68行到结束,当检测到一个尖峰脉冲的时候,按键计数器加1。

编写测试代码如下:


/****************************************************

*   Engineer      :   梦翼师兄

*   QQ             :   761664056

*   The module function:按键消抖测试模块 *****************************************************/

01  `timescale 1ns/1ps

02

03  module tb;

04

05  //-----------------------系统输入-----------------------

06  reg clk;//系统50MHZ时钟输入

07  reg rst_n;//低电平复位信号输入

08  reg key_in;//外部按键输入

09

10  //-----------------------系统输出-----------------------

11  wire [3:0]sum;//按键次数计数器

12

13  //-----------------------产生测试激励-------------------

14  initial

15      begin

16          clk=0;

17          rst_n=0;

18          key_in=1;

19          # 1000.1 rst_n=1;

20  //-------------------模拟按键动作-------------------

21          # 1000 key_in=0;

22          # 1000 key_in=1;

23          # 100  key_in=0;

24          # 100  key_in=1;

25          # 300  key_in=0;

26          # 300  key_in=1;

27          # 100  key_in=0;

28          # 200  key_in=1;

29          # 1000 key_in=0;

30          # 900  key_in=1;

31          # 1000 key_in=0;

32          # 800  key_in=1;

33          # 1000 key_in=0;

34          # 1000 key_in=1;

35  //----------------------------------------------

36      end

37

38  always #10 clk=~clk;//50MHZ晶振

39

40  //----------------实例化被测试模块----------------

41  pulse  pulse (

42                  //系统输入

43                  .clk(clk),//系统50MHZ时钟输入

44                  .rst_n(rst_n),//低电平复位信号输入

45                  .key_in(key_in),//外部按键输入

46                  //系统输出

47                  .sum(sum)//按键次数计数器

48               );

49  endmodule

 仿真分析

我们再放大标示线区域:

由上述波形可以看出,当按键按下以后,计数器首先开始计数,当计数值不满足时,计数器清零并等待下一次按键按下。当计数值满足以后,才会输出一个时钟周期的尖峰脉冲,而按键次数寄存器sum也会在尖峰脉冲的作用下开始累加。每次按键按下,只会出现一次尖峰脉冲,说明我们的设计是正确的。

本设计中,我们只是消除了按键按下时候的抖动而按键放开时候的抖动我们并没有处理梦翼师兄希望大家可以自行将改代码填充完整

原文地址:https://www.cnblogs.com/mengyi1989/p/11518347.html

时间: 2024-10-31 20:13:02

基础项目(6)基于尖峰脉冲的按键消抖程序设计讲解的相关文章

按键消抖学习

KevinChen的博客——KevinChen's Blog [博客大赛]按键消抖之终极解决方案 http://bbs.ednchina.com/BLOG_ARTICLE_3020402.HTM EE_FPGA基础教程系列 -- 按键消抖  http://wenku.baidu.com/link?url=CGJkd0CRwzW-dreuF5FSiNWbUDHGE6HQIO3A8kWmERPkJmkr9vh2YOPLq3vKC8wvkaLxOa4iwSVM-ESqiODsvJwOrOpNTS24_

按键消抖之终极解决方案

1.按键消抖的原理 图1.按键抖动示意图 我们平常所用的按键为机械弹性开关,由于触点的弹性作用,按键在闭合时不会马上稳定的接通,而是有一段时间的抖动,在断开时也不会立即断开.抖动时间由按键的机械特性所决定,一般为5ms~10ms.所以我们在做按键检测时都要加一个消抖的过程. 按键消抖主要有两种方案: 一是延时重采样:二是持续采样. 从理论上来说,延时(如10ms)重采样的准确率肯定低于持续采样. 2.按键消抖的方法 (1)延时重采样 延时重采样的意思是,当第一次检测到键值由'1'变为'0'时,再

关于按键消抖实验

对于特权同学按键消抖程序的理解:(程序源码见<深入浅出玩转FPGA>P191) 第一个always块中,在每个时钟周期(clk)对按键值进行采样 第二个always块中,利用边沿脉冲检测法,当key_rst有下降沿时,key-an将输出一个周期的高脉冲 第三个always块中,利用cnt进行循环计数(计数时间周期大约20ms),当keg-an为1时,cnt将清零,然后从零开始计数(由此产生一个20ms,从而消除抖动部分的影响) 第四个always块中,每当cnt从0计数到20'hfffff(即

从简单的按键消抖开始

笔者正在接受FPGA的线上培训,以接近尾声,就水平来说算是入门.设计时发现做些设计总结非常重要,可以帮助自己理清思路,同时也能得到很好的复习,便于日后回顾.之前一直在做altera FPGA的相关学习,对xilinx还不是很熟悉,借着这个契机,将比较基础常用的设计在VIVADO开发环境中过一遍,对我来说是个不错的选择.废话不多说,进入今天的正题. 众所周知,硬件按键都存在机械抖动.所以一次人为按下的动作会触发数次按键按下的行为.所谓"按键消抖"模块的功能就是将抖动滤除掉,保证对按键状态

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

芯航线--普利斯队长精心奉献 ? 实验目的: 1.复习按键的设计 2.用模块化设计的方式实现每次按下按键0,4个LED显示状态以二进制加法格式加1,每次按下按键1,4个LED显示状态以二进制加法格式减1 实验平台:芯航线FPGA核心板 实验原理:???? ????在上一讲中设计并验证了独立按键的消抖,这里基于上一讲的按键消抖模块来实现一个加减法计数器,并以此学习模块化的设计方式. ????在设计过程中,相对大一点的工程经常通常不会写在一个设计文件中,通常会针对不同的功能设计出不同的子文件,最后在

jQueryAjax模拟按键消抖(可设置抖动延迟时间)

在硬件中,按键等都会有抖动现象,如何消除抖动,不重复触发事件呢,这就要用到消抖机制了. 这是我用jQuery模拟硬件消抖原理,额,可能是吧...又不对的地方,希望有高手指点指点. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

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

实验三:按键消抖 首先将按键消抖功能分成了两个模块,电平检查模块和10ms延迟模块.电平检测模块用来检测按键信号的变化(是否被按下),10ms延迟模块用来稳定电平检查模块的输入,进而稳定按键信号,防止其抖动而产生的信号跳变而影响输出. 设计思路:     1.当电平检测模块检查到按键被按下(输入由高电平变为低电平),则拉高H2L_Sig电平,然后拉低. 2.10ms延迟模块,检测到H2L_Sig高电平,则对其进行10ms过滤,拉高输出. 3.当按键被释放,电平检测模块会拉高L2H_Sig电平,然

FPGA培训专家 V3学院带你学习 按键消抖 和 边缘检测

FPGA培训专家 V3学院 一般情况下,我们从按下按键到松开基本需要大于几十毫秒的时间,系统时钟的周期处于纳秒级,因此我们按下一次按键会被大于十万个时钟的上升沿采集到,然而我们希望的是按下一次按键只被一次上升沿采集到,不然会被认为按了多次按键,所以我们需要对我们的按键进行处理.假设按键在没被按下时为高电平,被按下时处于低电平,如图1所示的波形图. 图1 按键波形图 由图1 分析可知在key被按下时有且仅有一个key的上升沿和一个key的下降沿,我们可以通过检测key的上升沿或者下降沿来确定按键被

手动按键复位程序(包含按键消抖)

1 //这是一个按键复位程序 2 module stable_key( 3 i_clkin, 4 i_inKey, 5 o_outKey 6 ); 7 8 input i_clkin; 9 input i_inKey; 10 output o_outKey; 11 12 reg key=1; 13 reg key_get = 1; //key输出指示信号 14 reg [20:0] cntK = 0; 15 reg o_outKey_r = 1; 16 17 always@(posedge i_