矩陣鍵盤是單片機外部設備中所使用的排布類似于矩陣的鍵盤組。矩陣式結構的鍵盤顯然比直接法要復雜一些,識別也要復雜一些,列線通過電阻接正電源,并將行線所接的單片機的I/O口作為輸出端,而列線所接的I/O口則作為輸入。
矩陣鍵盤特點
矩陣鍵盤的編程是十分復雜的,但是矩陣鍵盤也節省IO口。而且還提高了I/O口利用率。
矩陣鍵盤構成與工作方式
圖9-7為一個4x3的行列結構,可以構成12個鍵的鍵盤。如果使用4x4的行列結構,就能組成一個16鍵的鍵盤。很明顯,在按鍵數量多的場合,矩陣鍵盤與獨立式按鍵鍵盤相比可以節省很多的I/O口線。
矩陣鍵盤不僅在連接上比單獨式按鍵復雜,它的按鍵識別方法也比單獨式按鍵復雜。在矩陣鍵盤的軟件接口程序中,常使用的按鍵識別方法有行掃描法和線反轉法。這兩種方法的基本思路是采用循環查循的方法,反復查詢按鍵的狀態,因此會大量占用MCU的時間,所以較好的方式也是采用狀態機的方法來設計,盡量減少鍵盤查詢過程對MCU的占用時間。
下面以圖9-7為例,介紹采用行掃描法對矩陣鍵盤進行判別的思路。圖9-7中,PD0、PD1、PD2為3根列線,作為鍵盤的輸入口(工作于輸入方式)。PD3、PD4、PD5、PD6為4根行線,工作于輸出方式,由MCU(掃描)控制其輸出的電平值。行掃描法也稱為逐行掃描查詢法,其按鍵識別的過程如下。
√將全部行線PD3-PD6置低電平輸出,然后讀PD0-PD2三根輸入列線中
有無低電平出現。只要有低電平出現,則說明有鍵按下(實際編程時,還要考慮按鍵的消抖)。如讀到的都是高電平,則表示無鍵按下。
√在確認有鍵按下后,需要進入確定具體哪一個鍵閉合的過程。其思路是:依次將行線置為低電平,并檢測列線的輸入(掃描),進而確認是具體的按鍵位置。如當PD5輸出低電平時(PD3=1、PD4=1、PD5=0、PD6=1),測到PD1的輸入為低電平(PD0=1、PD1=0、PD2=1),則可確認按鍵K3-2處于閉合狀態。通過以上分析可以看出,MCU對矩陣鍵盤的按鍵識別,是采用掃描方式控制行線的輸出和檢測列線輸入的信號相配合實現的。
√矩陣按鍵的識別僅僅是確認和定位了行和列的交叉點上的按鍵,接下來還要
考慮鍵盤的編碼,即對各個按鍵進行編號。在軟件中常通過計算的方法或查表的方法對按鍵進行具體的定義和編號。
在單片機嵌入式系統中,鍵盤掃描只是MCU的工作內容之一。MCU除了要檢測鍵盤和處理鍵盤操作之外,還要進行其他事物的處理,因此,MCU如何響應鍵盤的輸入需要在實際系統程序設計時認真考慮。
通常,完成鍵盤掃描和處理的程序是系統程序中的一個專用子程序,MCU調用該鍵盤掃描子程序對鍵盤進行掃描和處理的方式有三種:程序控制掃描、定時掃描和中斷掃描。
√程序控制掃描方式。在主控程序中的適當位置調用鍵盤掃描程序,對鍵盤進
行讀取和處理。
√定時掃描方式。在該方式中,要使用MCU的一個定時器,使其產生一個
10ms的定時中斷,MCU響應定時中斷,執行鍵盤掃描,當在連續兩次中斷中都讀到相同的按
√鍵按下(間隔10ms作為消抖處理),MCU才執行相應的鍵處理程序中斷
方式。使用中斷方式時,鍵盤的硬件電路要做一定的改動,增加一個按鍵產生中斷信號的輸入線,當鍵盤有按鍵按下時,鍵盤硬件電路產生一個外部的中斷信號,
MCU響應外部中斷,進行鍵盤處理。
下面我們介紹基于狀態機并采用定時鍵盤掃描的鍵盤處理系統的設計方法。
定時掃描方式的鍵盤接口程序
根據圖9-7,下面的鍵盤接口函數read_keyboaed()完成了對4*3鍵盤的掃描識別和鍵盤的編碼。編碼鍵盤的定義使用define語句定義,鍵盤的形式類似電話和手機鍵盤,如圖9-8所示。
#defineNo_key255
#defineK1_11
#defineK1_22
#defineK1_33
#defineK2_14
#defineK2_25
#defineK2_36
#defineK3_17
#defineK3_28
#defineK3_39
#defineK4_110
#defineK4_20
#defineK4_311
#defineKey_mask0b00000111
charread_keyboard()
{
staticcharkey_state=0,key_value,key_line;
charkey_return=No_key,i;
switch(key_state)
{
case0:
key_line=0b00001000;
for(i=1;i《=4;i++)//掃描鍵盤
PORTD=~key_line;//輸出行線電平
PORTD=~key_line;//必須送2次!!!(注1key_value=Key_mask&PIND;//讀列電平if(key_value==Key_mask)
key_line《《=1;//沒有按鍵,繼續掃描
else
{
key_state++;//有按鍵,停止掃描
break;//轉消抖確認狀態
}
}
break;case1:
if(key_value==(Key_mask&PIND))//再次讀列電平,{
switch(key_line|key_value)//與狀態0的相同,確認按鍵{//鍵盤編碼,返回編碼值case0b00001110:key_return=K1_1;break;
case0b00001101:
key_return=K1_2;break;
case0b00001011:
key_return=K1_3;break;
case0b00010110:
key_return=K2_1;break;
case0b00010101:key_return=K2_2;
break;
case0b00010011:
key_return=K2_3;break;
case0b00100110:
key_return=K3_1;break;
case0b00100101:
key_return=K3_2;break;
case0b00100011:
key_return=K3_3;break;
case0b01000110:
key_return=K4_1;
break;
case0b01000101:
key_return=K4_2;
break;
case0b01000011:
key_return=K4_3;
break;}
key_state++;//轉入等待按鍵釋放狀態
}
else
key_state--;//兩次列電平不同返回狀態0,(消抖處理)
break;
case2://等待按鍵釋放狀態
PORTD=0b00000111;//行線全部輸出低電平
PORTD=0b00000111;//重復送一次
if((Key_mask&PIND)==Key_mask)
key_state=0;//列線全部為高電平返回狀態0
break;
}
returnkey_return;
}
系統主程序應每隔10ms調用該鍵盤接口函數read_keyboaed(),函數返回值為255時表示無按鍵按下。檢測和確認按鍵按下時,函數返回值為0到11之間的一個,該返回值已經是經過了鍵盤編碼的值。
鍵盤接口函數read_keyboaed()是基于狀態機實現的,將鍵盤掃描處理過程化分成三個狀態,每個狀態的功能為:
√狀態0,鍵盤掃描檢測。控制PD3-PD6,4根行線逐行輸出低電平,對鍵盤
進行掃描檢測。一旦檢測到有鍵按下(key_value),立即停止鍵盤的掃描,狀態轉換到狀態1。注意此時變量key_value中保存著讀到的列線輸入值,而且該行線低電平的輸出是保持不變的。
√狀態1,消抖處理和鍵盤編碼。再次檢測鍵盤列線的輸入,并與狀態0時的
key_value比較,不相等則返回狀態0,實現了消抖處理。相等則確認該鍵的輸入,進行鍵盤編碼和設置函數的返回值,狀態轉化到狀態2。
√狀態2,等待按鍵釋放。控制PD3-PD6,4根行線全部輸出低電平,檢測3
根列線輸入全部為高電平(無按鍵按下)時狀態返回到狀態0。
讀者在閱讀該段程序時,請注意key_mask、key_value、key_line的作和用它們不僅與鍵盤的硬件連接有關系,同時還要注意他們在程序中是如何使用的,其值的保存等等。
通過這個例子也可以看出,在硬件設計的過程中,也需要認真考慮軟件的寫。比如,你也可以將4根鍵盤行線與PD0、PD2、PD3、PD6連接,列線使用PD1、PD4、PD5,從硬件的角度看是完全可以的,但會給軟件編寫造成很多麻煩。所以,一個好的嵌入式系統工程師必須同時具備良好的軟件設計編寫能力和硬件設計能力。
實際上read_keyboaed()還是一個比較簡單的鍵盤接口函數,還不能處理類似多鍵按下的識別、按鍵“連發”等功能。但當你真正掌握了基本鍵盤接口的設計思想和方法后,就可以在這個簡單的鍵盤接口函數基礎上,設計出功能更加完善的鍵盤系統了。
(注1)當AVR的I/O口處于輸入方式工作時,其對應的PINx就是外部引腳上的實際電平。為了防止讀入PINx時數據的不穩定和不確定,(例如在讀的期間,正好引腳電平發生改變),AVR的I/O輸入端到總線之間加入一個同步鎖存器,用以保證讀入數據的穩定和確定。同步鎖存器在系統I/O時鐘的作用下,經過1/2-3/2個系統時鐘周期,將引腳電平鎖定,提供MCU讀取。也就是說外部引腳的電平變化要經過1/2-3/2個時鐘周期才能真正的被讀到,見圖9-9。
因此,當編寫程序讀取AVR的I/O口PINx電平值時應注意:
當I/O口從輸出方式改成輸入方式后,應延時一個CLK再讀。
當I/O外部引腳電平改變后,也要延時一個CLK后再讀取。
在本例的鍵盤掃描程序中,根據掃描條件,首先改變行線輸出的電平,如果按鍵按下的話,那么對應點的列線(輸入口)電平也馬上改變了,此時需要延時一個CLK后讀列線的輸入電平值才是正確的。程序中采用輸出2次相同的行電平的方式,第2次輸出的實際作用是起到延時的作用(其實相當于2個NOP)。當然,也可以輸出1次行電平,在讀I/O口時采用讀2次的方式,只要滿足規定的延時時間就可以的。
矩陣鍵盤的原理
其中矩陣鍵盤是一種比較常用的方法。矩陣鍵盤的電路圖如下:
矩陣式鍵盤由行線和列線組成,按鍵位于行、列的交叉點上。當鍵被按下時,其交點的行線和列線接通,相應的行線或列線上的電平發生變化,單片機通過檢測行或列線上的電平變化可以確定哪個按鍵被按下。
矩陣鍵盤不僅在連接上比單獨式按鍵復雜,它的按鍵識別方法也比單獨式按鍵復雜。矩陣鍵盤的檢測方法有多種,常見的有:逐點掃描法、逐行掃描法、全局掃描法。在本實例中我們采用逐行掃描法來實現按鍵檢測,其中PD0-PD3作為列線,PD4-PD7作為行線。識別過程如下:
1、判斷鍵盤中是否有鍵按下。設置所有行線為輸出口,并輸出低電平;設置列線為輸入口,讀取列線上的電平狀態,只要有一列的電平為低,就表示有按鍵按下,并且被按下的鍵位于電平為低的列線與4跟行線相交叉的4個按鍵中,若所有列線都為高電平,表示沒有按鍵按下;
2、判斷被按下按鍵所在的位置。在確認有鍵按下后(進行按鍵消抖處理后),接下來就是確定具體哪個案件被按下,方法是:依次將每根行線設置為輸出口,并輸出低電平(同時剩余行線輸出高電平),然后逐列檢查每根列線的電平狀態,若某列為低電平,則該列線與設置為輸出低電平的行線交叉處的按鍵就是被按下的按鍵。
3、按鍵位置確定后,接下來就要給矩陣鍵盤中的每個按鍵進行編號,也就是進行按鍵編碼,程序設計中常用計算法和查表法兩種方式對按鍵進行編碼,本實例采用計算法編碼。
從上面的電路圖中我們可以看到,鍵盤的所有行線和列線都接了上拉電阻,這是為了確保在沒有按鍵按下的時候,I/O口的電平狀態始終為高電平,從而消除外界干擾。
對于AVR單片機來說,我們已經知道在I/O口輸入狀態下,可以使能其內部上拉電阻,所以上面電路圖中連接4根列線的上拉電阻可以不用,直接使能內部上拉電阻即可。
評論
查看更多