1、環境配置
java串口通訊需要依賴兩個dll文件 rxtxParallel.dll、rxtxSerial.dll,以及第三方sdk(RXTXcomm.jar);
博客園下載:https://files-cdn.cnblogs.com/files/blogs/666773/rxtx-win-x64.rar
官網下載:http://fizzed.com/oss/rxtx-for-java
兩個dll文件需要粘貼到jdk安裝目錄下 jdk/jre/bin/
當前第三方sdk也可通過pom.xml引入
<dependency> <groupId>org.rxtx</groupId> <artifactId>rxtx</artifactId> <version>2.1.7</version> </dependency>
java:java1.8
<properties> <java.version>1.8</java.version> </properties>
springboot:2.5.6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
pom.xml如下所示:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.rxtx/rxtx --> <!-- java操作串口需要的jar --> <dependency> <groupId>org.rxtx</groupId> <artifactId>rxtx</artifactId> <version>2.1.7</version> </dependency> <!-- swagger --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> </dependencies>
SerialPortManager.java
import gnu.io.*; import lombok.extern.slf4j.Slf4j; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.TooManyListenersException; @Slf4j public class SerialPortManager { //查找所有可用端口 public static ArrayList<String> findPorts() { // 獲得當前所有可用串口 Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers(); ArrayList<String> portNameList = new ArrayList<String>(); // 將可用串口名添加到List並返回該List while (portList.hasMoreElements()) { String portName = portList.nextElement().getName(); portNameList.add(portName); } return portNameList; } /** * 打開串口 * * @param portName 端口名稱 * @param baudRate 波特率 * @return 串口對象 * @throws PortInUseException 串口已被占用 */ public static SerialPort openPort(String portName, int baudRate) throws PortInUseException { try { // 通過端口名識別端口 CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); // 打開端口,並給端口名字和一個timeout(打開操作的超時時間) CommPort commPort = portIdentifier.open(portName, 2000); // 判斷是不是串口 if (commPort instanceof SerialPort) { SerialPort serialPort = (SerialPort) commPort; try { // 設置一下串口的波特率等參數 // 數據位:8 // 停止位:1 // 校驗位:None serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) { e.printStackTrace(); } return serialPort; } } catch (NoSuchPortException e1) { e1.printStackTrace(); } return null; } /** * 關閉串口 * @param serialPort 待關閉的串口對象 */ public static void closePort(SerialPort serialPort) { if (serialPort != null) { serialPort.close(); } } /** * 往串口發送數據 * @param serialPort 串口對象 * @param content 待發送數據 */ public static void sendToPort(SerialPort serialPort, byte[] content) { OutputStream out = null; try { out = serialPort.getOutputStream(); out.write(content); out.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (out != null) { out.close(); out = null; } } catch (IOException e) { e.printStackTrace(); } } } /** * 從串口讀取數據 * @param serialPort 當前已建立連接的SerialPort對象 * @return 讀取到的數據 */ public static byte[] readFromPort(SerialPort serialPort) { InputStream in = null; byte[] bytes = {}; try { in = serialPort.getInputStream(); // 緩沖區大小為一個字節 byte[] readBuffer = new byte[1]; int bytesNum = in.read(readBuffer); while (bytesNum > 0) { bytes = AgreementUtil.concat(bytes, readBuffer); bytesNum = in.read(readBuffer); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (in != null) { in.close(); in = null; } } catch (IOException e) { e.printStackTrace(); } } return bytes; } /** * 添加監聽器 * @param serialPort 串口對象 * @param listener 串口存在有效數據監聽 */ public static void addListener(SerialPort serialPort, DataAvailableListener listener) { try { // 給串口添加監聽器 serialPort.addEventListener(new SerialPortListener(listener)); // 設置當有數據到達時喚醒監聽接收線程 serialPort.notifyOnDataAvailable(true); // 設置當通信中斷時喚醒中斷線程 serialPort.notifyOnBreakInterrupt(true); } catch (TooManyListenersException e) { e.printStackTrace(); } } /** * 串口監聽 */ public static class SerialPortListener implements SerialPortEventListener { private DataAvailableListener mDataAvailableListener; public SerialPortListener(DataAvailableListener mDataAvailableListener) { this.mDataAvailableListener = mDataAvailableListener; } public void serialEvent(SerialPortEvent serialPortEvent) { switch (serialPortEvent.getEventType()) { case SerialPortEvent.DATA_AVAILABLE: // 1.串口存在有效數據 if (mDataAvailableListener != null) { mDataAvailableListener.dataAvailable(); } break; case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2.輸出緩沖區已清空 break; case SerialPortEvent.CTS: // 3.清除待發送數據 break; case SerialPortEvent.DSR: // 4.待發送數據准備好了 break; case SerialPortEvent.RI: // 5.振鈴指示 break; case SerialPortEvent.CD: // 6.載波檢測 break; case SerialPortEvent.OE: // 7.溢位(溢出)錯誤 break; case SerialPortEvent.PE: // 8.奇偶校驗錯誤 break; case SerialPortEvent.FE: // 9.幀錯誤 break; case SerialPortEvent.BI: // 10.通訊中斷 log.error("與串口設備通訊中斷"); break; default: break; } } } /** * 串口存在有效數據監聽 */ public interface DataAvailableListener { /** * 串口存在有效數據 */ void dataAvailable(); } }
調用示例
/** * @throws PortInUseException 串口已經被占用 */ public static void main(String[] args) throws PortInUseException { //獲取可用串口列表 ArrayList<String> ports = SerialPortManager.findPorts(); //當前使用第一個串口,通常串口名稱由用戶自行控制 String portName = ports.get(0); //波特率,當前使用115200 int baudRate = 115200; //打開串口,返回一個串口對象 SerialPort serialPort = SerialPortManager.openPort(portName, baudRate); //給當前串口對象設置監聽器 SerialPortManager.addListener(serialPort, new SerialPortManager.DataAvailableListener() { @Override public void dataAvailable() { //當前監聽器監聽到的串口返回數據 back byte[] back = SerialPortManager.readFromPort(serialPort); //數據監聽完之后,關閉串口 SerialPortManager.closePort(serialPort); } }); //當前向串口發送的數據(模擬假數據) byte[] content = new byte[10]; //向當前串口發送數據 SerialPortManager.sendToPort(serialPort,content); }
參考:https://blog.csdn.net/kong_gu_you_lan/article/details/80589859#commentBox