日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

按鍵消抖

 aixuexidewau1 2019-04-14
實(shí)際系統(tǒng)中常用的按鍵大部分都是輕觸式按鍵,如下圖所示。該按鍵內(nèi)部由一個(gè)彈簧片和兩個(gè)固定觸點(diǎn)組成,當(dāng)彈簧片被按下,則兩個(gè)固定觸點(diǎn)接通,按鍵閉合。彈簧片松開(kāi),兩個(gè)觸點(diǎn)斷開(kāi),按鍵也就斷開(kāi)了。根據(jù)這種按鍵的機(jī)械特性,在按鍵按下時(shí),會(huì)先有一段時(shí)間的不穩(wěn)定期,在這期間,兩個(gè)觸點(diǎn)時(shí)而接通,時(shí)而斷開(kāi),我們稱之為抖動(dòng),當(dāng)按鍵大約按下20ms后,兩個(gè)觸點(diǎn)才能處于穩(wěn)定的閉合狀態(tài),按鍵松開(kāi)時(shí)和閉合時(shí)情況類似。而我們的FPGA工作在很高的頻率,按鍵接通或斷開(kāi)時(shí)任何一點(diǎn)小的抖動(dòng)都能輕易的捕捉到,如果不加區(qū)分的將每一次閉合或斷開(kāi)都當(dāng)做一次按鍵事件,那么勢(shì)必一次按鍵動(dòng)作會(huì)被FPGA識(shí)別為很多次按鍵操作,從而導(dǎo)致系統(tǒng)工作穩(wěn)定性下降。

 

 

 輕觸按鍵實(shí)物圖

 

一次按鍵動(dòng)作的大致波形如下圖所示:

 

 

      因此,我們所需要做的工作,就是濾除按鍵按下和釋放時(shí)各存在的20ms的不穩(wěn)定波形。做法思路是:檢測(cè)按鍵按下---》等待20Ms ----》檢測(cè)此時(shí)按鍵鍵值,若為按下值則按下有效,否則按下無(wú)效(后面可以檢測(cè)亦可以不檢測(cè),據(jù)具體情況而定----》檢測(cè)到按鍵松開(kāi)----》延遲20Ms ----》檢測(cè)此時(shí)的鍵值,若為按下值則松開(kāi)無(wú)效,否則按鍵松開(kāi))
硬件電路:    
        獨(dú)立按鍵屬于一種輸入設(shè)備,其與FPGA連接的IO口被接上了10K的上拉電阻,在按鍵沒(méi)有按下時(shí),F(xiàn)PGA會(huì)檢測(cè)到高電平;當(dāng)按鍵按下后,F(xiàn)PGA的IO口上則將呈現(xiàn)低電平。因此,按鍵檢測(cè)的實(shí)質(zhì)就是讀取FPGA的IO上的電平。


獨(dú)立按鍵典型電路
 verilog 程序如下所示:
  
