1. 按鍵消抖
產(chǎn)生原因:
按鍵內(nèi)部的觸點出現(xiàn)了接觸不良的振動。通過儀器觀察,圖1-1是按鍵按下過程中CP端實際電平改變情況。T1為不按按鍵時刻,T2為按鍵按下瞬間的抖動,T3為按鍵按下穩(wěn)定時刻,T4為按鍵放開時刻瞬間,T5為按鍵放開時刻。從圖中可以了解到,按鍵按下的瞬間由于撞擊會使觸點來回彈跳,雖然時間一瞬間,但T2時間內(nèi)獲得了多個電平的上升沿。
(1-1)
按鍵抖動時間的長短由按鍵的機械特性決定,一般為5ms~10ms。在單片機系統(tǒng)中,按鍵可以直接連接在單片機的I/O口上,可以利用程序延時操作消除鍵盤的抖動現(xiàn)象。
2. 按鍵輸入程序
2.1 按鍵抬起有效
不同的人對鍵按鍵按下的時間長短有很大差別,按鍵按下抬起有效控制方式主要是為了避免按鍵按下所停留(粘滯)時間對控制結(jié)果的影響。程序設計時,按鍵按下抬起有效需控制編程需要注意幾個方面:首先,按鍵抖動時間一般在10毫秒以內(nèi),按鍵按下需要消除抖動;第二,按鍵按下不管時間有多長,LED不受控制;第三,按鍵抬起瞬間LED狀態(tài)才發(fā)生改變。按鍵按下抬起有效控制LED閃爍的程序處理過程見圖1-2所示。
(1-2)
#include
sbit key1 = P2^1; // key1接 P2.1
sbit LED = P0^0; // LED接P0.0
void delay(unsigned int x) //延時函數(shù)
{
while(x--);
}
void key(void)
{
if(key1 == 0) //如果按鍵按下
{
delay(300); //延時消除按鍵抖動,大約20毫秒
while(key1 == 0);//如果按鍵真的按下,等待按鍵抬起
LED = !LED;
}
}
void main(void)
{
P0 = 0x00; //讓LED全滅
while(1)
key(); //調(diào)用按鍵函數(shù)
}
2.2 按鍵按下有效
2.2.1 按鍵按下經(jīng)過消抖后就應該立即控制LED的狀態(tài)
if(key1 == 0)
{
delay(300);
if(key1 == 0)LED = !LED;
while(key1 == 0);//等待
}
2.2.2 重復按壓按鍵可立即控制LED,需記錄按鍵狀態(tài)
bit key_flag;
if(key1 == 1)key_flag = 0;
if(key1 == 0)
{
delay(300);
if(key1 == 0)key_flag = 1;
}
2.2.3 按鍵一直按壓先等待一段時間后,LED狀態(tài)自動轉(zhuǎn)換,不受按鍵控制。
while(key1 == 0 ) //如果按鍵按下不抬起
{
i++; //累計等待時間
if(i >= 7)LED = !LED; //按下累計等待時間到了,按鍵狀態(tài)變化
delay(20000);//長按按鍵后,利用延時控制LED狀態(tài)變換速度
}
3. 矩陣按鍵
3.1 電路原理
單片機4×4矩陣鍵盤見仿真電路1-3所示,電路采用Proteus軟件設計。圖中16個按鍵占用P2的8個端口,其中P2的低4位連接列線,高4位連接行線;兩個共陽數(shù)碼管段選端連接P0口,公共端分別連接P1.0和P1.1;網(wǎng)絡標號相同的引腳具有連接關(guān)系。
4×4矩陣鍵盤程序采用I/O口掃描與檢測原理,其步驟是先讓某一個行線設置為低電平,再檢測列線上的按鍵是否按下,如果此時某個按鍵按下,與之連接的列線也被拉低。比如當行線P2.4 設置為低電平時,如果按下按鍵K0、K1、K2、K3中某一個,即可以拉低P2.0、P2.1、P2.2、P2.3中對應的端口,此時通過查詢P2狀態(tài),系統(tǒng)就可以獲知是哪一個按鍵實際按下。
(1-3)
3.2 電路圖
3.3 程序設計
本項目實現(xiàn)的目的是系統(tǒng)檢測并讓數(shù)碼如顯示這個按鍵的編號。
#include
code P1_scan[]={0x7f,0xbf,0xdf,0xef}; //按鍵掃描數(shù)組
code key_temp_value[]={0xee,0xed,0xeb,0xe7,0xde,0xdd,
0xdb,0xd7,0xbe,0xbd,0xbb,0xb7,0x7e,0x7d,0x7b,0x77}; //按鍵按下所對應的值
code unsigned char seven_seg[10]={0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90};
void delay(unsigned int x) //延時函數(shù)
{
while(x--);
}
unsigned char key_scan() //鍵盤掃描函數(shù)
{
unsigned i,j;
for(i=0;i<4;i++) //讓每個列線出現(xiàn)低電平(按鍵掃描數(shù)據(jù))
{
P1=P1_scan[i];
if(P1!=P1_scan[i])
{
delay(200); //消抖
if(P1!=P1_scan[i])
{
for(j=0;j<16;j++) //檢測按鍵值
{
if(P1==key_temp_value[j])
return(j); //返回按鍵值
}
}
}
}
return(88);
}
void display(unsigned char i)
{
P2=~0x01;P0 = seven_seg[i%10]; //顯示按鍵編號個位
delay(300); //讓個位顯示一段時間
P2=~0x02;P0 = seven_seg[i/10]; //顯示按鍵編號十位
delay(300); //讓十位顯示一段時間
P0 = 0xff; //消隱
}
void main()
{
unsigned char i;
while(1)
{
i = key_scan();
display(i);
}
}