《電子技術應用》
您所在的位置:首頁 > 嵌入式技術 > 設計應用 > 一種基于Android系統(tǒng)的鍵盤模塊設計與實現(xiàn)
一種基于Android系統(tǒng)的鍵盤模塊設計與實現(xiàn)
來源:電子技術應用2013年第9期
梁 坤
(深圳市遠望谷信息技術股份有限公司,廣東 深圳518057)
摘要: 設計了一種基于TCA9535芯片的Android系統(tǒng)外擴鍵盤模塊。該模塊采用矩陣式鍵盤設計,通過I2C總線與主控芯片相連,利用按鍵產(chǎn)生的中斷對鍵盤進行掃描,并完成鍵值的上報。詳細介紹了Android系統(tǒng)的鍵盤驅(qū)動開發(fā)流程和鍵值處理的一些經(jīng)驗,實測證明達到了實用化的要求。這種總線方式的鍵盤模塊設計最大限度地利用了主控芯片資源,具有良好的可移植性和可擴展性,有一定的應用參考價值。
Abstract:
Key words :

摘  要: 設計了一種基于TCA9535芯片的Android系統(tǒng)外擴鍵盤模塊。該模塊采用矩陣式鍵盤設計,通過I2C總線與主控芯片相連,利用按鍵產(chǎn)生的中斷對鍵盤進行掃描,并完成鍵值的上報。詳細介紹了Android系統(tǒng)的鍵盤驅(qū)動開發(fā)流程和鍵值處理的一些經(jīng)驗,實測證明達到了實用化的要求。這種總線方式的鍵盤模塊設計最大限度地利用了主控芯片資源,具有良好的可移植性和可擴展性,有一定的應用參考價值。
關鍵詞: TCA9535;Android系統(tǒng);鍵盤模塊;I2C總線

    Android系統(tǒng)是一種基于Linux內(nèi)核的開放源碼的操作系統(tǒng),目前主要應用于移動設備中(如智能手機、平板電腦等)。而在工業(yè)控制領域的終端設備中,則主要采用Windows CE和嵌入式Linux系統(tǒng)。Android系統(tǒng)的開源特性和良好的UI系統(tǒng),相比Windows CE和Linux系統(tǒng)具有一定的優(yōu)勢,并有逐漸向工業(yè)控制的終端設備滲透的趨勢。
    鍵盤模塊作為一種人機交互接口,在各種終端設備中得到了廣泛應用。矩陣式鍵盤[1-7]占用較少的I/O,能提供較多的按鍵,是鍵盤設計中常見的一種低成本設計方案。隨著工控領域終端設備的智能化,各主控芯片集成的功能越來越多,GPIO往往與其他功能引腳復用。為了最大限度地利用主控芯片資源,GPIO資源在硬件設計時須謹慎規(guī)劃。雖然Android系統(tǒng)自帶虛擬鍵盤,但屏幕的大小和觸屏靈敏度直接影響虛擬鍵盤的使用效率和用戶體驗,一旦觸摸屏失靈,虛擬鍵盤將不能使用。因此在可靠性和成本要求甚高的工業(yè)控制領域并不是最佳選擇。
    本文采用I2C接口的TCA9535[8]芯片實現(xiàn)了一種通用的矩陣式鍵盤模塊,并完成了該模塊在Android系統(tǒng)上的驅(qū)動開發(fā)。由于采用的是I2C總線方式,其他設備也可掛載到同一總線上,因此最大限度地利用了主控芯片的資源。
