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

分享

[博客大賽]按鍵消抖之終極解決方案

 鹿港小鎮(zhèn)1989 2014-05-05
1.按鍵消抖的原理

                 圖1.按鍵抖動示意圖

我們平常所用的按鍵為機械彈性開關(guān),由于觸點的彈性作用,按鍵在閉合時不會馬上穩(wěn)定的接通,而是有一段時間的抖動,在斷開時也不會立即斷開。抖動時間由按鍵的機械特性所決定,一般為5ms~10ms。所以我們在做按鍵檢測時都要加一個消抖的過程。

按鍵消抖主要有兩種方案:

一是延時重采樣;二是持續(xù)采樣。

從理論上來說,延時(如10ms)重采樣的準確率肯定低于持續(xù)采樣。
2.按鍵消抖的方法
(1)延時重采樣
延時重采樣的意思是,當?shù)谝淮螜z測到鍵值由'1'變?yōu)?0'時,再延時一段時間(如10ms),再次采樣,確認是否仍是'0';若是'0'則認為此時鍵值為'0',否則,重新執(zhí)行檢測過程。
這個方案在特權(quán)同學(xué)的《深入淺出玩轉(zhuǎn)FPGA》的p191有例程;
該方案的缺陷:a.如果延時太短,有可能兩次采樣時都處于抖動時間,因此可能引起誤判;
                         b.如果延時太長,可能檢測不出按鍵變換
(2)持續(xù)采樣
持續(xù)采樣的原理是,當檢測到按鍵處于某電平(如'0')時,在之后的N個時鐘周期內(nèi)連續(xù)檢測此按鍵的電平,如果一直不變,則讀出此按鍵的電平值(如'0')。
持續(xù)采樣的優(yōu)點:a.樣本足夠多,減少誤判的可能性。
                            b.對于按鍵按下('1'->'0'),按鍵釋放('0'->'1')都可以檢測。
持續(xù)采樣的缺點:持續(xù)檢測的時間太長(大于按鍵按下和釋放的時間差),則可能無法檢測按鍵的變換。
1)單個按鍵的檢測
按鍵檢測的輸出有兩種方式:1.電平輸出,此時按鍵功能猶如撥碼開關(guān)。
                                              2.脈沖輸出,此時每按下一次按鍵,輸出一個脈沖信號。
 
                     圖2.按鍵檢測輸出波形示意圖
如圖2所示,Key_out1的輸出與Key_in的變換趨勢相同,只是濾除了抖動成分;
Key_out2則是每當按鍵按下后輸出一個高電平脈沖。在大多數(shù)的應(yīng)用中會用到Key_out2所示功能。
輸出為電平(用于電平判斷事件,類似于開關(guān)選擇)
module key_scan
#(parameter DURATION = 1200)//the number of clk period
(
input wire clk, //120MHz
input wire rst_n,
input wire key_in,
output reg key_out
);
//key jitter filter
reg[11:0] low_cnt;
reg[11:0] high_cnt;
always @(posedge clk or negedge rst_n)
begin
 if(!rst_n)
  begin
       low_cnt <= 0;
       high_cnt <= 0;
  key_out <= 1'b1;
  end
 else
       begin
       if(key_in == 1'b0)
           begin
           high_cnt <= 0;
           if(low_cnt == DURATION)
               begin low_cnt <= low_cnt; key_out <= 1'b0; end
           else
               low_cnt <= low_cnt + 1'b1;
           end
       else //key_in == 1'b1
           begin
           low_cnt <= 0;
           if(high_cnt == DURATION)
               begin high_cnt <= high_cnt;key_out <= 1'b1; end
           else
               high_cnt <= high_cnt + 1'b1;
           end
       end
end
endmodule
輸出為脈沖(用于脈沖觸發(fā)事件)
module key_scan
#(parameter DURATION = 1200)//the number of clk period
(
input wire clk, //120MHz
input wire rst_n,
input wire key_in,
output wire key_out
);
//key jitter filter
reg[11:0] low_cnt;
always @(posedge clk or negedge rst_n)
begin
 if(!rst_n)
        low_cnt <= 0;
 else
        begin
        if(key_in == 1'b0)
            begin
            if(low_cnt == DURATION)
                low_cnt <= low_cnt;
            else
                low_cnt <= low_cnt + 1'b1;
            end
        else //key_in == 1'b1
            low_cnt <= 0;
        end
end
assign key_out = (low_cnt == DURATION -1)? 1'b1 : 1'b0;
endmodule
2)多個獨立按鍵的掃描(掃描得出鍵值)
功能:a.可以檢測出哪些鍵按下了,甚至哪些鍵同時按下了。
           b.鍵值更新后,輸出一個脈沖信號,提升更新完成;
           c.鍵值保持到下一次更新完成。
module key_counter_scan
#(
 parameter KEY_WIDTH = 4
)
(
 //global clock
 input clk,
 input rst_n,
 //key interface
 input [KEY_WIDTH-1:0] key_data,
 //user interface
 output reg key_flag,
 output reg [KEY_WIDTH-1:0] key_value //H Valid
);
//-----------------------------------
//Register key_data for compare
reg [KEY_WIDTH-1:0] key_data_r;
always @(posedge clk or negedge rst_n)
begin
 if(!rst_n)
  key_data_r <= {KEY_WIDTH{1'b1}};
 else
  key_data_r <= key_data;
end
//-----------------------------------
//continue 20ms
localparam DELAY_TOP = 20'd1000_000;
//localparam DELAY_TOP = 20'd1000; //Just for test
reg [19:0] delay_cnt;
//-----------------------------------
//Key scan via counter detect.
always @(posedge clk or negedge rst_n)
begin
 if(!rst_n)
  delay_cnt <= 0;
 else
  begin
  if((key_data == key_data_r) && (key_data != {KEY_WIDTH{1'b1}})) //20ms counter jitter
   begin
   if(delay_cnt < DELAY_TOP)
    delay_cnt <= delay_cnt + 1'b1;
   else
    delay_cnt <= DELAY_TOP;
   end
  else
   delay_cnt <= 0;
  end
end
//-----------------------------------
//the complete of key_data capture
wire key_trigger = (delay_cnt == DELAY_TOP - 1'b1) ? 1'b1 : 1'b0;
//-----------------------------------
//output the valid key_value via key_trigger
always@(posedge clk or negedge rst_n)
begin
 if(!rst_n)
  key_value <= {KEY_WIDTH{1'b0}};
 else if(key_trigger)
  key_value <= ~key_data_r;
 else
  key_value <= key_value;
end
//---------------------------------
//Lag 1 clock for valid read enable
always@(posedge clk or negedge rst_n)
begin
 if(!rst_n)
  key_flag <= 0;
 else
  key_flag <= key_trigger;
end
endmodule

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

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多