package com.mes.ui; import com.fazecast.jSerialComm.*; import java.math.BigInteger; public class ModbusRtu { public static SerialPort connect(){ try{ SerialPort serialPort = SerialPort.getCommPort("COM5"); // 替换为你的端口名 serialPort.setComPortParameters(38400, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY); // 设置端口参数 serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0); if (serialPort.openPort()) { System.out.println("Port opened successfully."); return serialPort; } else { return null; } }catch (Exception e){ e.printStackTrace(); return null; } } public static void disconnect(SerialPort serialPort) { if (serialPort != null && serialPort.isOpen()) { serialPort.closePort(); } } public static SerialPort reconnect(SerialPort serialPort) { disconnect(serialPort); return connect(); } public static void openDevice(SerialPort serialPort) { System.out.println("isOpen:"); if(serialPort ==null || !serialPort.isOpen()){ serialPort = reconnect(serialPort); } try { String writeString = "010600000000"; // 关 String crc = getCRC16_Modbus_Str(writeString); byte[] writeBuffer = hexStringToByteArray(writeString+crc); serialPort.writeBytes(writeBuffer, writeBuffer.length); // 接收数据 byte[] readBuffer = new byte[512]; // 调整数组大小以适应预期的响应长度 int numRead = serialPort.readBytes(readBuffer, readBuffer.length); System.out.println("Read " + numRead + " bytes."); // 将读取的字节转换为十六进制字符串 StringBuilder data = new StringBuilder(); for (int i = 0; i < numRead; i++) { data.append(String.format("%02X", readBuffer[i])); } String revStr = data.toString(); // String ret = revStr.substring(6,8); System.out.println("Received data: " + revStr); // System.out.println("ret data: " + ret); } catch (Exception e) { e.printStackTrace(); serialPort.closePort(); } finally { } } public static void closeDevice(SerialPort serialPort) { if(serialPort ==null || !serialPort.isOpen()){ serialPort = reconnect(serialPort); } try { String writeString = "010600000001"; // 开 String crc = getCRC16_Modbus_Str(writeString); byte[] writeBuffer = hexStringToByteArray(writeString+crc); serialPort.writeBytes(writeBuffer, writeBuffer.length); // 接收数据 byte[] readBuffer = new byte[512]; // 调整数组大小以适应预期的响应长度 int numRead = serialPort.readBytes(readBuffer, readBuffer.length); System.out.println("Read " + numRead + " bytes."); // 将读取的字节转换为十六进制字符串 StringBuilder data = new StringBuilder(); for (int i = 0; i < numRead; i++) { data.append(String.format("%02X", readBuffer[i])); } String revStr = data.toString(); // String ret = revStr.substring(6,8); System.out.println("Received data: " + revStr); // System.out.println("ret data: " + ret); } catch (Exception e) { e.printStackTrace(); serialPort.closePort(); } finally { } } public static Boolean readCoil(SerialPort serialPort,int pos) { if(serialPort ==null || !serialPort.isOpen()){ serialPort = reconnect(serialPort); } try { String writeString = "010100000"+pos+"01"; // 线圈地址 0/1,目前只有2路 String crc = getCRC16_Modbus_Str(writeString); byte[] writeBuffer = hexStringToByteArray(writeString+crc); serialPort.writeBytes(writeBuffer, writeBuffer.length); // 接收数据 byte[] readBuffer = new byte[512]; // 调整数组大小以适应预期的响应长度 int numRead = serialPort.readBytes(readBuffer, readBuffer.length); System.out.println("Read " + numRead + " bytes."); // 将读取的字节转换为十六进制字符串 StringBuilder data = new StringBuilder(); for (int i = 0; i < numRead; i++) { data.append(String.format("%02X", readBuffer[i])); } String revStr = data.toString(); String ret = revStr.substring(6,8); System.out.println("Received data: " + revStr); System.out.println("ret data: " + ret); if(ret.equals("01")){ MesClient.setPublicSerialStatus("采集:true",0); return true; }else{ MesClient.setPublicSerialStatus("采集:false",0); return false; } } catch (Exception e) { e.printStackTrace(); MesClient.setPublicSerialStatus("串口断线",-1); serialPort.closePort(); return false; } } /** * CRC16(modbus)校验 * 获取crc16校验码,参数data中不能有空格 * @param data * @return */ public static String getCRC16_Modbus_Str(String data) { data = data.replace(" ", ""); int len = data.length(); if (!(len % 2 == 0)) { return "0000"; } int num = len / 2; byte[] para = new byte[num]; for (int i = 0; i < num; i++) { int value = Integer.valueOf(data.substring(i * 2, 2 * (i + 1)), 16); para[i] = (byte) value; } return getCRC(para); } /** * 计算CRC16校验码 * @param bytes * 字节数组 * @return {@link String} 校验码 * @since 1.0 */ public static String getCRC(byte[] bytes) { // CRC寄存器全为1 int CRC = 0x0000ffff; // 多项式校验值 int POLYNOMIAL = 0x0000a001; int i, j; for (i = 0; i < bytes.length; i++) { CRC ^= ((int) bytes[i] & 0x000000ff); for (j = 0; j < 8; j++) { if ((CRC & 0x00000001) != 0) { CRC >>= 1; CRC ^= POLYNOMIAL; } else { CRC >>= 1; } } } // 结果转换为16进制 String result = Integer.toHexString(CRC).toUpperCase(); if (result.length() != 4) { StringBuffer sb = new StringBuffer("0000"); result = sb.replace(4 - result.length(), 4, result).toString(); } //高位在前地位在后 //return result.substring(2, 4) + " " + result.substring(0, 2); // 交换高低位,低位在前高位在后 return result.substring(2, 4) + result.substring(0, 2); } public static byte[] hexStringToByteArray(String hexString) { // 去除字符串前后的空格 hexString = hexString.trim(); // 确保字符串的长度是偶数 if (hexString.length() % 2 != 0) { throw new IllegalArgumentException("Invalid hex string"); } // 将字符串转换为BigInteger对象 BigInteger bigInt = new BigInteger(hexString, 16); // 获取BigInteger表示的字节数组 byte[] byteArray = bigInt.toByteArray(); // 处理符号位,如果数组的长度大于字符串的长度,则将符号位字节去除 if (byteArray.length > hexString.length() / 2) { byte[] trimmedArray = new byte[hexString.length() / 2]; System.arraycopy(byteArray, 1, trimmedArray, 0, trimmedArray.length); return trimmedArray; } return byteArray; } }