1 鍵盤模塊硬件設計
1.1 鍵盤模塊硬件接口

    鍵盤模塊通過TCA9535芯片擴展I/O實現(xiàn)。TCA9535芯片是TI公司生產(chǎn)的一款I2C接口擴展I/O的芯片,芯片供電范圍為1.65 V~5.5 V,最大支持400 kHz的通信速率,最大待機電流為3 ?滋A;具有16個獨立I/O和一個開漏極低電平輸出的中斷口,所有I/O口具備機型反轉(zhuǎn)功能,能直接驅(qū)動LED;具有3根地址線,可根據(jù)應用系統(tǒng)要求設置芯片的地址。芯片內(nèi)部有8個可編程的寄存器,分別是2個輸入端口寄存器、2個輸出端口寄存器、2個極性翻轉(zhuǎn)寄存器和2個端口配置寄存器。
    鍵盤模塊采用5×5矩陣式按鍵設計,鍵盤背光通過一個I/O口控制一個MOSFET管驅(qū)動多個并聯(lián)的LED實現(xiàn),總共使用TCA9535芯片的11個I/O口。鍵盤模塊與主控芯片AM3730之間通過I2C接口和一根中斷線連接,如圖1所示。

1.2 鍵盤模塊工作原理
    當按鍵陣列有按鍵按下時,TCA9535芯片產(chǎn)生一個低電平中斷。主控芯片檢測到中斷信號后,通過I2C總線配置TCA9535芯片的相關寄存器,對鍵盤陣列I/O進行掃描。每一次掃描后,讀取鍵盤陣列I/O值。多次掃描后,完成按鍵位置的確定,并根據(jù)位置確定鍵值。主控芯片確認有按鍵按下時,通過I2C總線控制TCA9535芯片控制背光的I/O口,點亮鍵盤的背光。在按鍵過后一段時間內(nèi),若沒有新的按鍵產(chǎn)生,則主控芯片將關閉鍵盤背光。
2 Android系統(tǒng)驅(qū)動開發(fā)
    Android系統(tǒng)大體可分為4層[9],從下往上依次是:Linux內(nèi)核層、Libraries層、Framework層和Application層。Android系統(tǒng)與硬件相關的驅(qū)動基本在Linux內(nèi)核層。因此,本文涉及的TCA9535設備驅(qū)動是指Linux內(nèi)核層的設備驅(qū)動。本文Android系統(tǒng)為Android ICS 4.0.3,其中的Linux內(nèi)核版本為2.6.37。
2.1 Linux內(nèi)核I2C設備驅(qū)動
    Linux內(nèi)核I2C設備驅(qū)動包含3層[10],分別是:I2C總線驅(qū)動(I2C core)、I2C控制器驅(qū)動(I2C adapter)及I2C設備的驅(qū)動(I2C driver)。I2C總線驅(qū)動主要實現(xiàn)對I2C總線及控制器和設備驅(qū)動的管理。這部分代碼為通用部分,Linux內(nèi)核已經(jīng)完善,不需要改動。I2C控制器驅(qū)動跟硬件相關,主要是構(gòu)造一個與I2C總線層接口的數(shù)據(jù)結(jié)構(gòu),并通過接口函數(shù)向I2C總線注冊一個控制器。同時,實現(xiàn)對I2C控制器中斷的處理函數(shù),完成I2C設備具體功能的實現(xiàn)。I2C設備驅(qū)動主要是構(gòu)造一個與I2C總線層接口的數(shù)據(jù)結(jié)構(gòu),通過接口函數(shù)向I2C總線層注冊一個I2C設備驅(qū)動。同時構(gòu)造一個與用戶層接口的數(shù)據(jù)結(jié)構(gòu),通過接口函數(shù)向內(nèi)核注冊一個字符型設備。本文涉及的驅(qū)動開發(fā)主要包含I2C控制器驅(qū)動和I2C設備驅(qū)動。
2.2 I2C控制器驅(qū)動開發(fā)
    (1)驅(qū)動文件添加
    在Linux內(nèi)核的drivers/i2c/muxes目錄下,新建一個tca9535kbd.c文件(該文件為TCA9535的設備驅(qū)動文件),同時在該層的Makefile和Kconfig文件中,添加對新建文件的支持。重新編譯內(nèi)核后,須選中添加的部分。如Makefile中添加:
obj-$(CONFIG_I2C_MUX_TCA9535)+=tca9535kbd.o
    (2)構(gòu)建與I2C總線層接口的數(shù)據(jù)結(jié)構(gòu)和接口函數(shù)
