? ? ? ?給大家分項(xiàng)下用RXTX庫(kù)實(shí)現(xiàn)JAVA串口編程。
一 準(zhǔn)備工作
1.1 下載資源文件
? ? ? ?首先下載RXTX庫(kù)對(duì)應(yīng)的資源文件。下載地址 http://fizzed.com/oss/rxtx-for-java 大家根據(jù)自己的系統(tǒng)下載對(duì)應(yīng)的文件。

- Windows-x64 對(duì)應(yīng)windows 64位系統(tǒng)。
- Windows-x86 對(duì)應(yīng)windows 32位系統(tǒng)。
- Windows-ia64 這種用的比較少,我們不管。
- Linux-x86_64 對(duì)應(yīng)Linux 64位系統(tǒng)。
- Linux-i386 對(duì)應(yīng)Linux 32位系統(tǒng)。
? ? ? ?每個(gè)文件下面都有我們下面需要的所有文件。
1.1 拷貝動(dòng)態(tài)庫(kù)
? ? ? ?RXJX的實(shí)現(xiàn)還需要依賴幾個(gè)動(dòng)態(tài)庫(kù),所以我們要先把動(dòng)態(tài)庫(kù)放到對(duì)應(yīng)的jdk目錄下面去。window和linux拷貝的文件不同,如下所示:
window平臺(tái):
- 拷貝 rxtxSerial.dll —> <JAVA_HOME>\jre\bin
- 拷貝 rxtxParallel.dll —> <JAVA_HOME>\jre\bin
linux平臺(tái):
- 拷貝 librxtxSerial.so —> <JAVA_HOME>/jre/lib/i386/
- 拷貝 librxtxParallel.so —> <JAVA_HOME>/jre/lib/i386/
1.2 項(xiàng)目引入RXTXcomm.jar
? ? ? ?RXTXcomm.jar文件引入到工程代碼里面去。
? ? ? ?比如我們把RXTXcomm.jar文件放到工程目錄下resource/jar目錄下面去。然后在pom.xml中把RXTXcomm.jar引入進(jìn)來(lái)。
<!-- 串口jar -->
<dependency>
<groupId>gnu.io</groupId>
<artifactId>com-lib</artifactId>
<version>2.2</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/jar/RXTXcomm.jar</systemPath>
</dependency>
二 實(shí)現(xiàn)代碼
? ? ? ?前面準(zhǔn)備工作做好了,接下來(lái)就是代碼實(shí)現(xiàn),好多代碼咱們也是從網(wǎng)上copy過(guò)來(lái)的,這里我就直接貼代碼了。
2.1 串口參數(shù)的簡(jiǎn)單封裝
package com.pilot.ioserver.basic.pbl.port.serialPort;
import gnu.io.SerialPort;
/**
* @name: SerialPortParameter
* @author: tuacy.
* @date: 2019/6/26.
* @version: 1.0
* @Description: 串口參數(shù)
*/
public final class SerialPortParameter {
/**
* 串口名稱(COM0、COM1、COM2等等)
*/
private String serialPortName;
/**
* 波特率
* 默認(rèn):115200
*/
private int baudRate;
/**
* 數(shù)據(jù)位 默認(rèn)8位
* 可以設(shè)置的值:SerialPort.DATABITS_5、SerialPort.DATABITS_6、SerialPort.DATABITS_7、SerialPort.DATABITS_8
* 默認(rèn):SerialPort.DATABITS_8
*/
private int dataBits;
/**
* 停止位
* 可以設(shè)置的值:SerialPort.STOPBITS_1、SerialPort.STOPBITS_2、SerialPort.STOPBITS_1_5
* 默認(rèn):SerialPort.STOPBITS_1
*/
private int stopBits;
/**
* 校驗(yàn)位
* 可以設(shè)置的值:SerialPort.PARITY_NONE、SerialPort.PARITY_ODD、SerialPort.PARITY_EVEN、SerialPort.PARITY_MARK、SerialPort.PARITY_SPACE
* 默認(rèn):SerialPort.PARITY_NONE
*/
private int parity;
public SerialPortParameter(String serialPortName) {
this.serialPortName = serialPortName;
this.baudRate = 115200;
this.dataBits = SerialPort.DATABITS_8;
this.stopBits = SerialPort.STOPBITS_1;
this.parity = SerialPort.PARITY_NONE;
}
public SerialPortParameter(String serialPortName, int baudRate) {
this.serialPortName = serialPortName;
this.baudRate = baudRate;
this.dataBits = SerialPort.DATABITS_8;
this.stopBits = SerialPort.STOPBITS_1;
this.parity = SerialPort.PARITY_NONE;
}
public String getSerialPortName() {
return serialPortName;
}
public void setSerialPortName(String serialPortName) {
this.serialPortName = serialPortName;
}
public int getBaudRate() {
return baudRate;
}
public void setBaudRate(int baudRate) {
this.baudRate = baudRate;
}
public int getDataBits() {
return dataBits;
}
public void setDataBits(int dataBits) {
this.dataBits = dataBits;
}
public int getStopBits() {
return stopBits;
}
public void setStopBits(int stopBits) {
this.stopBits = stopBits;
}
public int getParity() {
return parity;
}
public void setParity(int parity) {
this.parity = parity;
}
}
2.2 串口工具類的簡(jiǎn)單封裝
package com.pilot.ioserver.basic.pbl.port.serialPort;
import gnu.io.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.TooManyListenersException;
/**
* @name: SerialPortUtil
* @author: tuacy.
* @date: 2019/6/26.
* @version: 1.0
* @Description: 串口工具類
*/
public class SerialPortUtil {
/**
* 獲得系統(tǒng)可用的端口名稱列表(COM0、COM1、COM2等等)
*
* @return List<String>可用端口名稱列表
*/
@SuppressWarnings("unchecked")
public static List<String> getSerialPortList() {
List<String> systemPorts = new ArrayList<>();
//獲得系統(tǒng)可用的端口
Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
while (portList.hasMoreElements()) {
String portName = portList.nextElement().getName();//獲得端口的名字
systemPorts.add(portName);
}
return systemPorts;
}
/**
* 打開串口
*
* @param serialPortName 串口名稱
* @return SerialPort 串口對(duì)象
* @throws NoSuchPortException 對(duì)應(yīng)串口不存在
* @throws PortInUseException 串口在使用中
* @throws UnsupportedCommOperationException 不支持操作操作
*/
public static SerialPort openSerialPort(String serialPortName)
throws NoSuchPortException, PortInUseException, UnsupportedCommOperationException {
SerialPortParameter parameter = new SerialPortParameter(serialPortName);
return openSerialPort(parameter);
}
/**
* 打開串口
*
* @param serialPortName 串口名稱
* @param baudRate 波特率
* @return SerialPort 串口對(duì)象
* @throws NoSuchPortException 對(duì)應(yīng)串口不存在
* @throws PortInUseException 串口在使用中
* @throws UnsupportedCommOperationException 不支持操作操作
*/
public static SerialPort openSerialPort(String serialPortName, int baudRate)
throws NoSuchPortException, PortInUseException, UnsupportedCommOperationException {
SerialPortParameter parameter = new SerialPortParameter(serialPortName, baudRate);
return openSerialPort(parameter);
}
/**
* 打開串口
*
* @param serialPortName 串口名稱
* @param baudRate 波特率
* @param timeout 串口打開超時(shí)時(shí)間
* @return SerialPort 串口對(duì)象
* @throws NoSuchPortException 對(duì)應(yīng)串口不存在
* @throws PortInUseException 串口在使用中
* @throws UnsupportedCommOperationException 不支持操作操作
*/
public static SerialPort openSerialPort(String serialPortName, int baudRate, int timeout)
throws NoSuchPortException, PortInUseException, UnsupportedCommOperationException {
SerialPortParameter parameter = new SerialPortParameter(serialPortName, baudRate);
return openSerialPort(parameter, timeout);
}
/**
* 打開串口
*
* @param parameter 串口參數(shù)
* @return SerialPort 串口對(duì)象
* @throws NoSuchPortException 對(duì)應(yīng)串口不存在
* @throws PortInUseException 串口在使用中
* @throws UnsupportedCommOperationException 不支持操作操作
*/
public static SerialPort openSerialPort(SerialPortParameter parameter)
throws NoSuchPortException, PortInUseException, UnsupportedCommOperationException {
return openSerialPort(parameter, 2000);
}
/**
* 打開串口
*
* @param parameter 串口參數(shù)
* @param timeout 串口打開超時(shí)時(shí)間
* @return SerialPort串口對(duì)象
* @throws NoSuchPortException 對(duì)應(yīng)串口不存在
* @throws PortInUseException 串口在使用中
* @throws UnsupportedCommOperationException 不支持操作操作
*/
public static SerialPort openSerialPort(SerialPortParameter parameter, int timeout)
throws NoSuchPortException, PortInUseException, UnsupportedCommOperationException {
//通過(guò)端口名稱得到端口
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(parameter.getSerialPortName());
//打開端口,(自定義名字,打開超時(shí)時(shí)間)
CommPort commPort = portIdentifier.open(parameter.getSerialPortName(), timeout);
//判斷是不是串口
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
//設(shè)置串口參數(shù)(波特率,數(shù)據(jù)位8,停止位1,校驗(yàn)位無(wú))
serialPort.setSerialPortParams(parameter.getBaudRate(), parameter.getDataBits(), parameter.getStopBits(), parameter.getParity());
System.out.println("開啟串口成功,串口名稱:" + parameter.getSerialPortName());
return serialPort;
} else {
//是其他類型的端口
throw new NoSuchPortException();
}
}
/**
* 關(guān)閉串口
*
* @param serialPort 要關(guān)閉的串口對(duì)象
*/
public static void closeSerialPort(SerialPort serialPort) {
if (serialPort != null) {
serialPort.close();
System.out.println("關(guān)閉了串口:" + serialPort.getName());
}
}
/**
* 向串口發(fā)送數(shù)據(jù)
*
* @param serialPort 串口對(duì)象
* @param data 發(fā)送的數(shù)據(jù)
*/
public static void sendData(SerialPort serialPort, byte[] data) {
OutputStream os = null;
try {
//獲得串口的輸出流
os = serialPort.getOutputStream();
os.write(data);
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 從串口讀取數(shù)據(jù)
*
* @param serialPort 要讀取的串口
* @return 讀取的數(shù)據(jù)
*/
public static byte[] readData(SerialPort serialPort) {
InputStream is = null;
byte[] bytes = null;
try {
//獲得串口的輸入流
is = serialPort.getInputStream();
//獲得數(shù)據(jù)長(zhǎng)度
int bufflenth = is.available();
while (bufflenth != 0) {
//初始化byte數(shù)組
bytes = new byte[bufflenth];
is.read(bytes);
bufflenth = is.available();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return bytes;
}
/**
* 給串口設(shè)置監(jiān)聽(tīng)
*
* @param serialPort serialPort 要讀取的串口
* @param listener SerialPortEventListener監(jiān)聽(tīng)對(duì)象
* @throws TooManyListenersException 監(jiān)聽(tīng)對(duì)象太多
*/
public static void setListenerToSerialPort(SerialPort serialPort, SerialPortEventListener listener) throws TooManyListenersException {
//給串口添加事件監(jiān)聽(tīng)
serialPort.addEventListener(listener);
//串口有數(shù)據(jù)監(jiān)聽(tīng)
serialPort.notifyOnDataAvailable(true);
//中斷事件監(jiān)聽(tīng)
serialPort.notifyOnBreakInterrupt(true);
}
}
2.3 測(cè)試類
? ? ? ?我們簡(jiǎn)單的寫一個(gè)單元測(cè)試類
package com.pilot.ioserver.basic.pbl.port.serialPort;
import gnu.io.*;
import org.junit.Test;
import java.util.List;
import java.util.TooManyListenersException;
/**
* @name: SerialPortUtilTest
* @author: tuacy.
* @date: 2019/6/26.
* @version: 1.0
* @Description: 串口測(cè)試代碼
*/
public class SerialPortUtilTest {
/**
* 測(cè)試獲取串口列表
*/
@Test
public void getSystemPortList() {
List<String> portList = SerialPortUtil.getSerialPortList();
System.out.println(portList);
}
/**
* 測(cè)試串口打開,讀,寫操作
*/
@Test
public void serialPortAction() {
try {
final SerialPort serialPort = SerialPortUtil.openSerialPort("COM2", 115200);
//啟動(dòng)一個(gè)線程每2s向串口發(fā)送數(shù)據(jù),發(fā)送1000次hello
new Thread(() -> {
int i = 1;
while (i < 1000) {
String s = "hello";
byte[] bytes = s.getBytes();
SerialPortUtil.sendData(serialPort, bytes);//發(fā)送數(shù)據(jù)
i++;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//設(shè)置串口的listener
SerialPortUtil.setListenerToSerialPort(serialPort, event -> {
//數(shù)據(jù)通知
if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
byte[] bytes = SerialPortUtil.readData(serialPort);
System.out.println("收到的數(shù)據(jù)長(zhǎng)度:" + bytes.length);
System.out.println("收到的數(shù)據(jù):" + new String(bytes));
}
});
try {
// sleep 一段時(shí)間保證線程可以執(zhí)行完
Thread.sleep(3 * 30 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (NoSuchPortException | PortInUseException | UnsupportedCommOperationException | TooManyListenersException e) {
e.printStackTrace();
}
}
}
三 測(cè)試
? ? ? ?代碼寫完了,接下來(lái)就是驗(yàn)證了。我是在window條件下驗(yàn)證測(cè)試的,也在網(wǎng)上找了兩個(gè)工具,一個(gè)模擬串口工具,一個(gè)串口命令工具。為了方便大家我們把這兩個(gè)工具放一起又重新上傳在csdn上了。下載地址 https://download.csdn.net/download/wuyuxing24/11260170
3.1 虛擬串口
? ? ? ? 使用虛擬串口工具,虛擬兩個(gè)串口。比如這里我們虛擬了COM1和COM2出來(lái)。

3.2 運(yùn)行單元測(cè)試代碼
? ? ? ? 運(yùn)行我們上面編寫的測(cè)試代碼(測(cè)試代碼我們連接COM2)。同時(shí)啟動(dòng)串口調(diào)試工具,測(cè)試下串口的收發(fā)。

? ? ? ?這樣我們就用RXTX簡(jiǎn)單的實(shí)現(xiàn)了串口的收發(fā)邏輯。其他更加高級(jí)的用法大家可以去看看RXTX的文檔。