圖1 矩陣鍵盤電路
本實例我們來學習矩陣鍵盤(行列式鍵盤)的電路設計、編程實現。目的是通過較少的I/O口來識別多個按鍵。
我們在前面已經學習過獨立按鍵,在獨立按鍵電路中,一個按鍵連接單片機的一位I/O埠。這樣通過檢測I/O的狀態就能很方便的識別該按鍵是否按下。這種電路的優點是:電路簡單,程序簡單,缺點是一個按鍵就要佔用一個I/O口。我們知道,51單片機總共只有4個8位I/O口,如果外部電路功能較多,I/O口就會不夠用,例如如果電路中接了一個8位數碼管,又接了16個按鍵,那麼即使數碼管採用動態掃描法 也需要佔用16個I/O口(8位I/O口用於連接數碼管8個段,另8位I/O口用於控制8位數碼管的每一位),這時如果按鍵還是採用獨立按鍵的接法,每個按鍵接一位I/O口,那麼又要佔用16個I/O口,這樣就把單片機的I/O口全部佔完了,如果這時候想加一個蜂鳴器,就沒有多餘的I/O口了。所以很與必要考慮如何用較少的I/O口實現更多的功能。
矩陣鍵盤就是基於用較少I/O口連接更多按鍵的思路實現的。通常將多個按鍵排列成矩陣形式,這也是矩陣鍵盤名稱的由來,編程時,是按照矩陣的行、列組合判斷是那個按鍵被按下的,因此又稱為行列式鍵盤。
最常見的矩陣鍵盤是4*4鍵盤,其實現方法是將16個按鍵按照4x4矩陣方式連接,如下圖所示。從連接方式來看,有4根行線和4根列線。每個行線和列線的交匯處就是一個按鍵位。這樣總共有8根線就可以實現16個按鍵的檢測,比一個按鍵連接一個I/O口節省了一半的I/O埠。
圖2 矩陣鍵盤結構
矩陣鍵盤的工作原理
一般矩陣鍵盤都會將按鍵按照一定的規律賦予不同的標號(例如按照從左到右的順序,或者從上到下的順序),當檢測到有按鍵按下後,根據被按下的按鍵序號賦予一定的鍵值。程序中就可以根據鍵值進行相應的處理。
在51單片機中,對於矩陣鍵盤的處理方法是:使用行列掃描法,將鍵盤的行線和列線分別連接到單片機的I/O口線上,然後按照如下步驟操作:
第一步:判斷是否有按鍵按下
將行線全部輸出低電平,全部列線輸出高電平,然後將列線置為輸入狀態,檢測列線的狀態,只要有一根列線為低電平 ,就表示矩陣鍵盤中有按鍵被按下了。
第二步:按鍵消除抖動
在第一步中如果檢測到有按鍵按下,則使用軟體消抖的方法延時20ms左右,再次判斷是否有列線為低電平,如果仍有列線為低電平,則認為確實有按鍵被按下,則進入到第三步處理,否則,認為是抖動,不予識別,繼續回到第一步重新開始按鍵檢測。
第三步:按鍵識別
確認有按鍵被按下後,接下來就是最關鍵的內容:確定那個按鍵被按下。這需要用逐行掃描的方法來確定。先掃描第一行,即將第一行對應的埠輸出低電平,然後讀每一列的電平,當出現某一列為低電平,說明該列與第一行的交叉點的按鍵被按下,如果所有列都是高電平,說明第一行的按鍵都未被按下,那麼開始掃描第二行,以此類推,直到找到被按下的鍵所在的行與列的交叉點。
第四步:鍵值確定
在第三步中,當確定有按鍵被按下,則按照事先確定好的按鍵序號,根據行與列的交叉位置確定鍵值。簡直一般按照一定的規律排列,例如1,2,3,4....。例如確定第一行第一列的交叉點按鍵為1號按鍵,第一行與第二列交叉點的按鍵為2號按鍵....第四行與第四列的交叉點的按鍵為16號按鍵。
本實例電路圖如圖1所示。矩陣鍵盤電路與單片機的P3口的8額I/O連接,P0口連接一個共陽極數碼管,用於演示按鍵序號,指示那個按鍵被按下。
本實例程序代碼如下。
為了能讓大家更為直觀的理解矩陣鍵盤的掃描原理,本例的代碼非常詳細的列出了整個矩陣鍵盤的行列掃描過程,沒有採用更簡潔的編程方法。
#include<AT89X51.h> //
sbit P34=P3^4; //埠引腳定義
sbit P35=P3^5; //
sbit P36=P3^6; //
sbit P37=P3^7; //
//共陽極數碼管段碼錶,0~9,A,b,c,d,E,F,H,P
unsigned char code Tab[ ]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89}; //
//定義鍵值的全局變量
unsigned char keyval;
//延時函數
void led_delay(void)
{
unsigned char j;
for(j=0;j<200;j++)
;
}
//數碼管顯示鍵值
void display(unsigned char k)
{
P0=Tab[k]; //鍵值送數碼管顯示
led_delay(); //延時
}
// void delay20ms(void)
{
unsigned char i,j;
for(i=0;i<100;i++)
for(j=0;j<60;j++)
;
}
void main(void)
{
EA=1; //總中斷開啟
ET0=1; //定時器T0中斷開啟
TMOD=0x01; //定時器T0工作方式1
TH0=(65536-500)/256; //定時器初值
TL0=(65536-500)%256; //定時器初值
TR0=1; //開啟定時器
keyval=0x00; //鍵值初始化為0
P2=0xFC;//數碼管公共端打開,允許顯示
while(1)
{
display(keyval); //數碼管顯示鍵值
}
}
//定時器T0中斷服務程序
void time0_interserve(void) interrupt 1 using 1
{
TR0=0; //進中斷後,先關閉定時器
P3=0xf0; //行線電平全部置低電平,列線全部置高電平
if((P3&0xf0)!=0xf0) //如果列線中有低電平,說明有鍵被按下
delay20ms(); //延時,消除按鍵抖動
if((P3&0xf0)!=0xf0) //消抖後仍有列線為低電平,則認為確實有按鍵按下
{
//掃描第一行
P3=0xfe; //行線第一行置低電平,
if(P34==0) //第一列為低電平,則第一行第一列的按鍵按下
keyval=1; //按下的按鍵的鍵值
if(P35==0) //第二列為低電平,則第一行第二列按鍵按下
keyval=2; //鍵值
if(P36==0) //第三列為低電平,則第一行第三列按鍵按下
keyval=3;
if(P37==0) //第四列為低電平,則第一行第四列按鍵按下
keyval=4; //
//掃描第二行
P3=0xfd;
if(P34==0)
keyval=5;
if(P35==0)
keyval=6;
if(P36==0)
keyval=7;
if(P37==0)
keyval=8;
//掃描第三行
P3=0xfb;
if(P34==0)
keyval=9;
if(P35==0)
keyval=10;
if(P36==0)
keyval=11;
if(P37==0)
keyval=12;
//掃描第四行
P3=0xf7;
if(P34==0)
keyval=13;
if(P35==0)
keyval=14;
if(P36==0)
keyval=15;
if(P37==0)
keyval=16;
}
TR0=1; //重啟定時器
TH0=(65536-500)/256; //定時器賦初值
TL0=(65536-500)%256; //
}
編寫程序代碼,編譯生成HEX文件,將HEX文件裝載到proteus電路的單片機中,開始仿真,通過按下不同的按鍵觀察數碼管顯示的鍵值。
通過本實例,我們了解了如何用較少的按鍵實現矩陣鍵盤的按鍵識別。這為我們以後學習如何節約I/O埠打下了基礎。