如何用Linuxc編寫矩陣鍵盤掃描程序_第1頁
如何用Linuxc編寫矩陣鍵盤掃描程序_第2頁
如何用Linuxc編寫矩陣鍵盤掃描程序_第3頁
如何用Linuxc編寫矩陣鍵盤掃描程序_第4頁
如何用Linuxc編寫矩陣鍵盤掃描程序_第5頁
已閱讀5頁,還剩22頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、如何用Linux c 編寫矩陣鍵盤掃描程序通常,矩陣鍵盤的工作方式有三種,即:程序查詢、定時(shí)查詢和鍵盤中斷掃描。鍵盤工作方式的選取應(yīng)根據(jù)實(shí)際應(yīng)用系統(tǒng)中CPU工作的忙、閑情況而定。此次矩陣鍵盤的應(yīng)用場合是數(shù)字電橋系統(tǒng)。一者,電橋系統(tǒng)對(duì)按鍵的響應(yīng)速度、準(zhǔn)確性都有較高的要求。二者,按鍵相關(guān)代碼嵌入在linux系統(tǒng)中,linux系統(tǒng)中的其它程序(如LCD顯示)對(duì)CPU的占用量相對(duì)較大,基本排除程序查詢方式的使用。若采用中斷掃描方式在組合按鍵時(shí)有一定的局限性,即不能組合同列的按鍵,否則無法響應(yīng)中斷。相比以上兩種方式,定時(shí)掃描在嵌入式系統(tǒng)中的應(yīng)用最為廣范。l 設(shè)備驅(qū)動(dòng)層:將底層的硬件輸入轉(zhuǎn)化為統(tǒng)一事件形式

2、,向輸入核心層(Input Core)匯報(bào)。l 輸入子系統(tǒng)核心:承上啟下。為驅(qū)動(dòng)層提供輸入設(shè)備注冊與操作接口,如:input_register_device;通知事件處理層對(duì)事件進(jìn)行處理;在/Proc下產(chǎn)生相應(yīng)的設(shè)備信息等。l 事件處理層:主要是和用戶空間交互。(Linux中在用戶空間將所有的設(shè)備都當(dāng)做文件來處理,由于在一般的驅(qū)動(dòng)程序中都有提供fops接口,以及在/dev下生成相應(yīng)的設(shè)備文件nod,這些操作在輸入子系統(tǒng)中由事件處理層完成)。l 用戶空間:一般包括C程序?qū)崿F(xiàn)的應(yīng)用程序和Qt程序。從框圖可以看出驅(qū)動(dòng)程序員所要完成的是硬件相關(guān)部分(具體是輸入設(shè)備驅(qū)動(dòng)程序模塊)。設(shè)備驅(qū)動(dòng)程序主要完成鍵

