首页 > 其他 > 详细

按键消抖-----verilog

时间:2015-03-25 11:55:38      阅读:420      评论:0      收藏:0      [点我收藏+]
实际系统中常用的按键大部分都是轻触式按键,如下图所示。该按键内部由一个弹簧片和两个固定触点组成,当弹簧片被按下,则两个固定触点接通,按键闭合。弹簧片松开,两个触点断开,按键也就断开了。根据这种按键的机械特性,在按键按下时,会先有一段时间的不稳定期,在这期间,两个触点时而接通,时而断开,我们称之为抖动,当按键大约按下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:
*******************************************************************************/
 
 module  key_shake (
           clk,
           rst_n,
           
                     key_in,
                     key_out
             );
 input          clk;            //24Mhz
 input          rst_n;
 
 input          key_in;
 output         key_out;
 
 //--------------------------------------
 //在复位之后的100us内,不响应按键的操作
 localparam    t_100us  = 12d2399;
  reg    [11:0]   cnt;
    reg             key_en;         //复位之后允许按键输入标志
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
      cnt <= 0;
            key_en <=0;
    end
  else 
    begin
      if(cnt == t_100us)
              begin
                   key_en <= 1;
                 end
             else
                 begin
                        key_en <= 0; 
                        cnt <= cnt + 1;
                 end
    end
  end
 
 //--------------------------------------------------
 wire         HtoL_flag;         //下降沿标志
 wire         LtoH_flag;         //上升沿标志
 reg   [2:0]   key_reg;
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
      key_reg <= 3b111;            //默认没按下状态为高,按下之后为低.反之则为3b000;
    end
  else 
    begin
      key_reg <= {key_reg[1:0],key_in};  
    end
  end
    
 assign HtoL_flag = key_en?(key_reg[2:1] == 2b10):0;            //下降沿检测,一个时钟的高电平
 assign LtoH_flag = key_en?(key_reg[2:1] == 2b01):0;               //上升沿检测,一个时钟的高电平  
//---------------------------------------------
 reg          cnt_en;                 //计数使能标志
 localparam   t1ms = 16d23999;       //定时1ms 
 reg   [15:0]  cnt2; 
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
      cnt2 <= 16d0;
    end
  else if((cnt_en)&&(cnt2 == t1ms))
    begin
      cnt2 <= 16d0;
    end
    else if(cnt_en)
    begin
      cnt2 <= cnt2 + 16d1;
    end    
    else 
          cnt2 <= 16d0;    
  end
    
 localparam  t_20ms = 5d20;
 reg   [4:0]   cnt3; 
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
       cnt3 <= 5d0;
    end
  else if((cnt_en)&&(cnt2 == t1ms))
    begin
            if(cnt3 == t_20ms )
               cnt3 <= t_20ms;
            else
         cnt3 <= cnt3 + 1;                              
    end
    else if(!cnt_en)
       cnt3 <= 5d0;        
  end
    
//----------------------------------
//按键状态机
    reg  [2:0]  i;
    reg      key_down;        //按键按下标志
    reg      key_up;          //按键释放标志  
    always @(posedge clk or negedge rst_n)
     begin
      if(!rst_n)
       begin
                key_down <= 0;
                key_up <= 0;
                i <= 0;
                cnt_en <= 0;
        end
      else 
        begin
          case(i)
                 d0:
                    begin
                             key_down <= 0;
                       key_up <= 0;    
                      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 <= 1;            //按键按下成功
                                       i <= d3;
                                       cnt_en <= 0;
                                      end
                                    else
                                        begin
                                           key_down <= 0; 
                                         i <= d0;
                                         cnt_en <= 0;        
                                         end
                                 end
                             else
                               cnt_en <= 1;
                            end
                    d2:
                      begin
                            if(cnt3 == t_20ms )
                              begin
                                    if(key_in)                  //检测到按键被释放
                                   begin
                                       key_up <= 1;             //按键释放成功
                                       i <= d3;
                                       cnt_en <= 0;
                                      end
                                    else
                                        begin
                                           key_up <= 0;  
                                         i <= d0;
                                         cnt_en <= 0;        
                                         end
                                 end
                             else
                               cnt_en <= 1;
                            end
                    d3:
                      begin
                             key_up <= 0;  
                             key_down <= 0;            
                             i <= d0;                             
                         end                    
                  default:i <= d0;    
                endcase            
        end
      end
        
 assign      key_out = key_down;         //当按键被按下有效时
// assign   key_out = key_up;         //当按键被释放后才有效时
endmodule
View Code

 测试代码如下:     

技术分享
/********************************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 = 24;
localparam  t = 1000/tck;

always  #(t/2)  clk = ~clk;

task key_in_down;
 begin
     #(3*t)       key_in = 1;
     #(3*t)       key_in = 0;     
     #(8*t)       key_in = 1;
     #(8*t)    key_in = 0;
     #(13*t)   key_in = 1;
     #(13*t)     key_in = 0;
  end
 endtask
 
task key_in_up;
 begin
     #(3*t)        key_in = 0;     
     #(3*t)        key_in = 1;     
   #(8*t)        key_in = 0;     
     #(8*t)        key_in = 1;         
     #(13*t)      key_in = 0;     
     #(13*t)      key_in = 1;                   
  end
endtask
    
initial 
  begin
    clk = 0;
        rst_n = 0;
        key_in = 1;
        
        #(100*t)  rst_n = 1;
        
        #(100*t);
      #(10*t)    key_in_down;
      #(100*t);
      #(10*t)    key_in_up;
        
      #(8000*t);         
    #(10*t) repeat(2)     key_in_down;          //按下时抖动
     
      #(640000*t);                             //按下时间
     
      #(10*t) repeat(2)  key_in_up;            //释放时抖动
        
  end
    
endmodule
View Code

 仿真结果:

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

技术分享

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

 技术分享
  3、按下之后检测以及释放之后的检测。
  技术分享

 

按键消抖-----verilog

原文:http://www.cnblogs.com/fhyfhy/p/4363457.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!