初學單片機時,講到了一個按鍵“消抖”概念,視屏教程中只是說到要確定按鍵是不是真正按下,所以需要加一個延時來判斷。
附上延時消抖程序代碼:
代碼1
void keypros()
{
if(k1==0) //檢測按鍵K1是否按下
{
delay(1000); //消除抖動 一般大約10ms
if(k1==0) //再次判斷按鍵是否按下
{
//此處添加相應操作
}
while(!k1); //檢測按鍵是否鬆開
}
}
前不久,又瞭解到另外兩個按鍵消抖的代碼
狀態機消抖:
代碼2
#define key_input P3
#define key_state_0 0 //判斷是否按下
#define key_state_1 1 //判斷是否爲抖動
#define key_state_2 2 //判斷是否彈起
unsigned char t0count;
char key_value;
char read_key(void)
{
static char key_state = 0;
char key_press, key_return = 0;
key_press = key_input&key_mask;
switch (key_state)
{
case key_state_0:
if (key_press!=key_mask) key_state = key_state_1;
break;
case key_state_1:
if (key_press!=key_input&key_mask)
{
if(key_press==0x0e) key_return = 1; //S7
if(key_press==0x0d) key_return = 2; //S6
if(key_press==0x0b) key_return = 3; //S5
if(key_press==0x07) key_return = 4; //S4
key_state = key_state_2;
}
else
key_state = key_state_0;
break;
case key_state_2:
if (key_press==0x0f) key_state = key_state_0;
break;
}
return key_return;
}
void tm0_isr() interrupt 1
{
TL0 = 0x18; //設置定時初值
TH0 = 0xFC; //設置定時初值
t0count++;
if(t0count>=2)
{
t0count=0;
key_value=read_key();
}
}
...
if(key_value==...)
{
//對於操作
}
三行代碼消抖:
代碼2
#define KEYPORT P3
typedef unsigned char u8;
u8 Trg;
u8 Cont;
u8 t0count;
void Read_key()
{
u8 readdata=KEYPORT^0xff; //核心代碼1
Trg=readdata&(readdata^Cont); //核心代碼2
Cont=readdata; //核心代碼3
}
void tm0_isr() interrupt 1
{
TL0 = 0x18; //設置定時初值
TH0 = 0xFC; //設置定時初值
t0count++;
if(t0count>=10)
{
t0count=0;
Read_key();
}
}
...
if(Trg==...) //短按
{
//對應操作
}
if(Cont==..) //長按
{
//對應操作
}
三種方法爲什麼都可以“消抖”?
這一問題引起了我的思考。
於是我查詢了什麼是按鍵抖動:按鍵抖動通常的按鍵所用開關爲機械彈性開關,當機械觸點斷開、閉合時,由於機械觸點的彈性作用,一個按鍵開關在閉合時不會馬上穩定地接通,在斷開時也不會一下子斷開。因而在閉合及斷開的瞬間均伴隨有一連串的抖動。
如下圖:
由於單片機的運行速度非常快,按下一次按鍵,可能在A點檢測到一次低電平,在B點檢測到一次高電平,在C點又檢測到一次低電平。同時抖動是隨機,不可測的。那麼按下一次按鍵,抖動可能對會讓單片機誤以爲按下多次按鍵。
延時消抖
最簡單的消抖原理,就是當檢測到按鍵狀態變化後,先等待一個 10ms 左右的延時時間,讓抖動消失後再進行一次按鍵狀態檢測,如果與剛纔檢測到的狀態相同,就可以確認按鍵已經穩定的動作了。
狀態機消抖
與延時消抖大同小異,間隔10ms檢測一次按鍵電位變化,狀態0時檢測到有按鍵電位變化就進入狀態1,狀態1再來確認是否還有變化,有則是按下按鍵。但是由於是利用了定時器,所以在間隔等待10ms時單片機仍可以進行其他進程。
三行代碼消抖
真的佩服。
說起來與狀態機消抖原理差不多也是利用定時器間隔10ms檢測一次按鍵。但是構思非常巧妙。
當沒有按鍵按下時,Trg與Cont均爲0x00。
當單片機執行到此程序且按鍵按下時(假設P3^0按下),Trg與Cont均爲0x01。
當單片機再次執行到此程序且按鍵按下時(假設P3^0按下),Trg爲0x00,Cont爲0x01。
而當按鍵釋放,再次檢測時,Trg與Cont又均爲0x00。(恢復到沒有按鍵按下狀態)