久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

STM32單片機(jī)按鍵消抖和FPGA按鍵消抖大全

 goandlove 2018-06-25

寫在前面:



按鍵去抖:由上圖可以看出理想波形與實(shí)際波形之間是有區(qū)別的,實(shí)際波形在按下和釋放的瞬間都有抖動(dòng)的現(xiàn)象,,抖動(dòng)時(shí)間的長(zhǎng)短和按鍵的機(jī)械特性有關(guān),,一般為5~10ms。通常我們手動(dòng)按鍵然后釋放,,這個(gè)動(dòng)作中穩(wěn)定閉合的時(shí)間超過(guò)了20ms,。因此單片機(jī)在檢測(cè)鍵盤是否按下時(shí)都要加上去抖動(dòng)操作,有專用的去抖動(dòng)電路,,也有專門的去抖動(dòng)芯片,,但通常我們采用軟件延時(shí)的方法就可以解決抖動(dòng)問(wèn)題。


1,、單片機(jī)中按鍵消抖程序

1.1 單片機(jī)中,,比如STM32中,一般的方法(最簡(jiǎn)單的方法)

軟件消抖程序:

  if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_14)==1) 
            
                  delay_ms(20);//延時(shí)20ms再去檢測(cè)按鍵值
          if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_14)==0)// 相當(dāng)于下降沿

{

KEY1 = 1;  //表示KEY1被按下

}

}

1.2 比較全面的按鍵消抖程序及按鍵狀態(tài)檢測(cè)程序


第一步:初始化全局時(shí)間戳的定時(shí)器,,一般采用SysTick定時(shí)器來(lái)產(chǎn)生,,每ms一次tick即可。


第二步:初始化按鍵對(duì)應(yīng)的IO,,復(fù)用為邊沿觸發(fā)的外部中斷,。


第三步:在外部中斷函數(shù)中添加按鍵事件處理函數(shù),。


代碼部分:

typedefstruct _Key_t  

  u32 last_time;  

  enum  

  {  

    May_Press, 

    Release, 

  }private_state;  

  enum  

  {  

    No_Press, 

    Short_Press,  

    Long_Press,  

  }state;  

}Key_t; 

  

#defineIs_ShortPress_Threshold  1500 

簡(jiǎn)單定義一個(gè)按鍵狀態(tài)的結(jié)構(gòu)體,用于管理每個(gè)按鍵的狀態(tài),。順便再定義一個(gè)長(zhǎng)短按的識(shí)別閾值,,用于區(qū)分按鍵的長(zhǎng)短按。


if(key_state.private_state==Release)         

  if(KEY==0)  

  {  

    key_state.private_state=May_Press;  

    key_state.last_time=course_ms();  

  }  

