如何实现串口无响应时的设备失联提示逻辑?
如何用jssc实现串口设备失联检测
问题描述
程序通过jssc库连接串口设备,需要在设备无响应时显示“设备失联”提示。但当前事件监听器无法触发该提示,启动程序后仅占用串口无任何动作,查阅jssc示例未找到解决方案。现有代码如下:
import jssc.*; import java.util.ArrayList; public class ComPortOperation { private static SerialPort serialPort; private static int baudRate; private static String portName; private static ArrayList<Integer> codes = new ArrayList<>(); static int[] dataInt; public static void connect(int number) throws SerialPortException { System.out.println(MainView.getItemSuperComboBox()); serialPort = new SerialPort(portName); serialPort.openPort(); serialPort.setParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_EVEN); serialPort.setEventsMask(SerialPort.MASK_RXCHAR); serialPort.addEventListener(new SerialPortReader(serialPort)); serialPort.writeIntArray(new int[]{number}); } static class SerialPortReader implements SerialPortEventListener { private SerialPort serialPort; public SerialPortReader(SerialPort serialPort){ this.serialPort = serialPort; } public void serialEvent(SerialPortEvent event) { if(!event.isRXCHAR()) { System.out.println("No connection"); // never reaches } try { dataInt = serialPort.readIntArray(1, 500); } catch (SerialPortException e) { System.out.println(e); } catch (SerialPortTimeoutException e) { e.printStackTrace(); } } } }
解决方案
jssc的MASK_RXCHAR事件仅在串口收到字符时才会触发,没有数据时不会进入serialEvent方法,因此原代码里的!event.isRXCHAR()判断永远不会执行。需要改用心跳+超时检测的逻辑实现失联判断:
修改后的完整代码
import jssc.*; import java.util.ArrayList; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ComPortOperation { private static SerialPort serialPort; private static int baudRate; private static String portName; private static ArrayList<Integer> codes = new ArrayList<>(); static int[] dataInt; // 记录最后一次收到设备数据的时间戳 private static long lastReceivedTime; // 超时检测定时器 private static ScheduledExecutorService statusChecker; // 设备失联阈值(单位:毫秒,示例设为5秒) private static final int DISCONNECT_THRESHOLD = 5000; public static void connect(int number) throws SerialPortException { System.out.println(MainView.getItemSuperComboBox()); serialPort = new SerialPort(portName); serialPort.openPort(); serialPort.setParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_EVEN); serialPort.setEventsMask(SerialPort.MASK_RXCHAR); serialPort.addEventListener(new SerialPortReader(serialPort)); // 初始化时间戳并启动超时检测 lastReceivedTime = System.currentTimeMillis(); statusChecker = Executors.newSingleThreadScheduledExecutor(); // 每隔1秒检查一次设备状态 statusChecker.scheduleAtFixedRate(ComPortOperation::checkDeviceStatus, 0, 1000, TimeUnit.MILLISECONDS); // 发送初始指令 serialPort.writeIntArray(new int[]{number}); } static class SerialPortReader implements SerialPortEventListener { private SerialPort serialPort; public SerialPortReader(SerialPort serialPort){ this.serialPort = serialPort; } public void serialEvent(SerialPortEvent event) { if(event.isRXCHAR()) { try { dataInt = serialPort.readIntArray(1, 500); // 收到数据就更新时间戳 lastReceivedTime = System.currentTimeMillis(); } catch (SerialPortException e) { System.out.println("串口读取异常:" + e.getMessage()); } catch (SerialPortTimeoutException e) { System.out.println("串口读取超时"); } } } } // 检测设备是否失联 private static void checkDeviceStatus() { long currentTime = System.currentTimeMillis(); if(currentTime - lastReceivedTime > DISCONNECT_THRESHOLD) { System.out.println("设备失联"); // 此处可添加UI提示逻辑,比如更新界面控件 } } // 关闭串口时清理资源 public static void disconnect() throws SerialPortException { if(serialPort != null && serialPort.isOpened()) { serialPort.closePort(); } if(statusChecker != null && !statusChecker.isShutdown()) { statusChecker.shutdown(); } } }
核心改进说明
- 新增时间戳记录:每次收到设备数据时更新
lastReceivedTime,标记设备在线状态 - 定时器轮询检测:通过
ScheduledExecutorService每隔1秒检查时间戳差值,超过设定阈值则判定设备失联 - 资源清理:添加
disconnect方法,关闭串口时停止定时器,避免内存泄漏
内容的提问来源于stack exchange,提问作者user27167750
相关产品推荐
相关产品推荐

