51 線反轉(zhuǎn)法 實(shí)現(xiàn)矩陣鍵盤檢測(cè)
1.矩陣鍵盤 線反轉(zhuǎn)法算法
1.1矩陣鍵盤
矩陣鍵盤是指將鍵盤按鈕放置在行線與列線的交叉點(diǎn)上,由多行和多列就構(gòu)成了矩陣鍵盤。下圖就是一個(gè)矩陣式鍵盤。
將鍵盤行線接到單片機(jī)的引腳之上[P35引腳,P36引腳],將鍵盤列線接到單片機(jī)的另一些引腳之上[P31引腳,P32引腳,P33引腳,P34引腳]。
1.2線反轉(zhuǎn)法算法
對(duì)于外部鍵盤,程序在執(zhí)行時(shí)必須隨時(shí)掃描鍵盤跟單片機(jī)連接引腳的電平,看是否有鍵盤按鈕被按下。而在掃描各個(gè)端口的時(shí)候,一次只能掃描到按鍵的哪一行或那一列,只有同時(shí)記錄被按下按鍵的行和列才能決定按鍵的坐標(biāo)。
最直接的方式是先逐行檢測(cè)有哪一行的按鍵被按下,再逐列檢測(cè)有哪一列的按鈕被按下。這樣就能夠得到按鍵的行值和列值即得到按鍵的坐標(biāo),就檢測(cè)到了是哪一個(gè)按鍵被按下了。但是使用這種方法程序執(zhí)行效率就跟矩陣的行數(shù)R和列數(shù)C有關(guān)了,每次檢測(cè)都需要檢測(cè)R * R次。
到了21世紀(jì),線反轉(zhuǎn)法肯定會(huì)替代以上掃描方法的,因?yàn)檫@種檢測(cè)方法只需要兩次就可以掃描出來是哪一個(gè)按鍵被按下了。它是如何來實(shí)現(xiàn)就用掃面兩次就可以得到按鍵的坐標(biāo)的呢?單片機(jī)的引腳在默認(rèn)情況下為高電平,將接接矩陣鍵盤行的引腳置位低電平(0)[如上圖P3就應(yīng)該被置為],將接矩陣鍵盤列的引腳置位高電平(1),則結(jié)合上圖中的2X4鍵盤的P3端口的值應(yīng)為宏值#define ROW_LOW_COLUMN_HIGH 0x9f,然后檢測(cè)接矩陣鍵盤列中是否有低電平出現(xiàn),如果有則說明在低電平列有按鈕被按下;若檢測(cè)到某列為低電平后,確定是哪一列,然后將行和列所接引腳電位反轉(zhuǎn):行為高電平,列為低電平(結(jié)合上圖P3端口為宏值#define ROW_HIGH_COLUMN_LOW 0xe1),檢測(cè)行是否有高電平的行,如果有則確定是哪一行為高電平即確定哪一行有按鍵被按下。這樣就確定了一個(gè)按鍵的行和列坐標(biāo)。
1.3線反轉(zhuǎn)法代碼實(shí)現(xiàn)
將以下函數(shù)放置在main函數(shù)中的主程序循環(huán)中就可以檢測(cè)到是否有按鍵被按下并得知按鍵的行坐標(biāo)和列坐標(biāo):實(shí)現(xiàn)代碼如下
KEY_INDEX matrixKeyDown(){UINT temp;KEY_INDEX key_index;//鍵盤行為低電平,列為高電平P3 = ROW_LOW_COLUMN_HIGH;temp = P3;temp = temp & KEY_ALL_UP_IN_COLUMN;//檢測(cè)按鍵有沒有被按下if(temp != KEY_ALL_UP_IN_COLUMN){//消除是按鍵抖動(dòng)引起的嫌疑nms_delay(10);//再次檢測(cè)鍵盤有沒有被按下temp = P3;temp = temp & KEY_ALL_UP_IN_COLUMN;//檢測(cè)按鍵被按下的列if(temp != KEY_ALL_UP_IN_COLUMN){temp = P3;switch(temp){case KEY_DOWN_IN_FIRST_COLUMN:key_index.column = FIRST_COLUMN_INDEX;break;case KEY_DOWN_IN_SECOND_COLUMN:key_index.column = SECOND_COLUMN_INDEX;break;case KEY_DOWN_IN_THIRD_COLUMN:key_index.column = THIRD_COLUMN_INDEX;break;case KEY_DOWN_IN_FOURTH_COLUMN:key_index.column = FOURTH_COLUMN_INDEX;break;default:; //Do something}}//矩陣鍵盤端口反轉(zhuǎn),檢測(cè)按鍵所在的行//此時(shí)的按鍵還在被按住,但是還是判斷一下按鍵是否還被按住//與檢測(cè)列的按下并列,需要檢測(cè)P3 = ROW_HIGH_COLUMN_LOW;temp = P3;temp &= KEY_ALL_UP_IN_ROW;if(temp != KEY_ALL_UP_IN_ROW){temp = P3;switch(temp){case KEY_DOWN_IN_FIRST_ROW:key_index.row = FIRST_ROW_INDEX;break;case KEY_DOWN_IN_SECOND_ROW:key_index.row = SECOND_ROW_INDEX;break;default:;}//如果有按鍵被按下,則需要在這里等待被釋放//思路是記錄到底是哪一個(gè)鍵被按下,可以換一個(gè)地方等待案件的釋放的//因?yàn)槠渌胤接涗浟税存I的坐標(biāo)//其實(shí)只需要在這里檢測(cè)若行為KEY_ALL_UP_IN_ROW,則按鍵被釋放//temp = P3;//while(temp != KEY_ALL_UP_IN_ROW);}}return key_index; }
此函數(shù)時(shí)檢測(cè)矩陣鍵盤中是否有按鍵被按下。KEY_INDEX是一個(gè)包含按鍵行和列坐標(biāo)的結(jié)構(gòu)體。temp = temp &KEY_ALL_UP_IN_COLUMN; KEY_ALL_UP_IN_COLUMN宏值為0x9f表示在列中的鍵盤全為高電平時(shí)的狀態(tài),if(temp != KEY_ALL_UP_IN_COLUMN)表示若temp與此值做與運(yùn)算后的值不為鍵盤全列為高電平狀態(tài),則可能(還有可能是抖動(dòng)帶來的干擾)有按鍵被按下,于是用自定義延遲函數(shù)nms_delay(10);延遲10ms的時(shí)間來消除鍵盤抖動(dòng)(目的是進(jìn)一步判斷是否是按鍵真的被按下),然后用相同的方法判斷一次鍵盤是否全列都為高電平狀態(tài),如果不是,則此時(shí)確實(shí)有按鍵被按下,則接下來用case語言判斷是哪一列的按鍵被按下,將被按下按鍵的列賦值給結(jié)構(gòu)體的列值,從而得到按鍵的列值。得到列值之后,將接矩陣鍵盤行和列引腳P3反轉(zhuǎn),因?yàn)榇藭r(shí)已經(jīng)有按鍵被按下,所以無需再做消擾動(dòng)等操作。只需檢測(cè)是哪一行的按鍵被按下得到被按下按鍵的行值即可,代碼中還判斷了是否行值被按下,其實(shí)此時(shí)已經(jīng)有按鍵被按下,這一步可有可無。
最后函數(shù)將按鍵的列值和行值返回,供數(shù)碼管或LCD中顯示,是哪一個(gè)按鍵被按下了。實(shí)現(xiàn)人機(jī)合作。
2 擴(kuò)展
這里代碼是對(duì)2X4矩陣鍵盤的掃描,其實(shí)以上程序設(shè)計(jì)方法適合任何矩陣鍵盤和任何其它的芯片。需要變動(dòng)的是接矩陣鍵盤的端口:將接矩陣鍵盤行引腳和列引腳找出來賦予合適的宏值[高低電平,將進(jìn)行檢測(cè)的行或列置成高電平,另一些引腳置為低電平]。另外還需要改動(dòng)的一個(gè)地方是,判斷矩陣式哪一行和哪一列被按下,增加一些行和列值即可。
3 運(yùn)行結(jié)果
將鍵盤檢測(cè)函數(shù)的返回值送給數(shù)碼管動(dòng)態(tài)顯示(數(shù)碼管動(dòng)態(tài)顯示)函數(shù),再將數(shù)碼管動(dòng)態(tài)顯示函數(shù)放置在主程序循環(huán)中。下載程序到單片機(jī)中,運(yùn)行程序,當(dāng)按下第一行第二列的按鍵時(shí),數(shù)碼管顯示如下
按鍵[1][3]
按下2,4按鍵時(shí)顯示結(jié)果如下
按鍵[2][4]
此次筆記記錄完畢。
評(píng)論