在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

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

0BFC_eet_china ? 來(lái)源:未知 ? 作者:李倩 ? 2018-06-19 08:55 ? 次閱讀

寫(xiě)在前面:

按鍵去抖:由上圖可以看出理想波形與實(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è)鍵盤(pán)是否按下時(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ù)。

代碼部分:

typedef struct _Key_t

{

u32 last_time;

enum

{

May_Press,

Release,

}private_state;

enum

{

No_Press,

Short_Press,

Long_Press,

}state;

}Key_t;

#define Is_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();

}

}

else if(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;

}

else if(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è)值。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • FPGA
    +關(guān)注

    關(guān)注

    1630

    文章

    21798

    瀏覽量

    606032
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6043

    文章

    44621

    瀏覽量

    638583

原文標(biāo)題:STM32單片機(jī)按鍵消抖和FPGA按鍵消抖大全

文章出處:【微信號(hào):eet-china,微信公眾號(hào):電子工程專輯】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    單片機(jī)按鍵與幾種按鍵電路

    按鍵電路 一、 硬件按鍵電路控制電路 所示利用RC 積分電路來(lái)達(dá)成雜波的濾除與波形修整的
    的頭像 發(fā)表于 12-17 07:45 ?10.6w次閱讀
    <b class='flag-5'>單片機(jī)</b>的<b class='flag-5'>按鍵</b><b class='flag-5'>消</b><b class='flag-5'>抖</b>與幾種<b class='flag-5'>按鍵</b>電路

    51單片機(jī)_獨(dú)立按鍵延時(shí)

    51單片機(jī)_獨(dú)立按鍵延時(shí)_獨(dú)立按鍵定時(shí)器_矩
    發(fā)表于 07-16 13:56

    按鍵及原理是什么

    淺談:在設(shè)計(jì)單片機(jī)按鍵輸入的時(shí)候,進(jìn)行按鍵是防止按鍵輸入被CPU誤讀多次的必要手段。一、
    發(fā)表于 07-21 06:02

    STM32單片機(jī)定時(shí)器做按鍵原因

    STM32單片機(jī)定時(shí)器做按鍵原因:直接用軟件延時(shí)做會(huì)暫用整個(gè)資源,導(dǎo)致
    發(fā)表于 11-26 07:13

    STM32單片機(jī)按鍵和FPGA按鍵的相關(guān)資料分享

    寫(xiě)在前面:STM32單片機(jī)按鍵和FPGA按鍵
    發(fā)表于 01-18 06:39

    51單片機(jī)按鍵有沒(méi)有什么簡(jiǎn)潔又完美的方法?

    51單片機(jī)按鍵有沒(méi)有什么簡(jiǎn)潔又完美的方法
    發(fā)表于 11-01 07:21

    利用狀態(tài)機(jī)按鍵程序

    利用狀態(tài)機(jī)按鍵程序講解,很好的資料下載吧。
    發(fā)表于 01-11 09:32 ?30次下載

    51單片機(jī)的獨(dú)立按鍵按鍵及矩陣按鍵的電路與程序免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是51單片機(jī)的獨(dú)立按鍵按鍵及矩陣按鍵的電路與
    發(fā)表于 07-26 17:36 ?28次下載
    51<b class='flag-5'>單片機(jī)</b>的獨(dú)立<b class='flag-5'>按鍵</b>和<b class='flag-5'>按鍵</b><b class='flag-5'>消</b><b class='flag-5'>抖</b>及矩陣<b class='flag-5'>按鍵</b>的電路與<b class='flag-5'>程序</b>免費(fèi)下載

    使用51單片機(jī)實(shí)現(xiàn)按鍵的資料和程序免費(fèi)下載

    不是測(cè)試過(guò)程。一般不會(huì)選擇通過(guò)狀態(tài)延時(shí)來(lái),而是通過(guò)定時(shí)循環(huán)測(cè)試按鍵的狀態(tài)來(lái)。下面是針對(duì)51單片機(jī)
    發(fā)表于 07-05 17:41 ?5次下載
    使用51<b class='flag-5'>單片機(jī)</b>實(shí)現(xiàn)<b class='flag-5'>按鍵</b><b class='flag-5'>消</b><b class='flag-5'>抖</b>的資料和<b class='flag-5'>程序</b>免費(fèi)下載

    使用51單片機(jī)實(shí)現(xiàn)矩陣按鍵的掃描和動(dòng)作分離的程序免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是使用51單片機(jī)實(shí)現(xiàn)矩陣按鍵的掃描和動(dòng)作分離的程序免費(fèi)下載。
    發(fā)表于 07-04 17:41 ?5次下載
    使用51<b class='flag-5'>單片機(jī)</b>實(shí)現(xiàn)矩陣<b class='flag-5'>按鍵</b>的掃描<b class='flag-5'>消</b><b class='flag-5'>抖</b>和動(dòng)作分離的<b class='flag-5'>程序</b>免費(fèi)下載

    單片機(jī)按鍵電路圖免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是單片機(jī)按鍵電路圖免費(fèi)下載。
    發(fā)表于 07-01 08:00 ?10次下載
    <b class='flag-5'>單片機(jī)</b><b class='flag-5'>按鍵</b><b class='flag-5'>消</b><b class='flag-5'>抖</b>電路圖免費(fèi)下載

    STM單片機(jī)按鍵和FPGA

    閉合的時(shí)間超過(guò)了 20ms。因此單片機(jī)在檢測(cè)鍵盤(pán)是否按下時(shí)都要加上去抖動(dòng)操作,有專用的去抖動(dòng)電路,也有專門的去抖動(dòng)芯片,但通常我們采用軟件延時(shí)的方法就可以解決抖動(dòng)問(wèn)題。 1、單片機(jī)按鍵
    的頭像 發(fā)表于 11-30 17:39 ?2826次閱讀

    單片機(jī)按鍵及原理(硬件和軟件方法詳解)

    淺談:在設(shè)計(jì)單片機(jī)按鍵輸入的時(shí)候,進(jìn)行按鍵是防止按鍵輸入被CPU誤讀多次的必要手段。一、
    發(fā)表于 11-11 12:06 ?15次下載
    【<b class='flag-5'>單片機(jī)</b>】<b class='flag-5'>按鍵</b><b class='flag-5'>消</b><b class='flag-5'>抖</b>及原理(硬件和軟件方法詳解)

    STM32單片機(jī)定時(shí)器做按鍵

    STM32單片機(jī)定時(shí)器做按鍵原因:直接用軟件延時(shí)做會(huì)暫用整個(gè)資源,導(dǎo)致
    發(fā)表于 11-19 11:21 ?32次下載
    STM32<b class='flag-5'>單片機(jī)</b>定時(shí)器做<b class='flag-5'>按鍵</b><b class='flag-5'>消</b><b class='flag-5'>抖</b>

    單片機(jī)按鍵檢測(cè)程序(定時(shí)器法

    單片機(jī)按鍵檢測(cè)程序(定時(shí)器法)相信大家在初學(xué)51單片機(jī)的時(shí)候
    發(fā)表于 11-23 17:51 ?5次下載
    <b class='flag-5'>單片機(jī)</b><b class='flag-5'>按鍵</b>檢測(cè)<b class='flag-5'>程序</b>(定時(shí)器法<b class='flag-5'>消</b><b class='flag-5'>抖</b>)
    主站蜘蛛池模板: 成人久久久精品乱码一区二区三区 | 五月开心六月伊人色婷婷 | 一级做a爰片久久毛片美女图片 | 在线a网 | 国模私拍视频在线 | 国产精品四虎 | 超级乱淫伦网站 | 视频在线观看h | 伊人网在线免费视频 | 天天干天天操天天射 | 成人人免费夜夜视频观看 | 日韩一级片在线免费观看 | aaa在线观看视频高清视频 | 久久精品国产精品亚洲精品 | 亚洲三级电影在线播放 | 韩国三级理论在线看中文字幕 | 天天搞夜夜操 | 成成人看片在线 | 黄 色 免 费 网站在线观看 | 日韩精品无码一区二区三区 | 天天添天天干 | 成年网站在线 | 亚洲酒色1314狠狠做 | 天天看天天做 | 日韩免费一级毛片 | 在线一区二区观看 | 天堂影 | 色婷婷六月桃花综合影院 | 狠狠干天天操 | 免费人成观看在线网 | 91大神精品全国在线观看 | 日本高清视频wwww色 | 国产www在线播放 | 国产亚洲欧美成人久久片 | 国产精品美女一级在线观看 | 天天狠天天天天透在线 | 天天摸夜夜添狠狠添2018 | 欧美1819| 免费在线黄色网 | 欧美性淫爽www视频播放 | 在线免费看影视网站 |