簡(jiǎn)單介紹Java的串口通信(上)
有關(guān)Java串口通信簡(jiǎn)介,嵌入式系統(tǒng)或傳感器網(wǎng)絡(luò)的很多應(yīng)用和測(cè)試都需要通過(guò)PC機(jī)與嵌入式設(shè)備或傳感器節(jié)點(diǎn)進(jìn)行通信。其中,最常用的接口就是RS-232串口和并口(鑒于USB接口的復(fù)雜性以及不需要很大的數(shù)據(jù)傳輸量,USB接口用在這里還是顯得過(guò)于奢侈,況且目前除了SUN有一個(gè)支持USB的包之外,我還沒(méi)有看到其他直接支持USB的Java類庫(kù))。
SUN的CommAPI分別提供了對(duì)常用的RS232串行端口和IEEE1284并行端口通訊的支持。RS-232-C(又稱EIA RS-232-C,以下簡(jiǎn)稱RS232)是在1970年由美國(guó)電子工業(yè)協(xié)會(huì)(EIA)聯(lián)合貝爾系統(tǒng)、調(diào)制解調(diào)器廠家及計(jì)算機(jī)終端生產(chǎn)廠家共同制定的用于串行通訊的標(biāo)準(zhǔn)。RS232是一個(gè)全雙工的通訊協(xié)議,它可以同時(shí)進(jìn)行數(shù)據(jù)接收和發(fā)送的工作。
1 常見(jiàn)的Java串口包
目前,常見(jiàn)的Java串口包有SUN在1998年發(fā)布的串口通信API:comm2.0.jar(Windows下)、comm3.0.jar(Linux/Solaris);IBM的串口通信API以及一個(gè)開(kāi)源的實(shí)現(xiàn)。鑒于在Windows下SUN的API比較常用以及IBM的實(shí)現(xiàn)和SUN的在API層面都是一樣的,那個(gè)開(kāi)源的實(shí)現(xiàn)又不像兩家大廠的產(chǎn)品那樣讓人放心,這里就只介紹SUN的串口通信API在Windows平臺(tái)下的使用。
按照其使用說(shuō)明(Readme.html)的說(shuō)法,要想使用串口包進(jìn)行串口通信,除了設(shè)置好環(huán)境變量之外,還要將win32com.dll復(fù)制到\bin目錄下;將comm.jar復(fù)制到\lib;把javax.comm.properties也同樣拷貝到\lib 目錄下。然而在真正運(yùn)行使用串口包的時(shí)候,僅作這些是不夠的。
因?yàn)橥ǔ.?dāng)運(yùn)行“java MyApp”的時(shí)候,是由JRE下的虛擬機(jī)啟動(dòng)MyApp的。而我們只復(fù)制上述文件到JDK相應(yīng)目錄下,所以應(yīng)用程序?qū)?huì)提示找不到串口。解決這個(gè)問(wèn)題的方法很簡(jiǎn)單,我們只須將上面提到的文件放到JRE相應(yīng)的目錄下就可以了。
值得注意的是,在網(wǎng)絡(luò)應(yīng)用程序中使用串口API的時(shí)候,還會(huì)遇到其他更復(fù)雜問(wèn)題。有興趣的話,你可以查看CSDN社區(qū)中“關(guān)于網(wǎng)頁(yè)上Applet用javacomm20讀取客戶端串口的問(wèn)題”的帖子。
2 串口API概覽
2.1 javax.comm.CommPort
這是用于描述一個(gè)被底層系統(tǒng)支持的端口的抽象類。它包含一些高層的IO控制方法,這些方法對(duì)于所有不同的通訊端口來(lái)說(shuō)是通用的。 SerialPort 和ParallelPort都是它的子類,前者用于控制串行端口而后者用于控這并口,二者對(duì)于各自底層的物理端口都有不同的控制方法。這里我們只關(guān)心 SerialPort。
2.2 javax.comm.CommPortIdentifier
這個(gè)類主要用于對(duì)串口進(jìn)行管理和設(shè)置,是對(duì)串口進(jìn)行訪問(wèn)控制的核心類。主要包括以下方法
- 確定是否有可用的通信端口
- 為IO操作打開(kāi)通信端口
- 決定端口的所有權(quán)
- 處理端口所有權(quán)的爭(zhēng)用
- 管理端口所有權(quán)變化引發(fā)的事件(Event)
2.3 javax.comm.SerialPort
這個(gè)類用于描述一個(gè)RS-232串行通信端口的底層接口,它定義了串口通信所需的最小功能集。通過(guò)它,用戶可以直接對(duì)串口進(jìn)行讀、寫(xiě)及設(shè)置工作。
2.4 串口API實(shí)例
大段的文字怎么也不如一個(gè)小例子來(lái)的清晰,下面我們就一起看一下串口包自帶的例子---SerialDemo中的一小段代碼來(lái)加深對(duì)串口API核心類的使用方法的認(rèn)識(shí)。
2.4.1 列舉出本機(jī)所有可用串口
- 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.out.println(portId.getName());
- }
- }
- portChoice.select(parameters.getPortName());
- }
以上代碼可以列舉出當(dāng)前系統(tǒng)所有可用的串口名稱,我的機(jī)器上輸出的結(jié)果是COM1和COM3。
2.4.2 串口參數(shù)的配置
串口一般有如下參數(shù)可以在該串口打開(kāi)以前配置進(jìn)行配置:包括波特率,輸入/輸出流控制,數(shù)據(jù)位數(shù),停止位和齊偶校驗(yàn)。
- SerialPort sPort;
- try {
- sPort.setSerialPortParams(BaudRate,Databits,Stopbits,Parity);
- //設(shè)置輸入/輸出控制流
- sPort.setFlowControlMode(FlowControlIn | FlowControlOut);
- } catch (UnsupportedCommOperationException e) {}
2.4.3 串口的讀寫(xiě)
對(duì)串口讀寫(xiě)之前需要先打開(kāi)一個(gè)串口:
- CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(PortName);
- try {
- SerialPort sPort = (SerialPort) portId.open("串口所有者名稱", 超時(shí)等待時(shí)間);
- } catch (PortInUseException e) {//如果端口被占用就拋出這個(gè)異常
- throw new SerialConnectionException(e.getMessage());
- }
- //用于對(duì)串口寫(xiě)數(shù)據(jù)
- OutputStream os = new BufferedOutputStream(sPort.getOutputStream());
- os.write(int data);
- //用于從串口讀數(shù)據(jù)
- InputStream is = new BufferedInputStream(sPort.getInputStream());
- int receivedData = is.read();
讀出來(lái)的是int型,你可以把它轉(zhuǎn)換成需要的其他類型。
這里要注意的是,由于Java語(yǔ)言沒(méi)有無(wú)符號(hào)類型,即所有的類型都是帶符號(hào)的,在由byte到int的時(shí)候應(yīng)該尤其注意。因?yàn)槿绻鸼yte的最高位是1,則轉(zhuǎn)成int類型時(shí)將用1來(lái)占位。這樣,原本是10000000的byte類型的數(shù)變成int型就成了1111111110000000,這是很?chē)?yán)重的問(wèn)題,應(yīng)該注意避免。
3 串口通信的通用模式及其問(wèn)題
終于嘮叨完我最討厭的基礎(chǔ)知識(shí)了,下面開(kāi)始我們本次的重點(diǎn)--串口應(yīng)用的研究。由于向串口寫(xiě)數(shù)據(jù)很簡(jiǎn)單,所以這里我們只關(guān)注于從串口讀數(shù)據(jù)的情況。
通常,串口通信應(yīng)用程序有兩種模式,一種是實(shí)現(xiàn)SerialPortEventListener接口,監(jiān)聽(tīng)各種串口事件并作相應(yīng)處理;另一種就是建立一個(gè)獨(dú)立的接收線程專門(mén)負(fù)責(zé)數(shù)據(jù)的接收。由于這兩種方法在某些情況下存在很?chē)?yán)重的問(wèn)題(至于什么問(wèn)題這里先賣(mài)個(gè)關(guān)子J),所以我的實(shí)現(xiàn)是采用第三種方法來(lái)解決這個(gè)問(wèn)題。
由于篇幅過(guò)長(zhǎng)的原因 ,我們分兩篇給大家介紹。請(qǐng)看下一篇>>
【編輯推薦】
- 分享JavaScript的跨域共享的方法
- JAVA基礎(chǔ)之java面向?qū)ο缶幊?/span>
- JavaScript來(lái)實(shí)現(xiàn)的超炫組織結(jié)構(gòu)圖
- 經(jīng)驗(yàn)分享:學(xué)好java開(kāi)發(fā)的關(guān)鍵7步
- 深入解讀JavaScript內(nèi)存回收機(jī)制