Struct tca9535kbd_data{
Struct i2c_client client;
Struct input_dev *input;//輸入事件
Struct work_struct tca9535kdb_work;//按鍵處理
}
static int tca9535kbd_attach_adapter(struct i2c_adapter *adapter)
//接口函數(shù)
{
struct i2c_client    *new_client;
struct input_dev    *input;
struct tca9535kbd_data *data;
data = kzalloc(sizeof(struct tca9535kbd_data), GFP_KERNEL);
//申請分配空間
input = input_allocate_device();
input_register_device(input);//向總線注冊
    ……//此處省略一些I2C配置
request_irq(new_client->irq, tca9535kbd_keys_isr,
IRQF_TRIGGER_FALLING | IRQF_SHARED, "tca9535kbd",
data);//注冊中斷處理函數(shù)tca9535kbd_keys_isr
Init_tca9535();//初始化TCA9535配置
}
static int tca9535kbd_detach_adapter(struct i2c_client *client)
//接口函數(shù)
{
struct tca9535kbd_data *data = container_of(client, struct
tca9535kbd_data, client);
input_unregister_device(data->input);//向I2C總線注銷
free_irq(client->irq, data);
kfree(i2c_get_clientdata(client));
return 0;
}
    (3)鍵值處理
    主控芯片接收到中斷信號后,進入中斷服務函數(shù)(tca9535kbd_keys_isr函數(shù))進行按鍵事件處理。由于鍵盤按鍵的處理(鍵值掃描及去抖等)需要一定的時間,為了不長時間占用CPU資源,中斷服務程序只負責將真正的按鍵事件處理函數(shù)(tca9535kbd_do_work函數(shù))放在內(nèi)核的后臺任務隊列。內(nèi)核將根據(jù)規(guī)則進行自動調(diào)度并執(zhí)行。向內(nèi)核隊列中加入按鍵事件處理函數(shù)通過INIT_WORK函數(shù)和schedule_work函數(shù)來實現(xiàn)。初始化工作隊列函數(shù)(INIT_WORK函數(shù))在接口函數(shù)tca9535kbd_attach_adapter中調(diào)用,任務加入內(nèi)核后臺隊列(schedule_work函數(shù))在中斷服務程序中調(diào)用。
    按鍵事件處理流程如圖2所示。

    圖2中,鍵盤的防抖采取時間過濾、多次讀取來確定。向系統(tǒng)上報按鍵事件包括按鍵按下事件和按鍵松開事件。由于TCA9535芯片只有在有按鍵按下時才產(chǎn)生中斷,按鍵處理程序中的150 ms的較大延時(經(jīng)驗值)用于防止一次按鍵事件被處理成多次按鍵事件(不影響鍵連擊和長按事件的處理)。另外,在上報按鍵事件時,須同時上報按鍵按下和按鍵松開事件,而不額外檢測按鍵松開。具體實現(xiàn)函數(shù)如下:
    input_event(data->input, EV_KEY, keycode, 1);
//向系統(tǒng)上報按鍵按下事件
    input_sync(data->input);
//同步告知input core子系統(tǒng)事件結(jié)束
    input_event(data->input, EV_KEY, keycode, 0);
//向系統(tǒng)上報按鍵松開事件
    input_sync(data->input);//同上
