在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ 數(shù)據(jù)庫/ 8.6 單片機按鍵消抖程序
8.3 C 語言函數(shù)的形參和實參
12.2 C 語言指針變量的聲明
12.5 ?C 語言字符數(shù)組和字符指針
7.3 單片機 LED 點陣的介紹
11.5 UART 串口通信的基本應(yīng)用
9.9 單片機蜂鳴器控制程序和驅(qū)動電路
10. 單片機實例練習與經(jīng)驗積累
10.3 單片機交通燈控制程序和設(shè)計原理
9.8 實用的 28BYJ-48 步進電機控制程序
8.2 C 語言函數(shù)的調(diào)用
12.4 C 語言指向數(shù)組元素的指針
7.1 C 語言變量的作用域
11.2 RS232 通信接口
12.7 1602 液晶的讀寫時序介紹
7.2 C 語言變量的存儲類別
8. C 語言函數(shù)進階與單片機按鍵
10.4 51單片機 RAM 區(qū)域的劃分
12.1 C 語言變量的地址
11. UART 串口通信
7. 變量進階與點陣 LED
8.4 單片機按鍵介紹
9.3 電機的分類
9.1 單片機 IO 口的結(jié)構(gòu)
單片機通信實例與 ASCII 碼
8.1 單片機最小系統(tǒng)解析(電源、晶振和復(fù)位電路)
9.2 單片機上下拉電阻
11.4 單片機 IO 口模擬 UART 串口通信
9.5 讓 28BYJ-48 步進電機轉(zhuǎn)起來
9.7 28BYJ-48 步進電機控制程序基礎(chǔ)
12.8 1602 液晶指令介紹
12.3 C 語言指針的簡單示例
8.7 單片機矩陣按鍵的掃描
7.4 單片機 LED 點陣的圖形顯示
8.6 單片機按鍵消抖程序
10.2 單片機中 PWM 的原理與控制程序
7.6 單片機 LED 點陣的橫向移動(動態(tài)顯示)
11.3 USB 轉(zhuǎn)串口通信
12.9 1602 液晶簡單顯示程序
9.4 28BYJ-48 步進電機原理
8.5 ?單片機獨立按鍵掃描程序
12. C 語言指針基礎(chǔ)與1602液晶的初步認識
9. 單片機中的步進電機與蜂鳴器
10.1 單片機數(shù)字秒表程序
7.5 單片機 LED 點陣的縱向移動(動態(tài)顯示)
8.8 單片機簡易加法計算器程序
11.1 單片機串行通信介紹
10.5 單片機長短按鍵的應(yīng)用
12.6 1602 液晶介紹(電路和引腳圖)
9.6 28BYJ-48 步進電機轉(zhuǎn)動精度與深入分析

8.6 單片機按鍵消抖程序

通常按鍵所用的開關(guān)都是機械彈性開關(guān),當機械觸點斷開、閉合時,由于機械觸點的彈性作用,一個按鍵開關(guān)在閉合時不會馬上就穩(wěn)定的接通,在斷開時也不會一下子徹底斷開,而是在閉合和斷開的瞬間伴隨了一連串的抖動,如圖8-10所示。

http://wiki.jikexueyuan.com/project/mcu-tutorial-two/images/21.png" alt="" />

圖8-10 按鍵抖動狀態(tài)圖

按鍵穩(wěn)定閉合時間長短是由操作人員決定的,通常都會在 100 ms 以上,刻意快速按的話能達到 40-50 ms 左右,很難再低了。抖動時間是由按鍵的機械特性決定的,一般都會在 10 ms 以內(nèi),為了確保程序?qū)Π存I的一次閉合或者一次斷開只響應(yīng)一次,必須進行按鍵的消抖處理。當檢測到按鍵狀態(tài)變化時,不是立即去響應(yīng)動作,而是先等待閉合或斷開穩(wěn)定后再進行處理。按鍵消抖可分為硬件消抖和軟件消抖。

硬件消抖就是在按鍵上并聯(lián)一個電容,如圖8-11所示,利用電容的充放電特性來對抖動過程中產(chǎn)生的電壓毛刺進行平滑處理,從而實現(xiàn)消抖。但實際應(yīng)用中,這種方式的效果往往不是很好,而且還增加了成本和電路復(fù)雜度,所以實際中使用的并不多。

