吳蓬勃,張金燕,卜新華
(1.石家莊郵電職業(yè)技術(shù)學(xué)院,石家莊050031; 2.石家莊鐵道學(xué)院)
吳蓬勃(助教),主要研究方向?yàn)榍度胧较到y(tǒng)開(kāi)發(fā)。
隨著嵌入式系統(tǒng)的飛速發(fā)展,在嵌入式手持設(shè)備中,人機(jī)交互設(shè)備是與用戶(hù)接觸最多的部分,最能夠直接快速地體現(xiàn)出該設(shè)備的性能。所以,是否有一個(gè)友好的、快速的、可靠的人機(jī)交互設(shè)備已經(jīng)成為衡量一款手持設(shè)備的重要指標(biāo)。在嵌入式人機(jī)交互設(shè)備中,鍵盤(pán)由于其具有很高的準(zhǔn)確性和可靠性,能夠適應(yīng)各種惡劣的工作環(huán)境,并且具有很長(zhǎng)的使用壽命,而得到廣泛應(yīng)用。
本文根據(jù)手持終端的特點(diǎn),設(shè)計(jì)出一款矩陣鍵盤(pán),并在Linux平臺(tái)下開(kāi)發(fā)出鍵盤(pán)的驅(qū)動(dòng)程序。采用Qt/Embedded構(gòu)建圖形界面,通過(guò)對(duì)Qt/Embedded自帶輸入法的分析,結(jié)合Murphpinyin中文輸入法軟件包,構(gòu)建了一款可輸入數(shù)字、中/英文的嵌入式鍵盤(pán)。
本系統(tǒng)的硬件部分主要是一個(gè)4列5行的矩陣鍵盤(pán),如圖1所示。其中列線(xiàn)COL0~COL3使用了S3C2440的4個(gè)中斷引腳— —EINT10、ENIT13、EINT15、EINT20[1],并且每根列線(xiàn)都有一個(gè)4.7 kΩ的上拉電路,把中斷引腳電平拉高,確保按鍵空閑時(shí)不會(huì)觸發(fā)中斷;行線(xiàn)ROW0~ROW4使用的是S3C2440的5個(gè)普通I/O口——GPE11、GPE13、GPG3、GPG6、GPG11。這里需要注意的問(wèn)題是,一定要確保列線(xiàn)所用的中斷在Linux的各個(gè)設(shè)備中尚未使用到,否則在后面的驅(qū)動(dòng)程序中將會(huì)造成驅(qū)動(dòng)程序初始化失敗。
圖1 5×4矩陣鍵盤(pán)電路原理
考慮到手持終端操作的方便性,將所有的按鍵進(jìn)行重新布局,如圖2所示。為了延長(zhǎng)手持設(shè)備的使用壽命、提高可靠性,增加了電源按鍵Power。另外,考慮到手持設(shè)備的低功耗要求,增加了背光控制按鈕 Back-Light,通過(guò)控制 LCD_PWREN引腳的高低電平,控制 LCD背光的開(kāi)關(guān)。其中電源按鍵 Power、背光控制按鍵BackLight為單獨(dú)按鍵,直接與S3C2440的中斷引腳相連。本文重點(diǎn)對(duì)矩陣鍵盤(pán)做詳細(xì)介紹,電源按鍵和背光控制按鍵的處理機(jī)制與矩陣鍵盤(pán)類(lèi)似,這里不再做介紹。
圖2 5×4矩陣鍵盤(pán)布局圖
矩陣鍵盤(pán)是作為L(zhǎng)inux的一個(gè)字符設(shè)備注冊(cè)到系統(tǒng)中的。為了降低對(duì)系統(tǒng)資源的損耗,采用中斷處理函數(shù)對(duì)按鍵做處理;同時(shí)考慮到按鍵的抖動(dòng)問(wèn)題,采用定時(shí)器來(lái)消除抖動(dòng)[2]。
該驅(qū)動(dòng)程序的流程如圖3所示。首先,使用S3C2440_Kb_init()函數(shù)將鍵盤(pán)作為一個(gè)字符設(shè)備進(jìn)行注冊(cè),初始化行線(xiàn)引腳為:輸出、非上拉,并將所有行輸出置為低電平;注冊(cè)該鍵盤(pán)設(shè)備。初始化列線(xiàn)所連接的中斷引腳為:輸入、下降沿觸發(fā)中斷,并建立中斷與中斷處理函數(shù)Key_interrupt()的連接。
當(dāng)有按鍵按下后,由于所有的行為低電平,必然有一行和一列線(xiàn)導(dǎo)通,從而將相應(yīng)的列線(xiàn)拉低,觸發(fā)中斷。然后,中斷處理函數(shù)Key_interrupt()記錄相應(yīng)的中斷號(hào)碼,由于按鍵存在抖動(dòng),單憑一次中斷的觸發(fā)就判定相應(yīng)的按鍵按下很不可靠,所以在中斷觸發(fā)后開(kāi)啟定時(shí)器kb_timer對(duì)按鍵狀態(tài)再次進(jìn)行判定。
上層應(yīng)用程序使用S3C2440_Kb_open()打開(kāi)鍵盤(pán)設(shè)備,開(kāi)啟列線(xiàn)中斷,初始化定時(shí)器。當(dāng)中斷觸發(fā)后,開(kāi)啟定時(shí)器,定時(shí)器定時(shí)時(shí)間到后,觸發(fā)定時(shí)器中斷kb_timer_handler()。kb_timer_handler()首先會(huì)調(diào)用鍵盤(pán)掃描函數(shù)Scan_keyboard()掃描按鍵狀態(tài),Scan_keyboard()流程如圖4所示。如果經(jīng)過(guò)3次鍵盤(pán)掃描,每次都掃描到相同的按鍵值被按下,則證明確實(shí)有按鍵被按下,Scan_keyboard()函數(shù)返回KEYDOWN。如果按本次按鍵值與上一次按鍵值不同,則保存本次按鍵值到循環(huán)隊(duì)列,這樣可以不保存重復(fù)數(shù)據(jù)到緩沖隊(duì)列。如果連續(xù)10次掃描到按鍵的狀態(tài)都不為KEY_DOWN,則證明按鍵已經(jīng)彈起,關(guān)閉定時(shí)器kb_timer。
S3C2440_Kb_read()函數(shù)負(fù)責(zé)從循環(huán)隊(duì)列中讀取按鍵值反饋給上層應(yīng)用程序。
圖4 鍵盤(pán)掃描函數(shù)Scan_keyboard()流程
圖3 矩陣鍵盤(pán)驅(qū)動(dòng)程序流程
Qt/Embedded是 Trolltech公司針對(duì)采用嵌入式Linux的電子設(shè)備開(kāi)發(fā)的綜合應(yīng)用平臺(tái)。Qt/Embedded包含完整的應(yīng)用層、靈活的用戶(hù)界面、窗口操作系統(tǒng)、應(yīng)用程序以及開(kāi)發(fā)框架[1]。
Qt/Embedded本身提供了對(duì)按鍵的支持,它在文件qkeyboard_qws.cpp中提供了一個(gè)QWSKeyboardHandler類(lèi)來(lái)處理按鍵事件。本系統(tǒng)創(chuàng)建了QWSKeyboardHandler類(lèi)的一個(gè)子類(lèi) QWSKEYMATRIXHandler。在 QWSKEYMATRIXHandler類(lèi)的構(gòu)造函數(shù)中,通過(guò)open()函數(shù)打開(kāi)矩陣鍵盤(pán)key_matrix,通過(guò)對(duì)打開(kāi)的鍵盤(pán)設(shè)備創(chuàng)建一個(gè)QscoketNotifer[1]來(lái)監(jiān)控按鍵設(shè)備,通過(guò)信號(hào)與槽機(jī)制,建立該QscoketNotifer與讀鍵盤(pán)函數(shù)ReadKeyboardData()的連接,當(dāng)key_matrix被激活時(shí),就會(huì)觸發(fā)讀鍵盤(pán)函數(shù)ReadKeyboardData()。代碼如下:
notifier=new QSocketNotifier(key_matrix,QSocketNotifier::Read,this);
connect(notifier,SIGNAL(activated(int)),this,SLOT(ReadKeyboardData()));
在讀鍵盤(pán)函數(shù)ReadKeyboardData()中,調(diào)用矩陣鍵盤(pán)驅(qū)動(dòng)程序的讀函數(shù)Read()來(lái)獲取按鍵值。為了使得按鍵值能夠傳送給應(yīng)用程序,要使用QWSKeyboardHandler類(lèi)的成員函數(shù)processKeyEvent(int unicode,int keycode,int modifiers,bool isPress,bool autoRepeat)[3],各參數(shù)功能如下:
①Unicode:按鍵的 Unicode編碼,如數(shù)字 1的unicode編碼為1,字母A的unicode編碼為A。如果該項(xiàng)為0,則為功能鍵 Shift、Left、Right等;如果該項(xiàng)為 0xFFFF,則只傳送鍵值keycode,不打印編碼。
②Keycode:Qt中使用的按鍵名稱(chēng),如Qt::Key_Backspace、Qt::Key_Enter等。
③Modifiers:Qt所支持的鍵盤(pán)組合鍵。
④isPress:判斷按鍵的狀態(tài)是“按下”還是“彈起”。
⑤autoRepeat:判斷本次事件是有自動(dòng)重復(fù)機(jī)制產(chǎn)生,還是由一個(gè)現(xiàn)實(shí)中的按鍵產(chǎn)生。
通過(guò)processKeyEvent()函數(shù)可以發(fā)送數(shù)字、小寫(xiě)英文、大寫(xiě)英文,但是目前Qt/Embedded上沒(méi)有中文輸入法,不能輸入中文。
Murphypinyin是目前為止基于Qt/Embedded的一個(gè)比較好的開(kāi)源中文輸入法,而且Murphypinyin帶有軟鍵盤(pán),用戶(hù)可以通過(guò)觸摸屏輸入中文、英文、數(shù)字和符號(hào)等。對(duì)于Murphypinyin到Qt/Embedded的移植,網(wǎng)絡(luò)上有很多參考資料,這里不再作介紹。
但是將Murphypinyin應(yīng)用到手持終端上目前還有一個(gè)問(wèn)題:Murphypinyin帶有的軟鍵盤(pán)是標(biāo)準(zhǔn)的 PC101鍵盤(pán),按鍵數(shù)量很多。在對(duì)體積、重量要求很苛刻的手持終端上,觸摸屏本身的尺寸受到嚴(yán)重的制約,PC101鍵盤(pán)會(huì)占據(jù)觸摸屏的大部分顯示面積;而且單個(gè)按鍵所占面積很小,從而對(duì)觸摸屏的定位精度要求很高。然而觸摸屏本身受周?chē)h(huán)境的影響較大,很容易造成定位不準(zhǔn)。本系統(tǒng)將矩陣鍵盤(pán)映射到Murphypinyin上,通過(guò)矩陣鍵盤(pán)輸入中文、英文和數(shù)字,這樣在手持終端上可以使用普通的LCD,從而降低了系統(tǒng)成本、提高了系統(tǒng)的可靠性。
首先考慮的問(wèn)題是:如何用鍵盤(pán)打開(kāi)Murphypinyin輸入法?這里可以修改Murphypinyin軟件包中的Pinyin-Frame.cpp文件中的:
bool QPinyinFrame::filter(int unicode,int keycode,int modifiers,bool isPress,bool autoRepeat)
其中:if(!isHidden()&&isPress)語(yǔ)句用來(lái)判斷Murphypinyin輸入法是否已經(jīng)打開(kāi)并且有按鍵按下。如果是,則判斷當(dāng)前是中文模式、還是英文模式。中文模式則調(diào)用GetKey(unicode,keycode)函數(shù),根據(jù)輸入的拼音搜索漢字;英文模式則調(diào)用SendKey(unicode,keycode)函數(shù)發(fā)送大寫(xiě)或小寫(xiě)英文字母。如果unicode==9&&keycode==Qt::Key_Tab,則進(jìn)行中英文切換。在這里可以添加判斷語(yǔ)句:if(keycode==Qt::Key_Num-Lock)。當(dāng)NumLock按鍵按下時(shí),調(diào)用:QPinyinFrame::sizeHint()和QPinyinFrame::show()兩個(gè)函數(shù)來(lái)開(kāi)啟Murphypinyin輸入法界面。如果再次按下NumLock按鍵,則調(diào)用QPinyinFrame::hide()來(lái)隱藏輸入法界面。
用鍵盤(pán)打開(kāi)Murphypinyin輸入法之后,可以通過(guò)鍵盤(pán)發(fā)送拼音字母來(lái)輸入漢字。通過(guò)發(fā)送unicode==9&&keycode==Qt::Key_Tab來(lái)進(jìn)行中英文切換。
由于手持終端設(shè)備對(duì)自身的體積有嚴(yán)格的要求,為了縮小鍵盤(pán)的體積,本系統(tǒng)模仿手機(jī)鍵盤(pán)的布局,采用按鍵復(fù)用的方式來(lái)縮小鍵盤(pán)大小。將26個(gè)英文字母按字母表順序3個(gè)或4個(gè)一組依次排列在2~9這8個(gè)數(shù)字鍵上,并與阿拉伯?dāng)?shù)字進(jìn)行復(fù)用[4](見(jiàn)圖2)。
硬件上的簡(jiǎn)化必然導(dǎo)致軟件復(fù)雜度的增加。為了使得系統(tǒng)能夠在按下一個(gè)按鍵后自動(dòng)識(shí)別是數(shù)字、英文大寫(xiě)字母、英文小寫(xiě)還是拼音字母,需要修改Qt/Embedded中qkeyboard_qws.cpp的QWSKEYMATRIXHandler::ReadKeyboardData()函數(shù)。
當(dāng)有按鍵按下后,首先需要判斷當(dāng)前是處于何種模式:數(shù)字、拼音、小寫(xiě)英文還是大寫(xiě)英文模式,實(shí)現(xiàn)流程如圖5所示。通過(guò)NumLock按鍵和狀態(tài)標(biāo)志字English-Mode來(lái)進(jìn)行數(shù)字狀態(tài)和其他幾個(gè)狀態(tài)的切換。通過(guò)Tab按鍵來(lái)進(jìn)行中、英文模式的切換,通過(guò)CapsLock按鍵來(lái)進(jìn)行英文大小寫(xiě)字母的切換。
為了使一個(gè)按鍵能夠輸入不同的字符,本系統(tǒng)使用不同的key_ID值來(lái)標(biāo)識(shí)各個(gè)字符,這樣,每按一次鍵都是不同的。圖6是對(duì)于按鍵2的復(fù)用過(guò)程。根據(jù)不同的key_ID結(jié)合當(dāng)前所處的輸入模式,發(fā)送相應(yīng)的數(shù)字、小寫(xiě)英文或大寫(xiě)英文字符。
圖5 輸入模式切換圖
圖6 一鍵多用
本文介紹了基于S3C2440的矩陣鍵盤(pán)的硬件設(shè)計(jì)方法和軟件的驅(qū)動(dòng)開(kāi)發(fā)方法,通過(guò)將Murphpinyin開(kāi)源軟件包與Qt/Embeded自帶輸入法的融合,使用按鍵復(fù)用的策略,采用較少的按鍵,構(gòu)建了一款可輸入數(shù)字、中/英文的嵌入式鍵盤(pán),并在S3C2440上實(shí)現(xiàn)。為手持終端提供了一種嵌入式鍵盤(pán)的解決方案。
[1]胡章勇,蔣朝根.Linux的鍵盤(pán)驅(qū)動(dòng)與Qt/E的鍵盤(pán)映射[J].單片機(jī)與嵌入式系統(tǒng)應(yīng)用,2008(9).
[2]李杰,曹宇,等.基于嵌入式Linux的矩陣鍵盤(pán)的設(shè)計(jì)與實(shí)現(xiàn)[J].現(xiàn)代電子技術(shù),2006(24).
[3]Trolltech.QWSKeyboardHandler Class Reference.[2009-10-05].http://www.kuqin.com/qtdocument/qwskeyboardhandler.html#processKeyEvent.
[4]張萍,徐晶.Qt/Embedded環(huán)境下嵌入式鍵盤(pán)驅(qū)動(dòng)的實(shí)現(xiàn)[J].計(jì)算機(jī)工程,2007,33(11).
單片機(jī)與嵌入式系統(tǒng)應(yīng)用2010年1期