Java 串口通信Demo
一、工具
1、虚拟串口工具:Virtual Serial Port Driver Pro
2、串口调试工具
3、下载
链接:https://pan.baidu.com/s/1GSBlRECJ53WH6zHIn0vUWg
提取码:tknr
二、pom引入
<dependency>
<groupId>org.rxtx</groupId>
<artifactId>rxtx</artifactId>
<version>2.1.7</version>
</dependency>
三、Java串口通信demo
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import lombok.SneakyThrows;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
public class SerialPortCommunicationDemo {
private static byte[] cache = new byte[1024];
/**
* 时间格式化
*/
static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
public static void main(String[] args) throws Exception {
/**
* 监听的串口
*/
String serialPortNo = "COM1";
/**
* 存放所有串口
*/
List<String> serialPortList = new ArrayList<>();
/**
*
* 获取本地所有串口
*
*/
Enumeration portIdentifiers = CommPortIdentifier.getPortIdentifiers();
/**
* 遍历所有串口,获取串口名
*/
System.out.printf("输出所有串口:");
while (portIdentifiers.hasMoreElements()) {
CommPortIdentifier portIdentifier = (CommPortIdentifier) portIdentifiers.nextElement();
serialPortList.add(portIdentifier.getName());
}
System.out.println(serialPortList);
/**
* 判断串口是否存在
*/
if (!serialPortList.contains(serialPortNo)) {
System.out.println("串口不存在");
return;
}
/**
* 获取串口
*/
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(serialPortNo);
/**
* 打开串口
*/
SerialPort serialPort = (SerialPort) portIdentifier.open(serialPortNo, 1000);
System.out.println("监听串口:" + serialPortNo);
/**
* 创建线程池
*/
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(10, threadFactory);
/**
* 开启一个定时任务线程读取串口数据,每3秒执行一次
*/
scheduledThreadPoolExecutor.scheduleAtFixedRate(new Runnable() {
@SneakyThrows
@Override
public void run() {
readData(serialPort);
}
}, 1000, 3000, TimeUnit.MILLISECONDS);
/**
* 开启一个定时任务线程向串口写数据,每5秒执行一次
*/
scheduledThreadPoolExecutor.scheduleAtFixedRate(new Runnable() {
@SneakyThrows
@Override
public void run() {
writeData(serialPort);
}
}, 1000, 5000, TimeUnit.MILLISECONDS);
}
/**
* 读取串口数据
*
* @param serialPort
* @throws Exception
*/
public static void readData(SerialPort serialPort) throws Exception {
/**
* 获取串口的输入流对象
*/
InputStream inputStream = serialPort.getInputStream();
/**
* 获取可用数据
*/
int availableBytes = inputStream.available();
/**
* 如果可用数据大于0,则开始读取数据
*/
while (availableBytes > 0) {
/**
* 从串口的输入流对象中读入数据并将数据存放到缓存数组中
*/
inputStream.read(cache);
/**
* 将获取到的数据进行转码并输出
*/
for (int i = 0; i < cache.length && i < availableBytes; i++) {
System.out.print((char) cache[i]);
}
System.out.println();
availableBytes = inputStream.available();
}
}
/**
* 写数据到串口
*
* @param serialPort
* @throws Exception
*/
public static void writeData(SerialPort serialPort) throws Exception {
/**
* 获取串口的输出流对象
*/
OutputStream outputStream = serialPort.getOutputStream();
/**
* 当前时间格式化
*/
String date = simpleDateFormat.format(new Date());
/**
* 将当前时间发送给串口
*/
outputStream.write(date.getBytes(StandardCharsets.UTF_8));
}
}
四、运行截图
五、串口工具类
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 SerialPortUtil {
private static SerialPortUtil serialPortUtil = null;
static {
/**
* 在该类被ClassLoader加载时就初始化一个SerialTool对象
*/
if (serialPortUtil == null) {
serialPortUtil = new SerialPortUtil();
}
}
/**
* 私有化SerialTool类的构造方法,不允许其他类生成SerialTool对象
*/
private SerialPortUtil() {
}
/**
* 获取提供服务的SerialPortUtil对象
*
* @return serialPortUtil
*
*/
public static SerialPortUtil getSerialPortUtil() {
if (serialPortUtil == null) {
serialPortUtil = new SerialPortUtil();
}
return serialPortUtil;
}
/**
* 查找所有串口
*
* @return 串口名称列表
*
*/
public ArrayList<String> findPort() {
//获得当前所有可用串口
Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
ArrayList<String> portNameList = new ArrayList<>();
//将可用串口名添加到List,返回该List
while (portList.hasMoreElements()) {
String portName = portList.nextElement().getName();
portNameList.add(portName);
}
return portNameList;
}
/**
* 打开串口
*
* @param portName 串口名称
* @param baudrate 波特率
* @param databits 数据位
* @param parity 校验位(奇偶位)
* @param stopbits 停止位
* @return 串口对象
*
*/
public SerialPort openPort(String portName, int baudrate, int databits, int stopbits, int parity) {
if (!findPort().contains(portName)) {
log.info("串口" + portName + "不存在...");
return null;
}
try {
//通过串口名识别串口
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
//打开串口,并给串口名字和一个timeout(打开操作的超时时间)
CommPort commPort = portIdentifier.open(portName, 2000);
//判断是不是串口
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
try {
//设置一下串口的波特率等参数
serialPort.setSerialPortParams(baudrate, databits, stopbits, parity);
} catch (UnsupportedCommOperationException unsupportedCommOperationException) {
log.error("串口" + portName + "参数配置错误...");
unsupportedCommOperationException.printStackTrace();
}
log.info("串口" + portName + "打开成功...");
return serialPort;
} else {
log.error(portName + "不是串口...");
}
} catch (PortInUseException portInUseException) {
log.error("串口" + portName + "被占用...");
portInUseException.printStackTrace();
} catch (Exception exception) {
exception.printStackTrace();
}
return null;
}
/**
* 关闭串口
*
* @param serialPort 待关闭的串口对象
*
*/
public void closePort(SerialPort serialPort) {
if (serialPort != null) {
serialPort.close();
log.info(SerialPortStringUtil.serialPortNameHandle(serialPort.getName())+"串口关闭成功...");
}
}
/**
* 往串口发送数据
*
* @param serialPort 串口对象
* @param order 待发送数据
*
*/
public void sendToPort(SerialPort serialPort, byte[] order) {
OutputStream out = null;
try {
out = serialPort.getOutputStream();
out.write(order);
out.flush();
log.info(SerialPortStringUtil.serialPortNameHandle(serialPort.getName())+"串口写入数据完毕...");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 从串口读取数据
*
* @param serialPort 当前已建立连接的SerialPort对象
* @return 读取到的数据 bytes
*
*/
public byte[] readFromPort(SerialPort serialPort) {
InputStream in = null;
byte[] bytes = null;
try {
in = serialPort.getInputStream();
int bufflenth = in.available();
while (bufflenth != 0) {
bytes = new byte[bufflenth];
in.read(bytes);
bufflenth = in.available();
}
log.info(SerialPortStringUtil.serialPortNameHandle(serialPort.getName())+"串口读取数据完毕...");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bytes;
}
/**
* 添加监听器
*
* @param serialPort 串口对象
* @param listener 串口监听器
*
*/
public void addListener(SerialPort serialPort, SerialPortEventListener listener) {
try {
//给串口添加监听器
serialPort.addEventListener(listener);
//设置当有数据到达时唤醒监听接收线程
serialPort.notifyOnDataAvailable(true);
//设置当通信中断时唤醒中断线程
serialPort.notifyOnBreakInterrupt(true);
log.info(SerialPortStringUtil.serialPortNameHandle(serialPort.getName())+"串口添加监听成功...");
} catch (TooManyListenersException e) {
log.error("监听器串口对象数量溢出...");
e.printStackTrace();
}
}
/**
* 删除监听器
*
* @param serialPort 串口对象
* @param listener 串口监听器
*
*/
public void removeListener(SerialPort serialPort, SerialPortEventListener listener) {
//删除串口监听器
serialPort.removeEventListener();
log.info(SerialPortStringUtil.serialPortNameHandle(serialPort.getName())+"串口移除监听成功...");
}
}