3、盤的掃描,如果有按鍵按下或彈起,則通過input core完成兩件事件:報(bào)告事件 傳遞鍵碼本電路采用6*7矩陣鍵盤,共39個(gè)按鍵。其中行包括KEY_LINE1:6,分別連接GPB5GPB10作為電平輸出引腳。列包括KEY_ROW1:7,分別連接GPG5GPG7,GPG11GPG14作為電平輸入腳,且使用內(nèi)部上拉置高。 系統(tǒng)初始化時(shí)將列設(shè)為輸入,弱上拉;第1行輸出低電平,其余行輸出高電平(假設(shè)掃描順序按標(biāo)號(hào)由低到高);啟動(dòng)內(nèi)核定時(shí)器。 定時(shí)間隔到,查詢各列輸入電平情況,從而確定第1行上各個(gè)按鍵狀態(tài)與上次掃描時(shí)本行各按鍵狀態(tài)比較。若有按鍵狀態(tài)變化,此時(shí)的按鍵坐標(biāo)為button(line(1),ro

4、w(x),將按鍵鍵碼,狀態(tài)等信息保存,報(bào)告事件到input core層(也可將每次掃描結(jié)果全部匯報(bào),由應(yīng)用程序決定按鍵狀態(tài)是否改變)。同時(shí)將第2行輸出低電平,其余行輸出高電平。 定時(shí)間隔到,查詢各列輸入電平情況,從而確定第2行上各個(gè)按鍵狀態(tài)與上次掃描時(shí)本行各按鍵狀態(tài)比較。若有按鍵變化,此時(shí)的按鍵坐標(biāo)為button(line(2),row(x),將按鍵鍵碼,狀態(tài)等信息保存,報(bào)告事件到input core層。同時(shí)將第3行輸出低電平,其余行輸出高電平。 如此周期循環(huán)進(jìn)行,即可方便將所有按鍵變化掃描到,并向input core層匯報(bào),鍵碼轉(zhuǎn)換后供用戶程序調(diào)用。 說明:為什么不在定時(shí)間隔到的時(shí)候一次性將

5、6行都掃描了? 因?yàn)樵诙〞r(shí)間隔到來時(shí),按上面方法一次將6行掃描,很可能會(huì)出現(xiàn)硬件不能及時(shí)響應(yīng)指令,而造成掃描不到按鍵變化的現(xiàn)象(特別是在系統(tǒng)時(shí)鐘較高的情況)。比如:第1行掃描完成后,將第2行置高,其余行置低來掃描低二行,這句話就兩條C語言指令:拉低第1行,置高低2行。接下來馬上掃描列的電平,但其實(shí)在上面兩條指令結(jié)束時(shí),硬件上并不一定完成這兩條指令預(yù)期的動(dòng)作。即第1行線路真的已經(jīng)為0,第2行線路真的為1碼?如果有鍵按著,此時(shí)列的數(shù)據(jù)寄存器里的值已經(jīng)根據(jù)行電平的變化而變化了嗎?其實(shí)這些是難以保證的,按鍵的阻抗,GPIO的阻性、容性都會(huì)滯后電平變化。所以難以保證一次性將所有行掃描完成這種方式的準(zhǔn)確性

6、和穩(wěn)定性。 #include #include #include #include #include int main(int argc, char *argv) int fd = -1; int num; size_t rb; int version; char name20; struct input_event ev; if (fd = open(/dev/event0, O_RDONLY) 0) perror(open error); exit(1); if (ioctl(fd, EVIOCGNAME(sizeof(name)-1), name) 0) perror(getname e

7、rror); exit(1); /printf(name=%sn, name); if (ioctl(fd, EVIOCGVERSION, &version) 0) perror(getversion error); exit(1); /printf(version=0 x%xn, version); while(1) rb = read(fd, &ev, sizeof(struct input_event); if (rb (int)sizeof(struct input_event) perror(read error); exit(1); /printf(read %d eventn,

8、(int)(rb/sizeof(struct input_event); if (EV_KEY=ev.type) if (1 = ev.value) printf(key %d is pressedn, ev.code-58); else printf(key %d is releassedn, ev.code-58); close(fd); return 0; 數(shù)據(jù)結(jié)構(gòu)描述 同時(shí)定義每個(gè)按鍵的數(shù)據(jù)結(jié)構(gòu) #define BUTTON_DOWN 1 #define BURRON_UP 0 struct button_desc int num; /按鍵編號(hào),用來定位按鍵 int code; /按鍵

9、鍵碼,需遵循PS/2鍵碼(input.h中已定義) char status; /按鍵狀態(tài):BUTTON_DOWN 或 BUTTON_UP ; struct button_desc pre_button38; /按鍵的上一次狀態(tài) struct button_desc curr_button38; /按鍵的當(dāng)前狀態(tài) 定義pre_button38和pre_button38的是為了提到的兩次按鍵比較。若變換則傳遞鍵碼及報(bào)告事件。 報(bào)告事件和鍵碼傳遞 input core層起了承上啟下的作用,有為驅(qū)動(dòng)層提供輸入設(shè)備注冊與操作接口的功能。 用于報(bào)告EV_KEY,EV_REL,EV_ABS事件的函數(shù)分別為:

10、 void input_report_key(struct input_dev *dev,unsigned int code,int value) void input_report_rel(struct input_dev *dev,unsigned int code,int value) void input_report_abs(struct input_dev *dev,unsigned int code,int value) 目前用到的是第一個(gè)函數(shù),用于向事件層報(bào)告按鍵事件,函數(shù)的第一參數(shù)是值具體的設(shè)備;第二個(gè)參數(shù)指鍵碼;第三個(gè)參數(shù)為按鍵狀態(tài)值,1表示按下,0表示彈起。 例1: in

11、put_report_key(button_dev, KEY_Z, 1); /報(bào)告z鍵按下 例2: input_report_key(button_dev, KEY_SLASH, 1); /報(bào)告shift鍵按下 input_report_key(button_dev, KEY_Z, 1); /報(bào)告z鍵按下 別忘了要讓input core知道什么時(shí)候一次報(bào)告結(jié)束: input_sync(struct input_dev *dev) /輸入同步,用于告訴input core子系統(tǒng)報(bào)告結(jié)束。 在例1,例2最后必須加上input_sync(button_dev)才是一次有效的報(bào)告。 上面講到input

12、_report_key()用來報(bào)告EV_KEY事件,為什么可以這個(gè)EV_KEY甚至具體的一個(gè)鍵碼會(huì)支持呢? 驅(qū)動(dòng)實(shí)現(xiàn)初始化(事件支持): 用set_bit()告訴input輸入子系統(tǒng)支持哪些事件,哪些按鍵。例如: set_bit(EV_KEY,button_dev.evbit) (其中button_dev是struct input_dev類型) set_bit(KEY_1,button_dev.evbit) struct input_dev中有兩個(gè)成員為: evbit:事件類型(包括EV_RST,EV_REL,EV_MSC,EV_KEY,EV_ABS,EV_REP等) input_sync(s

13、truct input_dev *dev) /輸入同步,用于告訴input core子系統(tǒng)報(bào)告結(jié)束。 在例1,例2最后必須加上input_sync(button_dev)才是一次有效的報(bào)告。 上面講到input_report_key()用來報(bào)告EV_KEY事件,為什么可以這個(gè)EV_KEY甚至具體的一個(gè)鍵碼會(huì)支持呢? 驅(qū)動(dòng)實(shí)現(xiàn)初始化(事件支持): 用set_bit()告訴input輸入子系統(tǒng)支持哪些事件,哪些按鍵。例如: set_bit(EV_KEY,button_dev.evbit) (其中button_dev是struct input_dev類型) set_bit(KEY_1,button_

14、dev.evbit) struct input_dev中有兩個(gè)成員為: evbit:事件類型(包括EV_RST,EV_REL,EV_MSC,EV_KEY,EV_ABS,EV_REP等) keybit:按鍵類型(當(dāng)事件類型為EV_KEY時(shí)包括KEY_1,KEY_Z,BTN_LEFT keybit:按鍵類型(當(dāng)事件類型為EV_KEY時(shí)包括KEY_1,KEY_Z,BTN_LEFT, BTN_0,BTN_1,BTN_MIDDLE等)。 /#include #include #include #include #include #include #include #include #include #i

15、nclude #include #include #include #include #include #include #include #include #include /*timer*/ #include /*jiffies*/ #include #include #include #include #include mybutton.h #define DEVICE_NAME ET35-Buttons static struct timer_list ScanTimer; struct input_dev *button_dev; static unsigned int line =

16、 0;/當(dāng)前掃描行 /* timer_function */ void timer_function(unsigned long para) unsigned int row,num,value;/*獲取當(dāng)前掃描行*tmp = s3c2410_gpio_getpin(button_io_lineline.pin);if(tmp = 0 x20)/tmp = 0;else if(tmp = 0 x40)tmp = 1;else if(tmp = 0 x80)tmp = 2;else if(tmp = 0 x100)tmp = 3;else if(tmp = 0 x200)tmp = 4;else

17、 if(tmp = 0 x400)tmp = 5; *掃描矩陣鍵盤*/for(row = 0 ; row ZROW_NUM ; row+)value = s3c2410_gpio_getpin(button_io_rowrow.pin);if(value | (0 button_io_rowrow.number) = 0)value = BUTTON_DOWN;/有建按下else value = BUTTON_UP;num = 6*row + line; if(button_infonum.value != value);/有按鍵變化 if(value = BUTTON_UP) button_

18、infonum.value = BUTTON_UP;/鍵彈起elsebutton_infonum.value = BUTTON_DOWN;/鍵按下input_report_key(button_dev, button_infonum.code, button_infonum.value);input_sync(button_dev);/同步事件報(bào)告 s3c2410_gpio_setpin(button_io_lineline.pin,1);/當(dāng)前掃描行置 1if(line = 5)line = 0;s3c2410_gpio_setpin(button_io_lineline.pin,0);elseline +;s3c2410_gpio_setpin(button_io_lineline.pin,0);/下一掃描行置 0mod_timer(&ScanTimer, jiffies + (HZ

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論