版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、.如何用 Java 語言向串口讀寫數(shù)據(jù)串口 , RS-232-C(又稱 EIA RS-232-C ,以下簡稱 RS232)是在 1970年由美國電子工業(yè)協(xié)會(EIA) 聯(lián)合貝爾系統(tǒng)、調(diào)制解調(diào)器廠家及計算機終端生產(chǎn)廠家共同制定的用于串行通訊的標(biāo)準。RS232 是一個全雙工的通訊協(xié)議,它可以同時進行數(shù)據(jù)接收和發(fā)送的工作。串口是計算機上一種非常通用設(shè)備通信的協(xié)議。以前,大多數(shù)計算機包含兩個基于 RS232 的串口。串口同時也是儀器儀表設(shè)備通用的通信協(xié)議;很多 GPIB 兼容的設(shè)備也帶有RS-232 口。同時,串口通信協(xié)議也可以用于獲取遠程采集的數(shù)據(jù)。串口通信的概念非常簡單,串口 按位 (bit) 發(fā)
2、送和接收字節(jié) 。盡管比按字節(jié) (byte)的并行通信慢,但是串口可以在使用一根線發(fā)送數(shù)據(jù)的同時用另一根線接收數(shù)據(jù)。 它很簡單并且能夠?qū)崿F(xiàn)遠距離通信。比如 IEEE488 定義并行通行狀態(tài)時, 規(guī)定設(shè)備線總常不得超過 20 米,并且任意兩個設(shè)備間的長度不得超過 2 米;而對于串口而言,長度可達1200 米。說到串口,也許很多人都要懷疑,這都什么年代了,USB設(shè)備已經(jīng)如此普及了, 誰還能想起這個老掉牙的通信端口呀?其實,在現(xiàn)實生活中,串口正因為它老,才會在實際使用中經(jīng)常用到它。舉個簡單的例子: 工業(yè)制造及其設(shè)備與計算機之間的通訊、還有在各種電子工廠測試設(shè)備的過程中,都無一例外使用的串口。因為它可以
3、不用像 USB 設(shè)備一樣必須有軟件驅(qū)動的支持才可以進行工作。.Java對串口通信的支持常見的 Java串口包SUN 的 CommAPI 分別提供了對常用的 RS232 串行端口和 IEEE1284 并行端口通訊的支持。 目前,常見的 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)又不像兩家大廠的
4、產(chǎn)品那樣讓人放心, 這里就只介紹SUN 的串口通信 API在 Windows 平臺下的使用。串口包的安裝 (Windows 下)到 SUN 的網(wǎng)站下載 javacomm20-win32.zip ,包含的東西如下所示:.按照其使用說明 (Readme.html)的說法,要想使用串口包進行串口通信, 除了設(shè)置好環(huán)境變量之外, 還要將 win32com.dll 復(fù)制到 bin 目錄下 ;將 comm.jar 復(fù)制到 lib; 把 perties 也同樣拷貝到 lib 目錄下。然而在真正運行使用串口包的時候,僅作這些是不夠的。因為通常當(dāng)運行“ java MyApp ”的時候
5、,是由 JRE 下的虛擬機啟動 MyApp 的。而我們只復(fù)制上述文件到 JDK相應(yīng)目錄下, 所以應(yīng)用程序?qū)崾菊也坏酱凇?解決這個問題的方法很簡單,我們只須將上面提到的文件放到 JRE 相應(yīng)的目錄下就可以了。串口 API 介紹m.CommPort這是用于描述一個被底層系統(tǒng)支持的端口的抽象類。 它包含一些高層的 IO 控制方法,這些方法對于所有不同的通訊端口來說是通用的。 SerialPort 和 ParallelPort 都是它的子類,前者用于控制串行端口而后者用于控這并口,二者對于各自底層的物理端口都有不同的控制方法。這里我們只關(guān)心SerialPort。javax.co
6、mm.CommPortIdentifier.這個類主要用于對串口進行管理和設(shè)置, 是對串口進行訪問控制的核心類。主要包括以下方法確定是否有可用的通信端口為 IO 操作打開通信端口決定端口的所有權(quán)處理端口所有權(quán)的爭用管理端口所有權(quán)變化引發(fā)的事件 (Event) m.SerialPort這個類用于描述一個 RS-232 串行通信端口的底層接口,它定義了串口通信所需的最小功能集。 通過它,用戶可以直接對串口進行讀、寫及設(shè)置工作。串口 API 實例壓縮包中除了api,還包括了幾個小例子,下面我們就一起看.一下串口包自帶的例子-SerialDemo 中的一小段代碼來加深對串口 API
7、核心類的使用方法的認識。列舉出本機所有可用串口void listPortChoices() CommPortIdentifier portId;Enumeration en = CommPortIdentifier.getPortIdentifiers();/ iterate through the ports. while (en.hasMoreElements() portId = (CommPortIdentifier) en.nextElement();if (portId.getPortType() = CommPortIdentifier.PORT_SERIAL) System.o
8、ut.println(portId.getName();.portChoice.select(parameters.getPortName();以上代碼可以列舉出當(dāng)前系統(tǒng)所有可用的串口名稱, 我的機器上輸出的結(jié)果是 COM1 和 COM3 。串口參數(shù)的配置串口一般有如下參數(shù)可以在該串口打開以前配置進行配置:包括波特率,輸入 /輸出流控制,數(shù)據(jù)位數(shù),停止位和奇偶校驗。.SerialPort sPort;try sPort.setSerialPortParams(BaudRate,Databits,Stopbits,Parity);/設(shè)置輸入 /輸出控制流sPort.setFlowControlM
9、ode(FlowControlIn | FlowControlOut); catch (UnsupportedCommOperationException e) 串口的讀寫對串口讀寫之前需要先打開一個串口:CommPortIdentifierportId=CommPortIdentifier.getPortIdentifier(PortName);try SerialPort sPort = (SerialPort) portId.open( 串口所有者名稱 ,.超時等待時間 ); catch (PortInUseException e) / 如果端口被占用就拋出這個異常throw new S
10、erialConnectionException(e.getMessage();/用于對串口寫數(shù)據(jù)OutputStreamos=newBufferedOutputStream(sPort.getOutputStream();os.write(int data);/用于從串口讀數(shù)據(jù)InputStreamis=newBufferedInputStream(sPort.getInputStream();int receivedData = is.read();.讀出來的是 int 型,你可以把它轉(zhuǎn)換成需要的其他類型。這里要注意的是,由于 Java 語言沒有無符號類型,即所有的類型都是帶符號的,在由
11、byte 到 int 的時候應(yīng)該尤其注意。因為如果 byte 的最高位是 1,則轉(zhuǎn)成 int 類型時將用 1 來占位。這樣,原本是 10000000 的 byte 類型的數(shù)變成 int 型就成了1111111110000000,這是很嚴重的問題,應(yīng)該注意避免。串口通信的通用模式及其問題下面開始我們本次的重點-串口應(yīng)用的研究。由于向串口寫數(shù)據(jù)很簡單,所以這里我們只關(guān)注于從串口讀數(shù)據(jù)的情況。通常,串 口 通 信 應(yīng) 用 程 序 有 兩 種 模 式 , 一 種 是 實 現(xiàn)SerialPortEventListener 接口,監(jiān)聽各種串口事件并作相應(yīng)處理;另一種就是建立一個獨立的接收線程專門負責(zé)數(shù)據(jù)的
12、接收。 由于這兩種方法在某些情況下存在很嚴重的問題, 所以我的實現(xiàn)是采用第三種方法來解決這個問題。事件監(jiān)聽模型現(xiàn)在我們來看看事件監(jiān)聽模型是如何運作的:.首 先 需 要 在 你 的 端 口 控 制 類 ( 例 如SManager) 加 上“implements SerialPortEventListener”在初始化時加入如下代碼:try SerialPort sPort.addEventListener(SManager); catch (TooManyListenersException e) sPort.close();throw new SerialConnectionException
13、(too many listeners added);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_A VAILABLE- 串口有數(shù)據(jù)到達事件。
14、也就是說當(dāng)串口有數(shù)據(jù)到達時, 你可以在 serialEvent 中接收并處理所收到的數(shù)據(jù)。 然而在我的實踐中, 遇到了一個十分嚴重的問題。首先描述一下我的實驗: 我的應(yīng)用程序需要接收傳感器節(jié)點從串口發(fā)回的查詢數(shù)據(jù), 并將結(jié)果以圖標(biāo)的形式顯示出來。 串口設(shè)定的波特率是 115200,串口每隔 128 毫秒返回一組數(shù)據(jù) (大約是 30 字節(jié)左右 ),周期 (即持續(xù)時間 )為 31 秒。實測的時候在一個周期內(nèi)應(yīng)該返回 4900 多個字節(jié),而用事件監(jiān)聽模型我最多只能收到不到 1500 字節(jié),不知道這些字節(jié)都跑哪里去了,也不清楚到底丟失的是那部分數(shù)據(jù)。 值得注意的是, 這是我將 serialEvent(
15、) 中所有處理代碼都注掉, 只剩下打印代碼所得的結(jié)果。 數(shù)據(jù)丟失的如此嚴重是我所不能忍受的,于是我決定采用其他方法。串口讀數(shù)據(jù)的線程模型這個模型顧名思義, 就是將接收數(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 (IO
16、Exception ex) System.err.println(ex); return;.readDataProcess.start();在我的應(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ù)過快,而我的接收線程處
17、理不過來,所以 InputStream 就先把已到達卻還沒處理的字節(jié)緩存起來, 于是就導(dǎo)致了明明傳感器節(jié)點已經(jīng)不再發(fā)數(shù)據(jù)了, 而控制臺卻還能看見數(shù)據(jù)不斷打印這一奇怪.的現(xiàn)象。唯一值得慶幸的是最后收到數(shù)據(jù)確實是4900 左右字節(jié),沒出現(xiàn)丟失現(xiàn)象。 然而當(dāng)處理完最后一個數(shù)據(jù)的時候已經(jīng)快 1 分半鐘了,這個時間遠遠大于節(jié)點運行周期。 這一延遲對于一個實時的顯示系統(tǒng)來說簡直是災(zāi)難 !后來我想,是不是由于兩個線程之間的同步和通信導(dǎo)致了數(shù)據(jù)接收緩慢呢?于是我在接收線程的代碼中去掉了所有處理代碼,僅保留打印收到數(shù)據(jù)的語句,結(jié)果依然如故。看來并不是線程間的通信阻礙了數(shù)據(jù)的接收速度, 而是用線程模型導(dǎo)致了對于發(fā)
18、送端數(shù)據(jù)發(fā)送速率過快的情況下的數(shù)據(jù)接收延遲。 這里申明一點,就是對于數(shù)據(jù)發(fā)送速率不是如此快的情況下前面者兩種模型應(yīng)該還是好用的,只是特殊情況還是應(yīng)該特殊處理。第三種方法TinyOS 中有一部分是和我的應(yīng)用程序類似的串口通信部分,于是我下載了它的1.x 版的 Java代碼部分, 參考了它的處理方法。解決問題的方法說穿了其實很簡單,就是從根源入手。根源不就是接收線程導(dǎo)致的嗎,那好,我就干脆取消接收線程和作為中介的共享緩存, 而直接在處理線程中調(diào)用串口讀數(shù)據(jù)的方法來解決問題,于是程序變成了這樣:.public byte getPack()while (true) / PacketLength 為數(shù)據(jù)包長度byte msgPack = new bytePacketLength;for(int i = 0; i PacketLength; i+)if( (newData = is.read() != -
溫馨提示
- 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)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 中學(xué)學(xué)生社團活動成果展示制度
- 2025年中職數(shù)據(jù)處理(數(shù)據(jù)統(tǒng)計分析)試題及答案
- 高一地理(查漏補缺)2025-2026年上學(xué)期期中測試卷
- 2025年大學(xué)本科(會計學(xué))稅務(wù)籌劃應(yīng)用階段測試題及答案
- 2025年中職化學(xué)(無機化學(xué)基礎(chǔ))試題及答案
- 2025年高職空中乘務(wù)(客艙服務(wù)規(guī)范)試題及答案
- 2025年大學(xué)第二學(xué)年(口腔醫(yī)學(xué))口腔內(nèi)科學(xué)基礎(chǔ)階段測試試題及答案
- 2025年高職醫(yī)療器械維護與管理(設(shè)備檢修)試題及答案
- 2025年大學(xué)(經(jīng)濟學(xué))國際貿(mào)易學(xué)期末測試題及答案
- 2025年大學(xué)二年級(地質(zhì)工程)地質(zhì)災(zāi)害防治綜合測試題及答案
- DB35T 2136-2023 茶樹病害測報與綠色防控技術(shù)規(guī)程
- 蓋板涵蓋板計算
- 運輸工具服務(wù)企業(yè)備案表
- 醫(yī)院藥房醫(yī)療廢物處置方案
- 天塔之光模擬控制PLC課程設(shè)計
- 金屬眼鏡架拋光等工藝【省一等獎】
- 《藥品經(jīng)營質(zhì)量管理規(guī)范》的五個附錄
- ASMEBPE介紹專題知識
- 八年級上冊地理期末復(fù)習(xí)計劃通用5篇
- 初中日語人教版七年級第一冊單詞表講義
- GB/T 9065.5-2010液壓軟管接頭第5部分:37°擴口端軟管接頭
評論
0/150
提交評論