http://wiki.jikexueyuan.com/project/mcu-tutorial-two/images/22.png" alt="" />

圖8-11 硬件電容消抖

在絕大多數(shù)情況下,我們是用軟件即程序來實現(xiàn)消抖的。最簡單的消抖原理,就是當檢測到按鍵狀態(tài)變化后,先等待一個 10 ms 左右的延時時間,讓抖動消失后再進行一次按鍵狀態(tài)檢測,如果與剛才檢測到的狀態(tài)相同,就可以確認按鍵已經(jīng)穩(wěn)定的動作了。將上一個的程序稍加改動,得到新的帶消抖功能的程序如下。

#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;

unsigned char code LedChar[] = { //數(shù)碼管顯示字符轉(zhuǎn)換表
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};

void delay();
void main(){
    bit keybuf = 1; //按鍵值暫存,臨時保存按鍵的掃描值
    bit backup = 1; //按鍵值備份,保存前一次的掃描值
    unsigned char cnt = 0; //按鍵計數(shù),記錄按鍵按下的次數(shù)

    ENLED = 0;  //選擇數(shù)碼管 DS1 進行顯示
    ADDR3 = 1;
    ADDR2 = 0;
    ADDR1 = 0;
    ADDR0 = 0;
    P2 = 0xF7;  //P2.3 置0,即 KeyOut1 輸出低電平
    P0 = LedChar[cnt];  //顯示按鍵次數(shù)初值

    while (1){
        keybuf = KEY4;  //把當前掃描值暫存
        if (keybuf != backup){  //當前值與前次值不相等說明此時按鍵有動作
            delay();  //延時大約 10 ms
            if (keybuf == KEY4){  //判斷掃描值有沒有發(fā)生改變,即按鍵抖動
                if (backup == 0){  //如果前次值為0,則說明當前是彈起動作
                    cnt++;  //按鍵次數(shù)+1
                    //只用1個數(shù)碼管顯示,所以加到10就清零重新開始
                    if (cnt >= 10){
                       cnt = 0;
                    }
                    P0 = LedChar[cnt]; //計數(shù)值顯示到數(shù)碼管上
                }
                backup = keybuf; //更新備份為當前值,以備進行下次比較
            }
        }
    }
}
/* 軟件延時函數(shù),延時約 10 ms */
void delay(){
    unsigned int i = 1000;
    while (i--);
}

大家把這個程序下載到板子上再進行試驗試試,按一下按鍵而數(shù)字加了多次的問題是不是就這樣解決了?把問題解決掉的感覺是不是很爽呢?

這個程序用了一個簡單的算法實現(xiàn)了按鍵的消抖。作為這種很簡單的演示程序,我們可以這樣來寫,但是實際做項目開發(fā)的時候,程序量往往很大,各種狀態(tài)值也很多, while(1)這個主循環(huán)要不停的掃描各種狀態(tài)值是否有發(fā)生變化,及時的進行任務(wù)調(diào)度,如果程序中間加了這種 delay 延時操作后,很可能某一事件發(fā)生了,但是我們程序還在進行 delay 延時操作中,當這個事件發(fā)生完了,程序還在 delay 操作中,當我們 delay 完事再去檢查的時候,已經(jīng)晚了,已經(jīng)檢測不到那個事件了。為了避免這種情況的發(fā)生,我們要盡量縮短 while(1)循環(huán)一次所用的時間,而需要進行長時間延時的操作,必須想其它的辦法來處理。

那么消抖操作所需要的延時該怎么處理呢?其實除了這種簡單的延時,我們還有更優(yōu)異的方法來處理按鍵抖動問題。舉個例子:我們啟用一個定時中斷,每 2 ms 進一次中斷,掃描一次按鍵狀態(tài)并且存儲起來,連續(xù)掃描8次后,看看這連續(xù)8次的按鍵狀態(tài)是否是一致的。8次按鍵的時間大概是 16 ms,這 16 ms 內(nèi)如果按鍵狀態(tài)一直保持一致,那就可以確定現(xiàn)在按鍵處于穩(wěn)定的階段,而非處于抖動的階段,如圖8-12。

