参考链接
java串口开发
RXTXcomm与 JSerialComm对比
基本代码
前情提要
JSerialComm
跟 RXTXcomm
开发串口不一样, JSerialComm
在打开串口发送消息接收消息后必须关闭串口, RXTXcomm
开启一次可继续用, JSerialComm
是独立的。
我在测试的时候,非常纳闷我打开串口了啊,怎么再次调用串口是否打开方法返回的是 false
呢,原来只有调用 serialPort.openPort(1000)
方法 ,serialPort.isOpen()
才会返回 true
, 必须调用一次打开一次, 关闭一次。不然下次就无法打开了。
调试工具
代码
导入依赖
这里 <version>[2.0.0,3.0.0)</version>
会默认导入最新的版本
<!--串口开发依赖-->
<dependency>
<groupId>com.fazecast</groupId>
<artifactId>jSerialComm</artifactId>
<version>[2.0.0,3.0.0)</version>
</dependency>
<!--其他工具类依赖 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.26</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.18</version>
</dependency>
工具类集测试
工具类
/**
* 串口存在有效数据监听
*/
public interface DataAvailableListener {
/**
* 串口存在有效数据
*/
void dataAvailable();
}
/**
* 串口监听
*/
@Slf4j
public class SerialPortListener implements SerialPortDataListener {
private final DataAvailableListener mDataAvailableListener;
public SerialPortListener(DataAvailableListener mDataAvailableListener) {
this.mDataAvailableListener = mDataAvailableListener;
}
// //必须是return这个才会开启串口工具的监听
@Override
public int getListeningEvents() {
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
}
/**
* 系列活动
*
* @param serialPortEvent 串口事件
*/
@Override
public void serialEvent(SerialPortEvent serialPortEvent) {
if (mDataAvailableListener != null) {
mDataAvailableListener.dataAvailable();
}
}
}
package com.example.rxtxdemo.rxtx;
import com.fazecast.jSerialComm.SerialPort;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
public class SerialPortManager {
/**
* 查找所有可用端口
*
* @return {@link List}<{@link String}>
*/
public static List<String> findPorts() {
// 获得当前所有可用串口
SerialPort[] serialPorts = SerialPort.getCommPorts();
List<String> portNameList = Lists.newLinkedList();
// 将可用串口名添加到List并返回该List
for (SerialPort serialPort : serialPorts) {
portNameList.add(serialPort.getSystemPortName());
}
//去重
portNameList = portNameList.stream().distinct().collect(Collectors.toList());
return portNameList;
}
/**
* 打开串口
*
* @param portName 端口名称
* @param baudRate 波特率
* @return 串口对象
*/
public static SerialPort openPort(String portName, Integer baudRate) {
SerialPort serialPort = SerialPort.getCommPort(portName);
if (baudRate != null) {
serialPort.setBaudRate(baudRate);
}
//开启串口
if (!serialPort.isOpen()) {
serialPort.openPort(1000);
} else {
return serialPort;
}
// 设置一下串口的波特率等参数
// 数据位:8
// 停止位:1
// 校验位:None
serialPort.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);
if (null != baudRate) {
serialPort.setComPortParameters(baudRate, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
}
serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 1000, 1000);
return serialPort;
}
/**
* 关闭串口
*
* @param serialPort 待关闭的串口对象
*/
public static void closePort(SerialPort serialPort) {
if (serialPort != null && serialPort.isOpen()) {
serialPort.closePort();
}
}
/**
* 往串口发送数据
*
* @param serialPort 串口对象
* @param content 待发送数据
*/
public static void sendToPort(SerialPort serialPort, byte[] content) {
if (!serialPort.isOpen()) {
return;
}
serialPort.writeBytes(content, content.length);
}
/**
* 从串口读取数据
*
* @param serialPort 当前已建立连接的SerialPort对象
* @return 读取到的数据
*/
public static byte[] readFromPort(SerialPort serialPort) {
log.info("开始发送消息====》 {}", serialPort.bytesAvailable());
byte[] reslutData = null;
try {
if (!serialPort.isOpen()) {
return null;
}
int i = 0;
while (serialPort.bytesAvailable() > 0 && i++ < 5) Thread.sleep(20);
byte[] readBuffer = new byte[serialPort.bytesAvailable()];
int numRead = serialPort.readBytes(readBuffer, readBuffer.length);
if (numRead > 0) {
reslutData = readBuffer;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return reslutData;
}
/**
* 添加监听器
* @param serialPort 串口对象
* @param listener 串口存在有效数据监听
*/
public static void addListener(SerialPort serialPort, DataAvailableListener listener) {
try {
// 给串口添加监听器
serialPort.addDataListener(new SerialPortListener(listener));
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试类
package com.example.rxtxdemo.rxtx;
import cn.hutool.core.util.HexUtil;
import com.alibaba.fastjson2.JSONObject;
import com.fazecast.jSerialComm.SerialPort;
import com.google.common.collect.Maps;
import gnu.io.PortInUseException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@Slf4j
@RestController
@RequiredArgsConstructor
public class RxtxRest {
@GetMapping("sendData")
public Map<String, Object> sendData(@RequestParam String portName, @RequestParam Integer baudRate, @RequestParam String content) {
Map<String, Object> map = Maps.newHashMap();
SerialPort serialPort = SerialPortManager.openPort(portName, baudRate);
byte[] bytes = HexUtil.decodeHex(content);
try {
SerialPortManager.sendToPort(serialPort, bytes);
Thread.sleep(1000);
byte[] bytes1 = SerialPortManager.readFromPort(serialPort);
String receiveMsg = HexUtil.encodeHexStr(bytes1, false);
map.put("msg", receiveMsg);
} catch (InterruptedException e) {
e.printStackTrace();
}
SerialPortManager.closePort(serialPort);
return map;
}
@GetMapping("ports")
public Map<String, Object> test() {
Map<String, Object> map = Maps.newHashMap();
List<String> ports = SerialPortManager.findPorts();
ports.forEach(port -> map.put(port, SerialPort.getCommPort(port).isOpen()));
return map;
}
@GetMapping("test1")
public void test1() {
SerialPort[] serialPorts = SerialPort.getCommPorts();
//查找所有串口
for(SerialPort serialPort: serialPorts){
//打印串口名称,如COM4
System.out.println("Port:"+serialPort.getSystemPortName());
//打印串口类型,如USB Serial
System.out.println("PortDesc:"+serialPort.getPortDescription());
//打印串口的完整类型,如USB-SERIAL CH340(COM4)
System.out.println("PortDesc:"+serialPort.getDescriptivePortName());
//获取到第一个串口
//设置波特率为112500
serialPort.setBaudRate(112500);
//设置超时
serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 1000, 1000);
serialPort.setRTS();//设置RTS。也可以设置DTR
//设置串口的控制流,可以设置为disabled,或者CTS, RTS/CTS, DSR, DTR/DSR, Xon, Xoff, Xon/Xoff等
serialPort.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);
//一次性设置所有的串口参数,第一个参数为波特率,默认9600;第二个参数为每一位的大小,默认8,可以输入5到8之间的值;第三个参数为停止位大小,只接受内置常量,可以选择(ONE_STOP_BIT, ONE_POINT_FIVE_STOP_BITS, TWO_STOP_BITS);第四位为校验位,同样只接受内置常量,可以选择 NO_PARITY, EVEN_PARITY, ODD_PARITY, MARK_PARITY,SPACE_PARITY。
serialPort.setComPortParameters(112500, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
if(!serialPort.isOpen()){
//判断串口是否打开,如果没打开,就打开串口。打开串口的函数会返回一个boolean值,用于表明串口是否成功打开了
boolean openFlag = serialPort.openPort();
log.info("打开串口 == {}", openFlag);
}
//关闭串口。该函数同样会返回一个boolean值,表明串口是否成功关闭
boolean closeFlag = serialPort.closePort();
log.info("关闭== {}", closeFlag);
}
}
测试
调用 ip:port/sendData?portName=COM3&baudRate=1200&content=msg
查看返回信息是否跟调试软件一致即可