復(fù)制代碼
/********************************Copyright**************************************                           
**----------------------------File information--------------------------
** File name  :key_shake.v  
** CreateDate :2015.03
** Funtions   : 按鍵的消抖操作:在復(fù)位之后的100us內(nèi),不響應(yīng)按鍵的操作,在之后有按鍵按下后,有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, 常數(shù)聲明放到一起,便于修改。
*******************************************************************************/
 
 module  key_shake (
           clk_100M,
           rst_n,
           
            key_in,
            key_out
             );
 input          clk_100M;            //100Mhz
 input          rst_n;
 
 input          key_in;
 output         key_out;
 
 //--------------------------------------
 //在復(fù)位之后的100us內(nèi),不響應(yīng)按鍵的操作
 localparam    t_100us  = 14'd9999;
 localparam    t1ms = 17'd99999;       //定時(shí)1ms 
 localparam    t_20ms = 5'd20;
    
  reg    [13:0]   cnt;
    reg             key_en;         //復(fù)位之后允許按鍵輸入標(biāo)志
 always @(posedge clk_100M 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;         //下降沿標(biāo)志
 wire         LtoH_flag;         //上升沿標(biāo)志
 reg   [2:0]   key_reg;
 always @(posedge clk_100M or negedge rst_n)
 begin
  if(!rst_n)
   begin
      key_reg <= 3'b111;            //默認(rèn)沒(méi)按下?tīng)顟B(tài)為高,按下之后為低.反之則為3'b000;
    end
  else 
    begin
      key_reg <= {key_reg[1:0],key_in};  
    end
  end
    
 assign HtoL_flag = key_en?(key_reg[2:1] == 2'b10):0;            //下降沿檢測(cè),一個(gè)時(shí)鐘的高電平
 assign LtoH_flag = key_en?(key_reg[2:1] == 2'b01):0;               //上升沿檢測(cè),一個(gè)時(shí)鐘的高電平  
//---------------------------------------------
 reg          cnt_en;                 //計(jì)數(shù)使能標(biāo)志

 reg   [16:0]  cnt2; 
 always @(posedge clk_100M or negedge rst_n)
 begin
  if(!rst_n)
   begin
      cnt2 <= 17'd0;
    end
  else if((cnt_en)&&(cnt2 == t1ms))
    begin
      cnt2 <= 17'd0;
    end
    else if(cnt_en)
    begin
      cnt2 <= cnt2 + 17'd1;
    end    
    else 
          cnt2 <= 17'd0;    
  end
    
 reg   [4:0]   cnt3; 
 always @(posedge clk_100M or negedge rst_n)
 begin
  if(!rst_n)
   begin
       cnt3 <= 5'd0;
    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 <= 5'd0;        
  end
    
//----------------------------------
//按鍵狀態(tài)機(jī)
    reg  [2:0]  i;
    reg      key_down;        //按鍵按下標(biāo)志
    reg      key_up;          //按鍵釋放標(biāo)志  
    always @(posedge clk_100M 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;         //檢測(cè)到按下
                            else if(LtoH_flag) i <= 'd2;    //檢測(cè)到釋放按鍵
                            else  i  <= 'd0;
                     end
                    'd1:
                      begin
                            if(cnt3 == t_20ms )
                              begin
                                    if(!key_in)                  //檢測(cè)到按鍵依然被按下
                                   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)                  //檢測(cè)到按鍵被釋放
                                   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;         //當(dāng)按鍵被按下有效時(shí)
// assign   key_out = key_up;         //當(dāng)按鍵被釋放后才有效時(shí)
endmodule
復(fù)制代碼

 

 測(cè)試代碼如下:     

復(fù)制代碼
/********************************Copyright**************************************                           
**----------------------------File information--------------------------
** File name  :key_testbench.v  
** CreateDate :2015.03
** Funtions   :按鍵消抖的測(cè)試文件
** 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;          //按下時(shí)抖動(dòng)
     
      #(640000*t);                             //按下時(shí)間
     
      #(10*t) repeat(2)  key_in_up;            //釋放時(shí)抖動(dòng)
        
  end
    
endmodule
復(fù)制代碼

 仿真結(jié)果:

 1、在復(fù)位之后100us之前按下按鍵時(shí),不響應(yīng)。

 2、抖動(dòng)(按下后20ms之內(nèi)釋放)。

 
  3、按下之后檢測(cè)以及釋放之后的檢測(cè)。
  

 

如果將按鍵按下有效時(shí)刻、按鍵釋放有效時(shí)刻和按鍵所處狀態(tài)全部表現(xiàn)出來(lái),則代碼稍作修改即可:

  

復(fù)制代碼
/********************************Copyright**************************************                           
**----------------------------File information--------------------------
** File name  :key_shake.v  
** CreateDate :2015.03
** Funtions   : 按鍵的消抖操作:在復(fù)位之后的100us內(nèi),不響應(yīng)按鍵的操作,在之后有按鍵按下后,有20ms的延遲,檢測(cè),然后松開(kāi)時(shí)也有20ms的檢測(cè),之后輸出按鍵輸出.
** 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, 常數(shù)聲明放到一起,便于修改。
*******************************************************************************/
 
 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;       //跟隨輸入輸出
 
 //--------------------------------------
 //在復(fù)位之后的100us內(nèi),不響應(yīng)按鍵的操作
   parameter  t_20ms = 5'd20;
     
    `define      CLK_20M
//    `define      CLK_24M
//    `define      CLK_50M
        
  `ifdef   CLK_20M
       parameter  t_100us  = 12'd1999;
         parameter  t1ms = 16'd19999;       //定時(shí)1ms 
    `endif
 
  `ifdef   CLK_20M
       parameter  t_100us  = 12'd2399;
         parameter  t1ms = 16'd23999;       //定時(shí)1ms 
    `endif
 
 
  `ifdef   CLK_20M
       parameter  t_100us  = 13'd4999;
         parameter  t1ms = 16'd49999;       //定時(shí)1ms 
    `endif
 
 

    reg    [12:0]   cnt;
    reg             key_en;         //復(fù)位之后允許按鍵輸入標(biāo)志
  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;         //下降沿標(biāo)志
 wire          LtoH_flag;         //上升沿標(biāo)志
 reg   [2:0]   key_reg;
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
      key_reg <= 3'b111;            //默認(rèn)沒(méi)按下?tīng)顟B(tài)為高,按下之后為低.反之則為3'b000;
    end
  else 
    begin
      key_reg <= {key_reg[1:0],key_in};  
    end
  end
    
 assign HtoL_flag = key_en?(key_reg[2:1] == 2'b10):0;            //下降沿檢測(cè),一個(gè)時(shí)鐘的高電平
 assign LtoH_flag = key_en?(key_reg[2:1] == 2'b01):0;               //上升沿檢測(cè),一個(gè)時(shí)鐘的高電平  
//---------------------------------------------
 reg           cnt_en;                 //計(jì)數(shù)使能標(biāo)志
 reg   [15:0]  cnt2; 
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
      cnt2 <= 16'd0;
    end
  else if((cnt_en)&&(cnt2 == t1ms))
    begin
      cnt2 <= 16'd0;
    end
    else if(cnt_en)
    begin
      cnt2 <= cnt2 + 16'd1;
    end    
    else 
          cnt2 <= 16'd0;    
  end
    

 reg   [4:0]   cnt3; 
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
       cnt3 <= 5'd0;
    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 <= 5'd0;        
  end
    
//----------------------------------
//按鍵狀態(tài)機(jī)
    reg  [2:0]  i;
    reg      key_down;        //按鍵按下標(biāo)志
    reg      key_up;          //按鍵釋放標(biāo)志  
    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;         //檢測(cè)到按下
                 else if(LtoH_flag) i <= 'd2;    //檢測(cè)到釋放按鍵
                 else  i  <= 'd0;
                end
               'd1:
                 begin
                   if(cnt3 == t_20ms )
                       begin
                        if(!key_in)                  //檢測(cè)到按鍵依然被按下
                          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)                  //檢測(cè)到按鍵被釋放
                            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

//---------------------------
 reg          key_out;
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
      key_out <= 1; 
    end
  else 
    begin
      if(key_down)
           key_out <= 0;               //按下為低
      else  if(key_up)
           key_out <= 1;              //釋放為高
      else
           key_out <= key_out;         //否則保持
    end
  end
    
 assign   key_down_out = key_down;         //當(dāng)按鍵被按下有效時(shí)
 assign   key_up_out = key_up;         //當(dāng)按鍵被釋放后才有效時(shí)
 assign   key_in_out = key_out;
endmodule
復(fù)制代碼

 

 

 

仿真:

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多