http://wiki.jikexueyuan.com/project/mcu-tutorial-two/images/23.png" alt="" />

圖8-12 按鍵連續(xù)掃描判斷

假如左邊時間是起始0時刻,每經(jīng)過 2 ms 左移一次,每移動一次,判斷當前連續(xù)的8次按鍵狀態(tài)是不是全1或者全0,如果是全1則判定為彈起,如果是全0則判定為按下,如果0和1交錯,就認為是抖動,不做任何判定。想一下,這樣是不是比簡單的延時更加可靠?

利用這種方法,就可以避免通過延時消抖占用單片機執(zhí)行時間,而是轉(zhuǎn)化成了一種按鍵狀態(tài)判定而非按鍵過程判定,我們只對當前按鍵的連續(xù) 16 ms 的8次狀態(tài)進行判斷,而不再關(guān)心它在這 16 ms 內(nèi)都做了什么事情,那么下面就按照這種思路用程序?qū)崿F(xiàn)出來,同樣只以 K4 為例。

#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;

unsigned char code LedChar[] = {  //數(shù)碼管顯示字符轉(zhuǎn)換表
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
bit KeySta = 1;  //當前按鍵狀態(tài)

void main(){
    bit backup = 1;  //按鍵值備份,保存前一次的掃描值
    unsigned char cnt = 0;  //按鍵計數(shù),記錄按鍵按下的次數(shù)
    EA = 1;  //使能總中斷
    ENLED = 0;  //選擇數(shù)碼管 DS1 進行顯示
    ADDR3 = 1;
    ADDR2 = 0;
    ADDR1 = 0;
    ADDR0 = 0;
    TMOD = 0x01; //設(shè)置 T0 為模式1
    TH0 = 0xF8; //為 T0 賦初值 0xF8CD,定時 2 ms
    TL0 = 0xCD;
    ET0 = 1;  //使能 T0 中斷
    TR0 = 1;  //啟動 T0
    P2 = 0xF7;  //P2.3 置 0,即 KeyOut1 輸出低電平
    P0 = LedChar[cnt];  //顯示按鍵次數(shù)初值

    while (1){
        if (KeySta != backup){  //當前值與前次值不相等說明此時按鍵有動作
            if (backup == 0){  //如果前次值為0,則說明當前是彈起動作
                cnt++;  //按鍵次數(shù)+1
                if (cnt >= 10){  //只用1個數(shù)碼管顯示,所以加到10就清零重新開始
                    cnt = 0;
                }
                P0 = LedChar[cnt]; //計數(shù)值顯示到數(shù)碼管上
            }
            //更新備份為當前值,以備進行下次比較
            backup = KeySta;
        }
    }
}
/* T0 中斷服務(wù)函數(shù),用于按鍵狀態(tài)的掃描并消抖 */
void InterruptTimer0() interrupt 1{
    //掃描緩沖區(qū),保存一段時間內(nèi)的掃描值
    static unsigned char keybuf = 0xFF;

    TH0 = 0xF8; //重新加載初值
    TL0 = 0xCD;
    //緩沖區(qū)左移一位,并將當前掃描值移入最低位
    keybuf = (keybuf<<1) | KEY4;
    //連續(xù)8次掃描值都為0,即 16 ms 內(nèi)都只檢測到按下狀態(tài)時,可認為按鍵已按下
    if (keybuf == 0x00){
        KeySta = 0;
    //連續(xù)8次掃描值都為1,即 16 ms 內(nèi)都只檢測到彈起狀態(tài)時,可認為按鍵已彈起
    }else if (keybuf == 0xFF){
        KeySta = 1;
    }
    else{
        //其它情況則說明按鍵狀態(tài)尚未穩(wěn)定,則不對 KeySta 變量值進行更新
    }
}

這個算法是我們在實際工程中經(jīng)常使用按鍵所總結(jié)的一個比較好的方法,介紹給大家,今后都可以用這種方法消抖了。當然,按鍵消抖也還有其它的方法,程序?qū)崿F(xiàn)更是多種多樣,大家也可以再多考慮下其它的算法,拓展下思路。