2.3 I2C設備驅(qū)動開發(fā)
    (1)構(gòu)建I2C總線驅(qū)動數(shù)據(jù)結(jié)構(gòu)
    static struct i2c_driver tca9535kbd_driver = {
        .driver = {
            .owner    = THIS_MODULE,
            .name    = "tca9535kbd",
    },
    .attach_adapter    = tca9535kbd_attach_adapter,
    .detach_adapter= tca9535kbd_detach_adapter,
    };
    (2)注冊設備驅(qū)動
    static int __init tca9535kbd_init(void)
    {
    return i2c_add_driver(&tca9535kbd_driver);
    }
    static void __exit tca9535kbd_exit(void)
    {
        i2c_del_driver(&tca9535kbd_driver);
    }
    module_init(tca9535kbd_init);
    module_exit(tca9535kbd_exit);
    (3)硬件平臺設備初始化
    在主控芯片對應的平臺文件中須添加對設備的初始化參數(shù),并向平臺注冊硬件設備(本文所對應的平臺文件為內(nèi)核中arm/arm/mach-omap2/board-omap3beagle.c)。
    static struct i2c_board_info __initdata beagle_i2c_
            tca9535keyboard[ ]= {
    {
        I2C_BOARD_INFO("tca9535kbd",0x26),
            //驅(qū)動名稱和地址
        .flags=I2C_CLIENT_WAKE,
        .irq=OMAP_GPIO_IRQ(65),//主控芯片中斷管腳號
    },
};
omap_register_i2c_bus(3,400,beagle_i2c_tca9535keyboard,
ARRAY_SIZE(beagle_i2c_tca9535keyboard));
//配置I2C總線時鐘,向平臺設備注冊
2.4 Andorid鍵值映射

 


    Andorid系統(tǒng)的鍵盤按鍵事件由WindowManagerService服務來管理,然后以消息的形式轉(zhuǎn)發(fā)給當前活動的應用程序進行處理。Linux內(nèi)核層上報按鍵事件時附帶了一個鍵值(在Linux內(nèi)核include/input.h文件中定義),該鍵值與Andorid系統(tǒng)使用中的鍵值對應時才能正確顯示按鍵值。Andorid系統(tǒng)通過qwerty.kl和generic.kl文件進行鍵值的映射。一些常用的按鍵在Linux內(nèi)核層和Android層基本一致。若需要自定義按鍵,或者內(nèi)核與Andorid系統(tǒng)層個別鍵值不一致時,須修改一方的值以完成兩者的統(tǒng)一。
    本文介紹了一款Android系統(tǒng)矩陣式鍵盤的設計與實現(xiàn)方式,實際使用證明該鍵盤模塊工作穩(wěn)定,達到了預期設計目標。該方案基于I2C總線,有利于提高主控芯片的資源利用率,方便移植到其他嵌入式系統(tǒng)上,具備很好的可擴展性。文中介紹的驅(qū)動開發(fā)流程對Android系統(tǒng)的底層開發(fā)具有一定的參考價值和借鑒意義。
參考文獻
[1] 王選民.智能儀器原理及設計[M].北京:清華大學出版社,2008.
[2] 黃菁,劉青春.ARM嵌入式系統(tǒng)GPIO擴展鍵盤設計[J].自動化應用,2011(7):1-2.
[3] 孟桂芳.基于嵌入式Linux的矩陣鍵盤設備驅(qū)動的設計[J]. 蘇州大學學報(工科版),2011,31(4):71-74.
[4] 李其珂,付紅橋.基于嵌入式Linux的矩陣鍵盤驅(qū)動研究與實現(xiàn)[J].重慶理工大學學報(自然科學),2012,26(12):88-92.
[5] 傅超,張昌華,孟勁松.基于嵌入式Linux的矩陣鍵盤模塊的設計[J].微型機與應用,2012,31(21):7-10.
[6] 徐德龍,余瑾.基于嵌入式Linux系統(tǒng)的鍵盤驅(qū)動設計[J].單片機與嵌入式系統(tǒng)應用,2013(2):21-23.
[7] 張永強,鄧少芝,王凱,等.專用鍵盤接口芯片的一種CPLD實現(xiàn)方案[J].電子技術應用,2002,28(11):17-18.
[8] TI.TCA9535 datasheet[EB/OL].(2009)[2009].http://www.ti.com/product/tca9535.
[9] 鄧平凡.深入理解Android:卷I[M].北京:機械工業(yè)出版社,2011.
[10] 杜博,方向忠.嵌入式Linux系統(tǒng)下I2C設備驅(qū)動程序的開發(fā)[J].微計算機信息,2006,22(4-2):31-33.

此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權禁止轉(zhuǎn)載。