elseif(key_state.private_state==May_Press) 

  if(KEY==1)  

  {  

    if((course_ms()-key_state.last_time>10)&&(course_ms()-key_state.last_time

    

      key_state.state=Short_Press; 

      key_state.private_state=Release;  

    

    elseif(course_ms()-key_state.last_time>Is_ShortPress_Threshold) 

    

      key_state.state=Long_Press; 

      key_state.private_state=Release;  

    

    else 

      key_state.private_state=Release;  

  }  

以上為需要添加到中斷處理函數(shù)的按鍵事件處理函數(shù),,算法的核心是一個(gè)狀態(tài)機(jī),。在本例中,按鍵被默認(rèn)上拉,,按下接地,。course_ms()為獲取全局時(shí)間戳的函數(shù)。

思路解釋如下:按鍵狀態(tài)結(jié)構(gòu)體有一個(gè)用于識(shí)別的狀態(tài)位,,默認(rèn)處于Release,也就是釋放的狀態(tài),。一旦按鍵被按下,,中斷觸發(fā),此時(shí)檢查是否是Relase狀態(tài),,如果是就檢查按鍵是否被拉低,,如果是,此時(shí)進(jìn)入May_Press狀態(tài),,也就是可能是按下的,,并且記錄此時(shí)的時(shí)間戳,這一步是消抖的關(guān)鍵,。當(dāng)按鍵被釋放,,由于是邊沿觸發(fā),會(huì)再次進(jìn)行處理,,此時(shí)檢查和上一次觸發(fā)之間的時(shí)間戳之差,,如果小于10ms我們就認(rèn)為是抖動(dòng),此時(shí)不會(huì)對(duì)按鍵輸出狀態(tài)進(jìn)行修改,,而是直接將按鍵狀態(tài)置回Relase狀態(tài),,反之檢查差值和長(zhǎng)短按閾值之間的關(guān)系,將state置位為對(duì)應(yīng)的狀態(tài),。消抖的核心在于記錄時(shí)間戳,,而這只是一個(gè)簡(jiǎn)單的賦值操作,并不耗費(fèi)時(shí)間,。


效率上來(lái)說(shuō),,延時(shí)消抖花費(fèi)時(shí)間在無(wú)意義延時(shí)上,而相對(duì)較好的定時(shí)輪詢還是不可避免的在輪詢,,而現(xiàn)在這種方式完全是中斷性質(zhì)的,。唯一多出的開(kāi)銷(全局時(shí)間戳)并不是只可以用于按鍵消抖,,另外在HAL庫(kù)中存在直接獲取tick的函數(shù),這樣實(shí)現(xiàn)就更方便了,。經(jīng)實(shí)際測(cè)試,,消抖效果可以達(dá)到其他兩種消抖算法的水平。


2,、FPGA按鍵消抖程序

首先,,做兩個(gè)假定,以方便后面的描述:

  • 假定按鍵的默認(rèn)狀態(tài)為0,,被按下后為1

  • 假定按鍵抖動(dòng)時(shí)長(zhǎng)小于20ms,,也即使用20ms的消抖時(shí)間

核心:方案

  • 最容易想到的方案

在按鍵電平穩(wěn)定的情況下,當(dāng)?shù)谝淮螜z測(cè)到鍵位電平變化,,開(kāi)始20ms計(jì)時(shí),,計(jì)時(shí)時(shí)間到后將按鍵電平更新為當(dāng)前電平。

  • 或許這才是最容易想的方案

在20ms計(jì)時(shí)的過(guò)程中,,有任何的電平變化都立即復(fù)位計(jì)時(shí)

  • 消除按鍵反應(yīng)延時(shí)抖方案

在有電平變化時(shí)立即改變按鍵輸出電平,,并開(kāi)始20ms計(jì)時(shí),忽略這其中抖動(dòng)

測(cè)試平臺(tái)設(shè)計(jì)(修改代碼以仿真的1us代替實(shí)際1ms)

  • 無(wú)抖動(dòng)上升沿抖動(dòng)5毫秒

  • 下降沿抖動(dòng)15毫秒

  • 上升和下降沿均抖動(dòng)19毫秒

  附加測(cè)試(可以不通過(guò))

  • 抖動(dòng)25毫秒


代碼

方案1

module debounce(    input wire clk, nrst,    input wire key_in,    output reg key_out    );    // 20ms parameter//    localparam TIME_20MS = 1_000_000; localparam TIME_20MS = 1_000; // just for test    // variable reg [20:0] cnt;    reg key_cnt;        // debounce time passed, refresh key state always @(posedge clk or negedge nrst) begin if(nrst == 0)            key_out <=>0;        else if(cnt == TIME_20MS - 1)            key_out <> key_in;    end // while in debounce state, count, otherwise 0 always @(posedge clk or negedge nrst) begin if(nrst == 0)            cnt <=>0;        else if(key_cnt)            cnt <= cnt="" +="">1'b1; else            cnt <=>0;    end // always @(posedge clk or negedge nrst) begin if(nrst == 0)                key_cnt <=>0;            else if(key_cnt == 0 && key_in != key_out)                key_cnt <=>1;            else if(cnt == TIME_20MS - 1)                key_cnt <=>0;     endendmodule


方案2

module debounce(    input wire clk, nrst,    input wire key_in,    output reg key_out    );//    localparam TIME_20MS = 1_000_000; localparam TIME_20MS = 1_000;    reg key_cnt;    reg [20:0] cnt;    always @(posedge clk or negedge nrst) begin if(nrst == 0)            key_cnt <=>0;        else if(cnt == TIME_20MS - 1)            key_cnt <=>0;        else if(key_cnt == 0 && key_out != key_in)            key_cnt <=>1;    end always @(posedge clk or negedge nrst) begin if(nrst == 0)            cnt <=>0;        else if(key_cnt) begin if(key_out == key_in)                cnt <=>0;            else                cnt <= cnt="" +="">1'b1; end else            cnt <=>0;    end always @(posedge clk or negedge nrst) begin if(nrst == 0)                key_out <=>0;            else if(cnt == TIME_20MS - 1)                key_out <> key_in;     endendmodule


方案3

module debounce(    input wire clk, nrst,    input wire key_in,    output reg key_out    );//    localparam TIME_20MS = 1_000_000; localparam TIME_20MS = 1_000; // just for test reg key_cnt;    reg [20:0] cnt;    always @(posedge clk or negedge nrst) begin if(nrst == 0)            key_cnt <=>0;        else if(key_cnt == 0 && key_out != key_in)            key_cnt <=>1;        else if(cnt == TIME_20MS - 1)            key_cnt <=>0;    end always @(posedge clk or negedge nrst) begin if(nrst == 0)            cnt <=>0;        else if(key_cnt)            cnt <= cnt="" +="">1'b1; else            cnt <=>0;    end always @(posedge clk or negedge nrst) begin if(nrst == 0)            key_out <=>0;        else if(key_cnt == 0 && key_out != key_in)            key_out <> key_in;    endendmodule

 

測(cè)試代碼

// 按鍵消抖測(cè)試電路// 時(shí)間單位`timescale 1ns/10ps// modulemodule  debounce_tb;    // time period parameter localparam T = 20;    // variable reg clk, nrst;    reg key_in;    wire key_out;    // instantiate    debounce uut(        .clk    (clk    ),        .nrst   (nrst   ),        .key_in (key_in ),        .key_out(key_out)    );    // clock initial begin        clk = 1;        forever #(T/2) clk = ~clk;    end // reset initial begin        nrst = 1;        @(negedge clk) nrst = 0;        @(negedge clk) nrst = 1;    end // key_in initial begin // initial value key_in = 0;                // wait reset repeat(3) @(negedge clk);                // no bounce        // key down key_in = 1;        // last 60ms repeat(3000) @(negedge clk);        // key up key_in = 0;        // wait 50ms repeat(2500) @(negedge clk);        // down 5ms, up 15ms        // key down, bounce 5ms repeat(251) @(negedge clk) key_in = ~key_in;        // last 60ms repeat(3000) @(negedge clk);        // key up, bounce 15ms repeat(751) @(negedge clk) key_in = ~key_in;        // wait 50ms repeat(2500) @(negedge clk);        // down 19ms, up 19ms        // key down, bounce 19ms repeat(951) @(negedge clk) key_in = ~key_in;        // last 60ms repeat(3000) @(negedge clk);        // key up, bounce 19ms repeat(951) @(negedge clk) key_in = ~key_in;        // wait 50ms repeat(2500) @(negedge clk);                // additional, this situation shoud not ever happen        // down 25ms, up 25ms        // key down, bounce 25ms repeat(1251) @(negedge clk) key_in = ~key_in;        // last 60ms repeat(3000) @(negedge clk);        // key up, bounce 25ms repeat(1251) @(negedge clk) key_in = ~key_in;        // wait 50ms repeat(2500) @(negedge clk);        // stop        $stop;    endendmodule


放在最后的,,并不一定是最不重要的

對(duì)于上面的三種方案,,我比較喜歡第三種方案,它更貼合實(shí)際的按鍵狀態(tài),,以上的代碼我都做過(guò)modelsim仿真,,但還沒(méi)有在實(shí)際的項(xiàng)目中驗(yàn)證。在整理準(zhǔn)備這個(gè)博客的時(shí)候,,我又想到了一個(gè)感覺(jué)是更巧妙的方案,,具體是這樣的:在第三個(gè)方案的基礎(chǔ)上,因?yàn)榘存I輸入有變化的第一時(shí)刻,,輸出就已經(jīng)改變了,,在這種情況下,我可以把計(jì)時(shí)的時(shí)長(zhǎng)改為一個(gè)很小的值,,該值只要比抖動(dòng)中的最長(zhǎng)高低電平變化時(shí)間長(zhǎng)即可,。但想想也沒(méi)這個(gè)必要,且這個(gè)抖動(dòng)的高低電平變化時(shí)長(zhǎng)我也很難去給它界定一個(gè)值,。

    本站是提供個(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)論公約

    類似文章 更多