




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、教育資源分享有關(guān)Java串口通信簡介有關(guān)Java串口通信簡介,嵌入式系統(tǒng)或傳感器網(wǎng)絡(luò)的很多應(yīng)用和測試都需要通過PC機與嵌入式設(shè)備或傳感器節(jié)點進行通信。其中,最常用的接口就是RS-232串口和并口(鑒于USB接口的復(fù)雜性以及不需要很大的數(shù)據(jù)傳輸量,USB接口用在這里還是顯得過于奢侈,況且目前除了SUN有一個支持USB的包之外,我還沒有看到其他直接支持USB的Java類庫)。SUN的CommAPI分別提供了對常用的RS232串行端口和IEEE1284并行端口通訊的支持。RS-232-C(又稱EIA RS-232-C,以下簡稱RS232)是在1970年由美國電子工業(yè)協(xié)會(EIA)聯(lián)合貝爾系統(tǒng)、調(diào)制解
2、調(diào)器廠家及計算機終端生產(chǎn)廠家共同制定的用于串行通訊的標準。RS232是一個全雙工的通訊協(xié)議,它可以同時進行數(shù)據(jù)接收和發(fā)送的工作。 1 常見的Java串口包目前,常見的Java串口包有SUN在1998年發(fā)布的串口通信API:comm2.0.jar(Windows下)、comm3.0.jar(Linux/Solaris);IBM的串口通信API以及一個開源的實現(xiàn)。鑒于在Windows下SUN的API比較常用以及IBM的實現(xiàn)和SUN的在API層面都是一樣的,那個開源的實現(xiàn)又不像兩家大廠的產(chǎn)品那樣讓人放心,這里就只介紹SUN的串口通信API在Windows平臺下的使用。串口包的安裝(Windows下)
3、到SUN的網(wǎng)站下載javacomm20-win32.zip,包含的東西如下所示:按照其使用說明(Readme.html)的說法,要想使用串口包進行串口通信,除了設(shè)置好環(huán)境變量之外,還要將win32com.dll復(fù)制到bin目錄下;將comm.jar復(fù)制到lib;把perties也同樣拷貝到lib 目錄下。然而在真正運行使用串口包的時候,僅作這些是不夠的。因為通常當運行“java MyApp”的時候,是由JRE下的虛擬機啟動MyApp的。而我們只復(fù)制上述文件到JDK相應(yīng)目錄下,所以應(yīng)用程序?qū)崾菊也坏酱凇=鉀Q這個問題的方法很簡單,我們只須將上面提到的文件放到JRE相應(yīng)的目錄下就可以
4、了。值得注意的是,在網(wǎng)絡(luò)應(yīng)用程序中使用串口API的時候,還會遇到其他更復(fù)雜問題。有興趣的話,你可以查看CSDN社區(qū)中“關(guān)于網(wǎng)頁上Applet用javacomm20讀取客戶端串口的問題”的帖子。2 串口API概覽2.1 m.CommPort這是用于描述一個被底層系統(tǒng)支持的端口的抽象類。它包含一些高層的IO控制方法,這些方法對于所有不同的通訊端口來說是通用的。 SerialPort 和ParallelPort都是它的子類,前者用于控制串行端口而后者用于控這并口,二者對于各自底層的物理端口都有不同的控制方法。這里我們只關(guān)心 SerialPort。2.2 m.CommPortIdentifier這個類
5、主要用于對串口進行管理和設(shè)置,是對串口進行訪問控制的核心類。主要包括以下方法確定是否有可用的通信端口為IO操作打開通信端口決定端口的所有權(quán)處理端口所有權(quán)的爭用管理端口所有權(quán)變化引發(fā)的事件(Event)2.3 m.SerialPort這個類用于描述一個RS-232串行通信端口的底層接口,它定義了串口通信所需的最小功能集。通過它,用戶可以直接對串口進行讀、寫及設(shè)置工作。2.4 串口API實例大段的文字怎么也不如一個小例子來的清晰,下面我們就一起看一下串口包自帶的例子-SerialDemo中的一小段代碼來加深對串口API核心類的使用方法的認識。2.4.1 列舉出本機所有可用串口void listPo
6、rtChoices() CommPortIdentifier portId;Enumeration en = CommPortIdentifier.getPortIdentifiers();/ iterate through the ports.while (en.hasMoreElements() portId = (CommPortIdentifier) en.nextElement();if (portId.getPortType() = CommPortIdentifier.PORT_SERIAL) System.out.println(portId.getName();portCho
7、ice.select(parameters.getPortName();以上代碼可以列舉出當前系統(tǒng)所有可用的串口名稱,我的機器上輸出的結(jié)果是COM1和COM3。2.4.2 串口參數(shù)的配置串口一般有如下參數(shù)可以在該串口打開以前配置進行配置:包括波特率,輸入/輸出流控制,數(shù)據(jù)位數(shù),停止位和齊偶校驗。SerialPort sPort;try sPort.setSerialPortParams(BaudRate,Databits,Stopbits,Parity);/設(shè)置輸入/輸出控制流sPort.setFlowControlMode(FlowControlIn | FlowControlOut); c
8、atch (UnsupportedCommOperationException e) 2.4.3 串口的讀寫對串口讀寫之前需要先打開一個串口:CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(PortName);try SerialPort sPort = (SerialPort) portId.open("串口所有者名稱", 超時等待時間); catch (PortInUseException e) /如果端口被占用就拋出這個異常throw new SerialConnectionExcept
9、ion(e.getMessage();/用于對串口寫數(shù)據(jù)OutputStream os = new BufferedOutputStream(sPort.getOutputStream();os.write(int data);/用于從串口讀數(shù)據(jù)InputStream is = new BufferedInputStream(sPort.getInputStream();int receivedData = is.read();讀出來的是int型,你可以把它轉(zhuǎn)換成需要的其他類型。這里要注意的是,由于Java語言沒有無符號類型,即所有的類型都是帶符號的,在由byte到int的時候應(yīng)該尤其注意。因
10、為如果byte的最高位是1,則轉(zhuǎn)成int類型時將用1來占位。這樣,原本是10000000的byte類型的數(shù)變成int型就成了1111111110000000,這是很嚴重的問題,應(yīng)該注意避免。3 串口通信的通用模式及其問題終于嘮叨完我最討厭的基礎(chǔ)知識了,下面開始我們本次的重點-串口應(yīng)用的研究。由于向串口寫數(shù)據(jù)很簡單,所以這里我們只關(guān)注于從串口讀數(shù)據(jù)的情況。通常,串口通信應(yīng)用程序有兩種模式,一種是實現(xiàn)SerialPortEventListener接口,監(jiān)聽各種串口事件并作相應(yīng)處理;另一種就是建立一個獨立的接收線程專門負責數(shù)據(jù)的接收。由于這兩種方法在某些情況下存在很嚴重的問題(至于什么問題這里先賣個
11、關(guān)子J),所以我的實現(xiàn)是采用第三種方法來解決這個問題。3.1 事件監(jiān)聽模型現(xiàn)在我們來看看事件監(jiān)聽模型是如何運作的:首先需要在你的端口控制類(例如SManager)加上“implements SerialPortEventListener”在初始化時加入如下代碼:try SerialPort sPort.addEventListener(SManager); catch (TooManyListenersException e) sPort.close();throw new SerialConnectionException("too many listeners added&quo
12、t;);sPort.notifyOnDataAvailable(true);覆寫public void serialEvent(SerialPortEvent e)方法,在其中對如下事件進行判斷:BI -通訊中斷.CD -載波檢測.CTS -清除發(fā)送.DATA_AVAILABLE -有數(shù)據(jù)到達.DSR -數(shù)據(jù)設(shè)備準備好.FE -幀錯誤.OE -溢位錯誤.OUTPUT_BUFFER_EMPTY -輸出緩沖區(qū)已清空.PE -奇偶校驗錯.RI -振鈴指示.一般最常用的就是DATA_AVAILABLE-串口有數(shù)據(jù)到達事件。也就是說當串口有數(shù)據(jù)到達時,你可以在serialEvent中接收并處理所收到的數(shù)
13、據(jù)。然而在我的實踐中,遇到了一個十分嚴重的問題。首先描述一下我的實驗:我的應(yīng)用程序需要接收傳感器節(jié)點從串口發(fā)回的查詢數(shù)據(jù),并將結(jié)果以圖標的形式顯示出來。串口設(shè)定的波特率是 115200,川口每隔128毫秒返回一組數(shù)據(jù)(大約是30字節(jié)左右),周期(即持續(xù)時間)為31秒。實測的時候在一個周期內(nèi)應(yīng)該返回4900多個字節(jié),而用事件監(jiān)聽模型我最多只能收到不到1500字節(jié),不知道這些字節(jié)都跑哪里去了,也不清楚到底丟失的是那部分數(shù)據(jù)。值得注意的是,這是我將 serialEvent()中所有處理代碼都注掉,只剩下打印代碼所得的結(jié)果。數(shù)據(jù)丟失的如此嚴重是我所不能忍受的,于是我決定采用其他方法。3.2 串口讀數(shù)據(jù)
14、的線程模型這個模型顧名思義,就是將接收數(shù)據(jù)的操作寫成一個線程的形式:public void startReadingDataThread() Thread readDataProcess = new Thread(new Runnable() public void run() while (newData != -1) try newData = is.read();System.out.println(newData);/其他的處理過程. catch (IOException ex) System.err.println(ex);return;readDataProcess.start()
15、;在我的應(yīng)用程序中,我將收到的數(shù)據(jù)打包放到一個緩存中,然后啟動另一個線程從緩存中獲取并處理數(shù)據(jù)。兩個線程以生產(chǎn)者消費者模式協(xié)同工作,數(shù)據(jù)的流向如下圖所示:這樣,我就圓滿解決了丟數(shù)據(jù)問題。然而,沒高興多久我就又發(fā)現(xiàn)了一個同樣嚴重的問題:雖然這回不再丟數(shù)據(jù)了,可是原本一個周期(31秒)之后,傳感器節(jié)電已經(jīng)停止傳送數(shù)據(jù)了,但我的串口線程依然在努力的執(zhí)行讀串口操作,在控制臺也可以看見收到的數(shù)據(jù)仍在不斷的打印。原來,由于傳感器節(jié)點發(fā)送的數(shù)據(jù)過快,而我的接收線程處理不過來,所以InputStream就先把已到達卻還沒處理的字節(jié)緩存起來,于是就導(dǎo)致了明明傳感器節(jié)點已經(jīng)不再發(fā)數(shù)據(jù)了,而控制臺卻還能看見數(shù)據(jù)不斷
16、打印這一奇怪的現(xiàn)象。唯一值得慶幸的是最后收到數(shù)據(jù)確實是4900左右字節(jié),沒出現(xiàn)丟失現(xiàn)象。然而當處理完最后一個數(shù)據(jù)的時候已經(jīng)快1分半鐘了,這個時間遠遠大于節(jié)點運行周期。這一延遲對于一個實時的顯示系統(tǒng)來說簡直是災(zāi)難!后來我想,是不是由于兩個線程之間的同步和通信導(dǎo)致了數(shù)據(jù)接收緩慢呢?于是我在接收線程的代碼中去掉了所有處理代碼,僅保留打印收到數(shù)據(jù)的語句,結(jié)果依然如故。看來并不是線程間的通信阻礙了數(shù)據(jù)的接收速度,而是用線程模型導(dǎo)致了對于發(fā)送端數(shù)據(jù)發(fā)送速率過快的情況下的數(shù)據(jù)接收延遲。這里申明一點,就是對于數(shù)據(jù)發(fā)送速率不是如此快的情況下前面者兩種模型應(yīng)該還是好用的,只是特殊情況還是應(yīng)該特殊處理。3.3 第三
17、種方法痛苦了許久(Boss天天催我L)之后,偶然的機會,我聽說TinyOS中(又是開源的)有一部分是和我的應(yīng)用程序類似的串口通信部分,于是我下載了它的1.x版的Java代碼部分,參考了它的處理方法。解決問題的方法說穿了其實很簡單,就是從根源入手。根源不就是接收線程導(dǎo)致的嗎,那好,我就干脆取消接收線程和作為中介的共享緩存,而直接在處理線程中調(diào)用串口讀數(shù)據(jù)的方法來解決問題(什么,為什么不把處理線程也一并取消?-都取消應(yīng)用程序界面不就鎖死了嗎?所以必須保留)于是程序變成了這樣:public byte getPack()while (true) / PacketLength為數(shù)據(jù)包長度byte msg
18、Pack = new bytePacketLength;for(int i = 0; i < PacketLength; i+)if( (newData = is.read() != -1)msgPacki = (byte) newData;System.out.println(msgPacki);return msgPack;在處理線程中調(diào)用這個方法返回所需要的數(shù)據(jù)序列并處理之,這樣不但沒有丟失數(shù)據(jù)的現(xiàn)象行出現(xiàn),也沒有數(shù)據(jù)接收延遲了。這里唯一需要注意的就是當串口停止發(fā)送數(shù)據(jù)或沒有數(shù)據(jù)的時候is.read()一直都返回-1,如果一旦在開始接收數(shù)據(jù)的時候發(fā)現(xiàn)-1就不要理它,繼續(xù)接收,直到收到真正的數(shù)據(jù)為止。4 結(jié)束語本文介紹了串口通信的基本知識,以及常用的幾種模式。通過實踐,提出了一些問題,并在最后加以解決。值得注意的是對于第一種方法,我曾將傳感器發(fā)送的時間由128毫
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 園區(qū)商家安全管理制度
- 員工外出學習管理制度
- 多人活動安全管理制度
- 售后配件發(fā)貨管理制度
- 城市配送倉庫管理制度
- 兼職私人教練管理制度
- 完善單位各項管理制度
- 醫(yī)院安保日常管理制度
- 學校病例隨訪管理制度
- 大型凈水設(shè)備管理制度
- (完整版)小學生心理健康教育課件
- (完整版)中國古代書法史課件
- 中醫(yī)適宜技術(shù)操作評分標準
- 二年級道德與法治下冊 (做個“開心果”)教學課件
- 六年級說明文閱讀復(fù)習課件
- 學校食堂食品安全總監(jiān)職責
- 鋼管出廠合格證
- 四川省廣元市2022-2023學年六年級下學期小升初招生數(shù)學試卷含答案
- 2022年正陽縣中小學教師招聘考試真題
- 醫(yī)院醫(yī)務(wù)科科長崗位競聘答辯PPT課件(帶內(nèi)容)
- 人類的起源和進化詳解演示文稿
評論
0/150
提交評論