??? 摘? 要: 通過對鼠標底層通信原理及協(xié)議的深入分析,探討了鼠標在80C196單片機系統(tǒng)中的應用價值與可行性,并介紹了鼠標接口軟件設計的原理及方法,給出了80C196單片機與Microsoft鼠標的具體接口程序。?
??? 關鍵詞: 鼠標? 接口技術? 軟件設計? 接口程序
?
??? 80C196單片機由于價格低、處理能力強,在信號分析、數(shù)據(jù)采集等很多領域得到廣泛應用,在目標系統(tǒng)中使用各種規(guī)格的液晶或CRT顯示器也越來越多。因此在這樣的單片機系統(tǒng)中引入鼠標,將會方便操作,提高工作效率。鼠標內核本質上是一個二維的角度或位移信號檢測裝置,耗電極少、可靠性高、價格低廉,可以在許多場合發(fā)揮作用。鼠標與主機之間通過RS-232標準串行接口" title="串行接口">串行接口進行通信,信息傳送是單方向、無條件、無應答連續(xù)進行的。此外80C196的UART不直接支持鼠標的接口協(xié)議,在程序設計" title="程序設計">程序設計中必須予以注意。本文主要探討80C196單片機與Microsoft兼容鼠標接口程序的設計實現(xiàn)。?
1 鼠標信號發(fā)送協(xié)議與過程?
??? 鼠標是一個功能高度集中的小型機電一體化系統(tǒng)。它首先將直線位移轉換成角度位移,再轉變成數(shù)字量,然后與按鈕狀態(tài)統(tǒng)一編碼,通過RS-232串口" title="串口">串口發(fā)出。鼠標工作所需功率從RS-232串行接口的控制線上竊取(PS/2、USB接口鼠標除外)。當鼠標被拖動" title="拖動">拖動超過一個最小距離或某一按鈕被按下時,它按照規(guī)定的協(xié)議將移動的距離和按鈕狀態(tài)通過一次或幾次信息發(fā)送到主機;主機上的鼠標驅動程序將信息變換成鼠標位置和按鈕狀態(tài)供其它程序模塊調用。每發(fā)生一次移動或按鈕狀態(tài)變化,鼠標向上發(fā)送一次信息。通常一般鼠標的分辨率為400DPI。理論上即沿著某一方向每拖動一英寸(一般速度),會產(chǎn)生400次信息發(fā)送過程。如果拖動較快,則信息發(fā)送次數(shù)減少,但所反映的總的移動距離仍然是400步。?
??? 各種串行接口鼠標在物理層普遍采用標準的串行通信協(xié)議,波特率為1200bps。幀格式為7個數(shù)據(jù)位、2個停止位,無奇偶校驗位。上層協(xié)議則在此基礎上以十六進制數(shù)形式直接發(fā)送鼠標信息,包括:初始化報告;移動方向、距離、按鈕狀態(tài)。其一般形式如表1所示。?
?
?
2 鼠標接口程序設計?
??? 80C196系列單片機內設RS-232收發(fā)器,但需要配置接口芯片實現(xiàn)電平轉換??紤]到鼠標從串口竊取功率,接口芯片必須具有一定的驅動能力,而不能采用簡單的準RS-232電平轉換器。這里采用MAX232E作為接口芯片。?
??? 圖1中左側為80C196單片機,P2.0(TXD)、P2.1(RXD)通過MAX232E形成滿足鼠標要求的串行接口,包括生成標準RS-232C電平和提供電源供應。圖1中最右邊為9針或25針標準串行接插件。由于鼠標的電源供應采用功率竊取方案,由DTR/RTS提供,這里為DTR加限流電阻防止對鼠標造成傷害。RTS由MAX232E的信號發(fā)送端提供,通過80C196的P2.0控制MAX232E的10腳(對應的輸出腳為7腳)電平高低以改變7腳電位,使鼠標可以接收來自RTS的控制命令,以實現(xiàn)鼠標安裝與否的檢測。在MAX232E的11腳(對應的輸入腳為14腳)設置高電平以保證14腳電位為負RS-232電位,滿足鼠標發(fā)送信號時的電平要求。?
?
?
??? 從鏈路層看,80C196串行接口的四種工作方式" title="工作方式">工作方式均不滿足鼠標的幀格式要求;但其工作方式1(1位起始位、8位數(shù)據(jù)位、1位停止位)的總傳送位數(shù)與鼠標(1位起始位、7個數(shù)據(jù)位、2個停止位)相同,均為10位。接收過程中80C196收到7個數(shù)據(jù)位后,將2個停止位中的第一個作為數(shù)據(jù)位裝入接收緩沖器的最高位,由于停止位在物理層是高電平,作為數(shù)據(jù)被接收后相當于邏輯“0”;剩下的第二個停止位恰好為80C196 提供了有效的停止位。利用80C196的工作方式1完全可以保證正確接收鼠標信息。?
??? 單片機起動后,通過鼠標驅動模塊對鼠標進行初始化,即通過P2.0使RTS電平翻轉一次而令鼠標發(fā)送初始化報告,以確認鼠標是否安裝。之后,鼠標即可隨著拖動或按鈕操作向單片機發(fā)送動作信息,經(jīng)接口模塊翻譯即可反應鼠標位置和按鈕狀態(tài)。?
??? 鼠標接口模塊主要包括按鈕狀態(tài)識別和位置識別兩個部分。80C196將根據(jù)接收到的鼠標信息不斷刷新鼠標信息緩沖區(qū)。由于鼠標事件間隔不確定,采用掃描方式不但會浪費CPU時間,還可能因來不及處理而丟失信息。有效的處理方法是采用中斷方式接收,應用模塊通過軟件接口獲得鼠標信息。完整的鼠標接口程序流程圖如圖2所示。在初始化階段,首先檢查鼠標是否存在,根據(jù)結果設置標志位,以備以后取鼠標信息時判斷用;根據(jù)需要設定鼠標初始位置、按鈕原始狀態(tài);最后設置串行接口參數(shù)(幀格式等)并開放鼠標中斷。鼠標發(fā)送信息時,每三個字節(jié)為一個完整的信息報告。但80C196每接收到一個字節(jié),就產(chǎn)生一次中斷,然后根據(jù)當前字節(jié)是否大于40H確定其性質。若是信息報告的首字節(jié),則還要進一步通過有效性檢驗后保存;若不是首字節(jié),則必須經(jīng)過一系列檢驗后保存起來。收到三個字節(jié)后立即進行命令分析和執(zhí)行。具體處理過程可參看源程序。用戶模塊通過特定接口模塊(圖2(b))獲得鼠標當前位置和按鈕狀態(tài),并可通過進位標志C=0/1判斷鼠標是否安裝。?
?
?
?
??? 下面是圖2、3程序流程圖對應的程序清單。該程序要求80C196單片機的工作頻率為12MHz;如果采用其它工作頻率,通過修改串行口的波特率設置參數(shù)以及延時程序的時間常數(shù)即可。?
;?
; 8098 特殊功能寄存器預定義?
??? R0????????? EQU?? 00H:Word?
??? SBUF??????? EQU?? 07H:Byte?
??? INT_MASK??? EQU?? 08H:Byte?
??? INT_PEND??? EQU?? 09H:Byte?
??? BAUD_RT ??? EQU?? 0EH:Byte?
??? IOP2??????????? EQU?? 10H:Byte?
??? SP_CON????? EQU?? 11H:Byte?
??? SP_STAT???? EQU?? 11H:Byte?
??? IOC1??????? EQU?? 16H:Byte?
??? SP????????? EQU?? 18H:Word?
??? ;?
??? ; 通用寄存器預定義?
??? RSEG??? AT???? 1CH?
??????? AX:???? DSW??? 1?
??????? DX:???? DSW??? 1?
??????? AL????? EQU??? AX:BYTE?
??????? AH????? EQU??? (AX+1):BYTE?
??????? DL????? EQU??? DX:BYTE?
??????? DH????? EQU??? (DX+1):BYTE?
??????? SCRNW?? EQU??? 640? ;顯示屏寬度?
??????? SCRNH?? EQU??? 480? ;顯示屏高度?
;?
; 變量區(qū)?
RSEG??? AT????? 20H?
??????? M_X :? DSW??? 1??????? ;光標X值?
??????? M_Y? :? DSW??? 1??????? ;光標Y值?
??????? M_BUF:? DSB??? 4??????? ;接收緩沖區(qū)?
??????? M_P? :? DSW??? 1??????? ;接收指針?
??????? BX?? :? DSW??? 1?
??????? LRB_OK: DSB??? 1??????? ;鼠標狀態(tài),?
;Bit7: 存在, Bit5: 左鍵, Bit4: 右鍵?
;?
CSEG??? AT????? 2000H?
??????? DCW???? INIT?
CSEG??? AT????? 200CH?
??????? DCW???? SIOINT?
??????? DCW???? INIT?
??????? DCW???? 0?
??????? DCB???? 0, 0, 0, 0, 0, 0?
??????? DCB???? 08DH?
??????? DCB???? 000H?
??????? DCB???? 027H, 0FEH?
;?
CSEG??? AT????? 2080H?
INIT:?? LD????? SP, #0100H???? ;設堆棧指針?
??????? LD????? M_X, #SCRNW/2? ;初始化指針?
??????? LD????? M_Y, #SCRNH/2?
??????? ANDB??? LRB_OK, #7CH?
??????? LD????? M_P, #M_BUF?
??????? CLRB??? INT_PEND??????? ;清除中斷?
??????? LDB???? INT_MASK, #40H ;開串行中斷?
??????? LDB???? AL, SP_STAT??????? ;清除RI/TI?
??????? LDB???? SP_CON, #09H?? ;設串口模式?
??????? LDB???? BAUD_RT, #9BH? ;1200,12MHz?
??????? LDB???? BAUD_RT, #80H?
??????? EI?
??????? ANDB??? IOP2, #0FEH??????? ;P2.0=0?
??????? LD????? AX, #8000H???? ;延遲200ms?
DLY0:?? DEC???? AX?
??????? JNE???? DLY0?
??????? LDB???? AL, LRB_OK?
??????? JBS???? AL,7, M_OK?
??????? ANDB??? INT_MASK, #0BFH?
M_OK:NOP?
;? ... ... ...?
;?
;清單二:取鼠標信息, ?
??????? AL=鼠標及按鈕狀態(tài), BX=X, DX=Y?
GET_M:ANDB? INT_MASK, #0BFH ?
??????? LDB???? AL, LRB_OK???? ;取鼠標信息?
??????? LD????? BX, M_X?
??????? LD????? DX, M_Y?
??????? ORB???? INT_MASK, #40H?
??????? RET?
;?
;清單三:串口中斷服務程序?
SIOINT: PUSHF?????????????? ;中斷服務?
??????? PUSH??? AX?
??????? LDB???? AL, SBUF?
??????? LDB???? AH, SP_STAT?
??????? JBS???? AL, 6, ISB0?????? ;第一個字節(jié)?
??????? CMP???? M_P, #M_BUF?
??????? JNE???? SIO_1?
??????? SJMP??? C99???????????? ;緩沖區(qū)空,出錯?
SIO_1:CMP?? M_P, #M_BUF+2?
??????? JH????? C98???????????? ;緩沖區(qū)滿,出錯?
??????? STB???? AL, [M_P]+???? ;存儲收到字節(jié)?
??????? CMP???? M_P, #M_BUF+3?
??????? JNE???? C99?
??????? LD????? M_P, #M_BUF??? ;已收到完整命令?
GOLR:LDB??? AL, 1[M_P]???? ;處理X方向位移?
??????? SHLB??? AL, #2?
??????? EXTB??? AL?
??????? SHRA??? AX, #2?
??????? ADD???? M_X, AX?
CKL:??? CMP???? M_X, #0?
??????? JGE???? CKR?
??????? CLR???? M_X?
CKR:??? CMP???? M_X, #SCRNW?
??????? JLT???? GOUD?
??????? LD????? M_X, #SCRNW?
GOUD:?? LDB??? ?AL, 2[M_P] ;處理Y方向位移?
??????? SHLB??? AL, #2?
??????? EXTB??? AL?
??????? SHRA??? AX, #2?
??????? ADD???? M_Y, AX?
CKU:??? CMP???? M_Y, #0?
??????? JGE???? CKD?
??????? CLR???? M_Y?
CKD:??? CMP???? M_Y, #SCRNH?
??????? JLT???? ELRUD?
??????? LD????? M_Y, #SCRNH?
ELRUD:? SJMP?? ?C98?
ISB0:?? STB???? AL, M_BUF?
??????? ANDB??? AL, #0FH?
??????? CMPB??? AL, #03H?
??????? JE????? C97???????????? ;=X3H,?
??????? CMPB??? AL, #0CH?
??????? JE????? C97???????????? ;=XCH?
??????? CMPB??? AL, #0DH?
??????? JNE???? C98???????????? ;<>XDH?
??????? ORB???? LRB_OK, #80H?? ;確認鼠標正常?
C97:??? ANDB??? AL, M_BUF, #30H?
??????? ANDB??? LRB_OK, #80H?
??????? ORB???? LRB_OK, AL???? ;更新左右鍵狀態(tài)?
??????? LD????? M_P, #M_BUF+1?
??????? SJMP??????? C99?
C98:??? LD????? M_P, #0000H?
C99:??? POP???? AX?
??????? POPF?
??????? RET?
;?
??????? END?
參考文獻?
1 INTEL. 8XC196Kx,8XC196Jx,87C196CA Micro-controller?Family User's Manual,?
2 徐君毅,張友德.單片微型計算機原理及應用.上海:上??茖W技術出版社,1989?
3 孫涵芳,徐愛卿.MCS51-96系列單片機原理及應用.北京:北京航空學院出版社,1988?
4 MAXIM.新產(chǎn)品數(shù)據(jù)手冊,第四卷.1995