高永相
摘要:在產(chǎn)品設(shè)計(jì)和開發(fā)中,需要在arm平臺(tái)下進(jìn)行驅(qū)動(dòng)開發(fā),根據(jù)旋轉(zhuǎn)編碼器的基本工作原理,利用Linux 設(shè)備驅(qū)動(dòng)的輸入子系統(tǒng)進(jìn)行了驅(qū)動(dòng)和應(yīng)用程序的設(shè)計(jì)。實(shí)驗(yàn)結(jié)果表明,方案切實(shí)可行。
關(guān)鍵詞: Linux; 旋轉(zhuǎn)編碼器; Input子系統(tǒng)
中圖分類號(hào): TP273 文獻(xiàn)標(biāo)志碼: A
選擇EC11旋轉(zhuǎn)編碼器作為輸入按鈕,向右旋轉(zhuǎn),按步長增加參數(shù),向左旋轉(zhuǎn),按步長遞減參數(shù)。為實(shí)現(xiàn)設(shè)計(jì)目標(biāo),研究旋轉(zhuǎn)編碼器的輸出特性以及l(fā)inux平臺(tái)的輸入子系統(tǒng)特性,并成功移植到當(dāng)前設(shè)備并設(shè)計(jì)應(yīng)用程序[1]。
1硬件結(jié)構(gòu)及基本原理
硬件平臺(tái)以NXP的I.MX6ULL 為核心的。EC11是AB 相旋轉(zhuǎn)編碼器。在正向旋轉(zhuǎn)時(shí)A相超前B相 90°; 在編碼器反轉(zhuǎn)時(shí),B相超前A相 90°。通過判斷A、B兩相邊沿處的電平高低就可判斷方向。
2 輸入子系統(tǒng)的組成
輸入設(shè)備有共同的特點(diǎn),輸入子系統(tǒng)自下而上分為驅(qū)動(dòng)層、核心層和事件處理層。驅(qū)動(dòng)層是與硬件相關(guān)的實(shí)現(xiàn)。核心層承上啟下,為驅(qū)動(dòng)層提供輸入設(shè)備注冊(cè)和操作接口。事件處理層主要和用戶空間進(jìn)行交互,負(fù)責(zé)創(chuàng)建設(shè)備文件并將報(bào)告的事件傳遞給用戶空間[2]。最底層就是具體設(shè)備,比如按鍵,旋轉(zhuǎn)編碼器等。
3 驅(qū)動(dòng)的設(shè)計(jì)與實(shí)現(xiàn)
設(shè)備驅(qū)動(dòng)程序是 Linux 內(nèi)核的一部分,它提供內(nèi)核接口,運(yùn)行在內(nèi)核態(tài)。驅(qū)動(dòng)程序主要完成如下功能:
1) 完成rotary encoder設(shè)備初始化、資源申請(qǐng)和釋放等操作;
2) 完成數(shù)據(jù)在內(nèi)核和硬件設(shè)備間的讀取和寫入;
3) 接收應(yīng)用程序傳給硬件設(shè)備的數(shù)據(jù)并返回應(yīng)用程序請(qǐng)求的數(shù)據(jù);
input 核心層會(huì)向 Linux 內(nèi)核注冊(cè)一個(gè)字符設(shè)備,input.c 就是 input 輸入子系統(tǒng)的核心層。class_registe注冊(cè)一個(gè)input 類,系統(tǒng)啟動(dòng)以后就會(huì)在/sys/class 目錄下生成 input 子 目錄。register_chrdev_region注冊(cè)一個(gè)字符設(shè)備[3]。設(shè)備驅(qū)動(dòng)流程圖見圖1的左邊。
3.1引腳的配置和初始化
EC_A連接到IMX6ULL 的GPIO5_1引腳,EC_B連接到IMX6ULL的GPIO1_1引腳。
引腳的配置和初始化,是外界硬件設(shè)備和內(nèi)核溝通的橋梁。使用設(shè)備樹來描述板級(jí)設(shè)備信息。
compatible = "rotary-encoder";用來和設(shè)備驅(qū)動(dòng)匹配
gpios = <&gpio5 1 GPIO_ACTIVE_LOW>,<&gpio1 1 GPIO_ACTIVE_LOW>;配置rotary encoder 驅(qū)動(dòng)的兩個(gè)輸入引腳,低電平有效。
3.2 驅(qū)動(dòng)加載函數(shù)
輸入對(duì)象的初始化是在驅(qū)動(dòng)加載入口函數(shù)內(nèi)完成的。輸入對(duì)象描述了一個(gè)輸入設(shè)備,包括它可能報(bào)告的事件,使用input 子系統(tǒng)的時(shí)候需注冊(cè)一個(gè)input設(shè)備,input_dev結(jié)構(gòu)體表示input設(shè)備。調(diào)用devm_input_allocate_device(struct input_dev*)實(shí)現(xiàn)input 設(shè)備的內(nèi)存分配。使用input_set_capability(input, EV_REL, encoder->axis)注冊(cè)此驅(qū)動(dòng),事件為EV_REL,使旋轉(zhuǎn)編碼器支持相對(duì)坐標(biāo)。之后調(diào)用input_register_device(struct input_dev*)函數(shù)實(shí)現(xiàn)將輸入設(shè)備注冊(cè)到輸入子系統(tǒng)中,并配置中斷函數(shù)。使用devm_request_threaded_irq注冊(cè)中斷,handler = &rotary_encoder_irq設(shè)定中斷函數(shù)。
3.3中斷函數(shù)的實(shí)現(xiàn)
中斷函數(shù)根據(jù)引腳當(dāng)前的狀態(tài)和之前狀態(tài),判斷方向并上報(bào)方向數(shù)據(jù)。用state變量來保存兩個(gè)輸入引腳的電平狀態(tài)。state=2之后state=1,判斷為順時(shí)針。state=2之后state=3,判斷為逆時(shí)針,input_report_rel(encoder->input, encoder->axis, encoder->dir)報(bào)告事件。調(diào)用函數(shù)input_sync(encoder->input)來通知輸入子系統(tǒng)同步到用戶層。
4用戶層應(yīng)用實(shí)現(xiàn)
根據(jù) Linux 下內(nèi)核調(diào)用機(jī)制,實(shí)現(xiàn)應(yīng)用程序讀取旋轉(zhuǎn)編碼器的值,有兩個(gè)值,1表示順時(shí)針旋轉(zhuǎn),-1表示逆時(shí)針旋轉(zhuǎn),由上層應(yīng)用程序?qū)?shù)據(jù)進(jìn)一步處理后輸出。流程如圖1的右圖。將應(yīng)用程序交叉編譯后在ARM平臺(tái)上執(zhí)行。此時(shí)轉(zhuǎn)動(dòng)旋轉(zhuǎn)編碼器運(yùn)行結(jié)果正向旋轉(zhuǎn)value=1 反向旋轉(zhuǎn)value=-1。
5結(jié)束語
本文設(shè)計(jì)并實(shí)現(xiàn)了Linux 下的旋轉(zhuǎn)編碼器驅(qū)動(dòng)程序,實(shí)現(xiàn)了旋轉(zhuǎn)編碼器相對(duì)值旋轉(zhuǎn)方向檢測功能,在實(shí)際應(yīng)用中運(yùn)行良好,達(dá)到了預(yù)期目的。
參考文獻(xiàn)
[1] 屈克文,石奮蘇基于 ARM- Linux 的旋轉(zhuǎn)編碼器接口與驅(qū)動(dòng)程序的設(shè)計(jì)[J] 計(jì)算機(jī)應(yīng)用,2011,12:31
[2] 宋寶華.Linux設(shè)備驅(qū)動(dòng)開發(fā)詳解[M].機(jī)械工業(yè)出版社,2015.7