WinCE下光電編碼器的驅(qū)動(dòng)程序設(shè)計(jì)
光電編碼器以其體積小、輸入靈活等特點(diǎn)作為輸入設(shè)備,廣泛應(yīng)用于各種嵌入式儀器中。本文討論光電編碼器的原理及使用方法;以三星公司ARM9芯片S3C2410為CPU的嵌入式系統(tǒng)開(kāi)發(fā)板為平臺(tái),詳細(xì)闡述嵌入式操作系統(tǒng)WinCE下光電編碼器驅(qū)動(dòng)程序的設(shè)計(jì)方法。實(shí)驗(yàn)證明,該方法正確可行,程序運(yùn)行穩(wěn)定可靠。
關(guān)鍵詞 嵌入式系統(tǒng) WinCE 光電編碼器 S3C2410
引言
近年來(lái),嵌入式技術(shù)發(fā)展迅速,嵌入式系統(tǒng)在各行各業(yè)得到了廣泛的應(yīng)用。然而,由于嵌入式計(jì)算機(jī)的專(zhuān)用性,系統(tǒng)的硬件、軟件結(jié)構(gòu)千差萬(wàn)別,其輸入設(shè)備也不再像通用計(jì)算機(jī)那樣單一。嵌入式計(jì)算機(jī)的輸入設(shè)備一般有鼠標(biāo)、鍵盤(pán)、觸摸屏、按鈕、旋鈕等,而光電編碼器(俗稱(chēng)“單鍵飛梭”)作為一種輸入設(shè)備,由于其具有輸入靈活,簡(jiǎn)單可靠等特點(diǎn),因此特別適合應(yīng)用在嵌入式儀器和手持式設(shè)備上,整個(gè)系統(tǒng)可以只用一個(gè)鍵作為輸入。觸摸屏由于其方便靈活、節(jié)省空間、界面直觀等特點(diǎn)也備受青睞,但存在壽命短,長(zhǎng)時(shí)間使用容易產(chǎn)生誤差等缺點(diǎn)。如果用光電編碼器輔助觸摸屏作為輸入設(shè)備,必將大大增強(qiáng)系統(tǒng)的可靠性,使得人機(jī)接口更加人性化。但由于光電編碼器并不是WinCE的標(biāo)準(zhǔn)輸入設(shè)備,因此其驅(qū)動(dòng)程序在嵌入式操作系統(tǒng)Windows CE Platform Builder中并未給出。本文以三星公司S3C2410(ARM9芯片)為CPU的嵌入式系統(tǒng)開(kāi)發(fā)板為平臺(tái),詳細(xì)闡述了嵌入式操作系統(tǒng)WinCE下光電編碼器驅(qū)動(dòng)程序的設(shè)計(jì)方法,以供同行參考。
1? 光電編碼器的工作原理
光電編碼器(Optical Encoder)俗稱(chēng)“單鍵飛梭”,其外觀好像一個(gè)電位器,因其外部有一個(gè)可以左右旋轉(zhuǎn)同時(shí)又可按下的旋鈕,很多設(shè)備(如顯示器、示波器等)用它作為人機(jī)交互接口。下面以美國(guó)Greyhill公司生產(chǎn)的光電編碼器為例,介紹其工作原理及使用方法。光電編碼器的內(nèi)部電路如圖1所示,其內(nèi)部有1個(gè)發(fā)光二極管和2個(gè)光敏三極管。當(dāng)左右旋轉(zhuǎn)旋鈕時(shí),中間的遮光板會(huì)隨旋鈕一起轉(zhuǎn)動(dòng),光敏三極管就會(huì)被遮光板有次序地遮擋,A、B相就會(huì)輸出圖2所示的波形;當(dāng)按下旋鈕時(shí),2、3兩腳接通,其用法同一般按鍵。
當(dāng)順時(shí)針旋轉(zhuǎn)時(shí),光電編碼器的A相相位會(huì)比B相超前半個(gè)周期;反之,A相會(huì)比B相滯后半個(gè)周期。通過(guò)檢測(cè)A、B兩相的相位就可以判斷旋鈕是順時(shí)針還是逆時(shí)針旋轉(zhuǎn),通過(guò)記錄A或B相變化的次數(shù),就可以得出旋鈕旋轉(zhuǎn)的次數(shù),通過(guò)檢測(cè)2、3腳是否接通就可以判斷旋鈕是否按下。其具體的鑒相規(guī)則如下:
①? A為上升沿,B=0時(shí),旋鈕右旋;
②? B為上升沿,A=1時(shí),旋鈕右旋;
③? A為下降沿,B=1時(shí),旋鈕右旋;
④? B為下降沿,A=0時(shí),旋鈕右旋;
⑤? B為上升沿,A=0時(shí),旋鈕左旋;
⑥? A為上升沿,B=1時(shí),旋鈕左旋;
⑦? B為下降沿,A=1時(shí),旋鈕左旋;
⑧? A為下降沿,B=0時(shí),旋鈕左旋。
通過(guò)上述方法,可以很簡(jiǎn)單地判斷旋鈕的旋轉(zhuǎn)方向。在判斷時(shí)添加適當(dāng)?shù)难訒r(shí)程序,以消除抖動(dòng)干擾。
2? WinCE提供的驅(qū)動(dòng)模型
WinCE操作系統(tǒng)支持兩種類(lèi)型的驅(qū)動(dòng)程序。一種為本地驅(qū)動(dòng)程序,是把設(shè)備驅(qū)動(dòng)程序作為獨(dú)立的任務(wù)實(shí)現(xiàn)的,直接在頂層任務(wù)中實(shí)現(xiàn)硬件操作,因此都有明確和專(zhuān)一的目的。本地設(shè)備驅(qū)動(dòng)程序適合于那些集成到Windows CE平臺(tái)的設(shè)備,諸如鍵盤(pán)、觸摸屏、音頻等設(shè)備。另一種是具有定制接口的流接口驅(qū)動(dòng)程序。它是一般類(lèi)型的設(shè)備驅(qū)動(dòng)程序。流接口驅(qū)動(dòng)程序的形式為用戶一級(jí)的動(dòng)態(tài)鏈接庫(kù)(DLL)文件,用來(lái)實(shí)現(xiàn)一組固定的函數(shù)稱(chēng)為“流接口函數(shù)”,這些流接口函數(shù)使得應(yīng)用程序可以通過(guò)文件系統(tǒng)訪問(wèn)這些驅(qū)動(dòng)程序。本文討論的光電編碼器就屬于流接口設(shè)備。
2.1? 流設(shè)備驅(qū)動(dòng)加載過(guò)程
WinCE.NET系統(tǒng)運(yùn)行時(shí)會(huì)啟動(dòng)負(fù)責(zé)流驅(qū)動(dòng)的加載進(jìn)程DEVICE.exe。DEVICE.exe進(jìn)程對(duì)驅(qū)動(dòng)的加載是通過(guò)裝載注冊(cè)表列舉器(RegEnum.dll)實(shí)現(xiàn)的。在WinCE.NET中,所有設(shè)備的資源信息都由OAL負(fù)責(zé)記錄在系統(tǒng)注冊(cè)表中,RegEnum.dll一個(gè)一個(gè)掃描注冊(cè)表項(xiàng)HEKY_LOCAL_MACHINE\Driver\BuiltIn下的子鍵,發(fā)現(xiàn)新設(shè)備就根據(jù)每個(gè)表項(xiàng)的內(nèi)容進(jìn)行硬件設(shè)備初始化。
2.2? 中斷與中斷處理
如果一個(gè)驅(qū)動(dòng)程序要處理一個(gè)中斷,那么驅(qū)動(dòng)程序需要首先使用CreateEvent函數(shù)建立一個(gè)事件,調(diào)用InterruptInitialize函數(shù)將該事件與中斷標(biāo)識(shí)綁定。然后驅(qū)動(dòng)程序中的IST就可以使用WaitForSingleObject函數(shù)來(lái)等待中斷的發(fā)生。在一個(gè)硬件中斷發(fā)生之后,操作系統(tǒng)進(jìn)入異常處理程序,異常處理程序調(diào)用OAL的OEMInterruptHandler函數(shù),該函數(shù)檢測(cè)硬件并將中斷標(biāo)識(shí)返回給系統(tǒng);系統(tǒng)得到該中斷標(biāo)識(shí)便會(huì)找到該中斷標(biāo)識(shí)對(duì)應(yīng)的事件,并喚醒等待相應(yīng)事件的線程(IST),然后IST進(jìn)行中斷處理。處理完成之后,IST需要調(diào)用InterruptDone函數(shù)來(lái)告訴操作系統(tǒng)中斷處理結(jié)束,操作系統(tǒng)再次調(diào)用OAL中的OEMInterruptDone函數(shù),最后完成中斷的處理。圖3為WinCE.NET中斷處理的流程框圖。
3? 光電編碼器驅(qū)動(dòng)程序的設(shè)計(jì)
3.1? 光電編碼器與S3C2410的硬件接口
光電編碼器與S3C2410的接口電路如圖4所示。光電編碼器的A、B相為集電極開(kāi)路輸出,由于S3C2410的I/O口電平為3.3 V,所以將其通過(guò)電阻上拉到3.3 V后再分別接到CPU的EINT0和EINT1上;將P1直接接到3.3 V,P2通過(guò)電阻下拉到GND。當(dāng)旋鈕按下時(shí),P2口輸出為高電平,否則輸出為低電平。
工作狀態(tài)下,將EINT0、EINT1配置成上升沿和下降沿均觸發(fā)的外部中斷,將EINT2配置成上升沿觸發(fā)的中斷,旋鈕按下時(shí)EINT2引腳產(chǎn)生上升沿觸發(fā)中斷。
3.2? 外部中斷初始化及中斷服務(wù)程序的編寫(xiě)
首先必須完成CPU的I/O口和中斷的初始化工作,然后再編寫(xiě)中斷處理程序。具體分為4個(gè)步驟:
①? 初始化I/O口。在Port_Init()函數(shù)中,將EINT0和EINT1初始化為上升沿和下降沿均觸發(fā)的中斷,將EINT2初始化為上升沿觸發(fā)的中斷。
②? 添加中斷號(hào)。在oalintr.h下添加光電編碼器中斷向量的宏定義。代碼為
#define SYSINTR_OED(SYSINTR_FIRMWARE+20)
③? 添加中斷的初始化、禁止、復(fù)位等函數(shù),分別在OEMInterruptEnable()、OEMInterruptDisable()、OEMInterruptDone()等函數(shù)中加入相關(guān)代碼。
④? 返回中斷標(biāo)識(shí),由OEMInterruptHandler()函數(shù)返回中斷標(biāo)識(shí)(SYSINTR_OED)。
3.3? 編寫(xiě)流接口驅(qū)動(dòng)程序
Windows CE.net把中斷處理分成兩個(gè)部分:中斷服務(wù)程序(ISR)和中斷服務(wù)線程(IST)。ISR通常要求越短、越快越好,它的唯一任務(wù)就是返回中斷標(biāo)識(shí)。正由于ISR很小,只能做少量的處理,因此中斷處理器就調(diào)用IST執(zhí)行大多數(shù)的中斷處理。中斷服務(wù)線程(IST)在從WaitForSingleObject()函數(shù)得到中斷已經(jīng)發(fā)生的信號(hào)前一直保持空閑;當(dāng)接收到中斷信號(hào)后,它就在本機(jī)設(shè)備驅(qū)動(dòng)程序的PDD層調(diào)用子程序,這些程序反過(guò)來(lái)訪問(wèn)硬件以獲得硬件的狀態(tài)。IST使用InterruptInitialize()函數(shù)來(lái)注冊(cè)自己,然后使用WaitForSingleObject()函數(shù)等待中斷信號(hào)。如果這時(shí)中斷信號(hào)到來(lái),則應(yīng)將光電編碼器的狀態(tài)記錄下來(lái),保存在變量OED_Status中。OED_Status=1表示旋鈕按下,OED_Status=2表示旋鈕逆時(shí)針旋轉(zhuǎn),OED_Status=3表示旋鈕順時(shí)針旋轉(zhuǎn)。
這里還有一種比較簡(jiǎn)單的鑒相規(guī)則,具體步驟是,當(dāng)創(chuàng)建線程時(shí)讀出EINT1的電平狀態(tài)并保存在變量PreEINT1中,每次中斷到來(lái)時(shí)首先判斷EINT2是否為高電平。如果為高電平,則說(shuō)明按鈕按下;如果EINT2為低電平,則判斷EINT0電平是否與PreEINT1相同。如果相同,則說(shuō)明旋鈕逆時(shí)針旋轉(zhuǎn);反之,旋鈕順時(shí)針旋轉(zhuǎn),判斷的流程如圖5所示。
Windows CE流接口驅(qū)動(dòng)程序模型要求驅(qū)動(dòng)程序開(kāi)發(fā)者編寫(xiě)10個(gè)接口函數(shù),針對(duì)光電編碼器的驅(qū)動(dòng)主要應(yīng)完成設(shè)備初始化和數(shù)據(jù)讀取2個(gè)函數(shù)的編寫(xiě)。Windows CE設(shè)備文件名前綴由3個(gè)大寫(xiě)字母組成,操作系統(tǒng)使用這3個(gè)字母來(lái)識(shí)別與流接口驅(qū)動(dòng)程序相對(duì)應(yīng)的設(shè)備。這里定義設(shè)備文件名前綴為“OED”(Optical Encoder),其中設(shè)備初始化函數(shù)OED_Init()在Windows CE裝載驅(qū)動(dòng)程序時(shí)用于創(chuàng)建中斷事件和中斷服務(wù)線程。在函數(shù)OED_Read()中將光電編碼器的狀態(tài)(OED_Status)返回。
3.4? 封裝驅(qū)動(dòng)程序并加入到WinCE中
根據(jù)上述方法編譯出動(dòng)態(tài)鏈接庫(kù)(DLL)還不夠,因?yàn)樗慕涌诤瘮?shù)還沒(méi)有導(dǎo)出,還需要告訴鏈接程序輸出什么樣的函數(shù),因此必須建立一個(gè)后綴名為def的文件。在本設(shè)計(jì)中為OpticalEncoder.def。下面是此文件的內(nèi)容:
LIBRARY OpticalEncoder
EXPORTS
OED_Close
OED_Deinit
OED_Init
OED_IOControl
OED_Open
OED_PowerDown
OED_PowerUp
OED_Read
OED_Seek
OED_Write
一個(gè)具體的流接口驅(qū)動(dòng)程序和注冊(cè)表是密不可分的。向WinCE內(nèi)核添加注冊(cè)表項(xiàng)的方法有兩種:一種是直接修改Platform Builder下的reg文件;另一種是自己編寫(xiě)一個(gè)注冊(cè)表文件,通過(guò)添加組件的方法將動(dòng)態(tài)鏈接庫(kù)文件添加到內(nèi)核中。這里用第2種方法,將OpticalEncoder.dll添加到內(nèi)核中。編寫(xiě)的注冊(cè)表文件內(nèi)容如下:
[HKEY_LOCAL_MACHINE\Drivers\Built In\STRINGS]
"Index"=dword :1
"Prefix"="OED"
"Dll"="OpticalEncoder.dll"
"Order"=dword :0
最后編寫(xiě)一個(gè)CEC文件,完成對(duì)定制內(nèi)核注冊(cè)表部分的修改并將OpticalEncoder.dll添加到系統(tǒng)內(nèi)核中去,然后在Platform Builder中就可以直接添加已經(jīng)編寫(xiě)好的驅(qū)動(dòng)程序了。
結(jié)語(yǔ)
本文主要介紹了光電旋轉(zhuǎn)編碼器的原理及應(yīng)用方法,并詳細(xì)介紹了WinCE驅(qū)動(dòng)程序的結(jié)構(gòu),成功地開(kāi)發(fā)出了光電編碼器在嵌入式操作系統(tǒng)WinCE下的驅(qū)動(dòng)程序。實(shí)驗(yàn)證明,該方法正確可行,程序運(yùn)行穩(wěn)定可靠。
評(píng)論
查看更多