ModbusRtu.java 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. package com.mes.ui;
  2. import com.fazecast.jSerialComm.*;
  3. import java.math.BigInteger;
  4. public class ModbusRtu {
  5. public static SerialPort connect(){
  6. try{
  7. SerialPort serialPort = SerialPort.getCommPort("COM5"); // 替换为你的端口名
  8. serialPort.setComPortParameters(38400, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY); // 设置端口参数
  9. serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0);
  10. if (serialPort.openPort()) {
  11. System.out.println("Port opened successfully.");
  12. return serialPort;
  13. } else {
  14. return null;
  15. }
  16. }catch (Exception e){
  17. e.printStackTrace();
  18. return null;
  19. }
  20. }
  21. public static void disconnect(SerialPort serialPort) {
  22. if (serialPort != null && serialPort.isOpen()) {
  23. serialPort.closePort();
  24. }
  25. }
  26. public static SerialPort reconnect(SerialPort serialPort) {
  27. disconnect(serialPort);
  28. return connect();
  29. }
  30. public static void openDevice(SerialPort serialPort) {
  31. System.out.println("isOpen:");
  32. if(serialPort ==null || !serialPort.isOpen()){
  33. serialPort = reconnect(serialPort);
  34. }
  35. try {
  36. String writeString = "010600000000"; // 关
  37. String crc = getCRC16_Modbus_Str(writeString);
  38. byte[] writeBuffer = hexStringToByteArray(writeString+crc);
  39. serialPort.writeBytes(writeBuffer, writeBuffer.length);
  40. // 接收数据
  41. byte[] readBuffer = new byte[512]; // 调整数组大小以适应预期的响应长度
  42. int numRead = serialPort.readBytes(readBuffer, readBuffer.length);
  43. System.out.println("Read " + numRead + " bytes.");
  44. // 将读取的字节转换为十六进制字符串
  45. StringBuilder data = new StringBuilder();
  46. for (int i = 0; i < numRead; i++) {
  47. data.append(String.format("%02X", readBuffer[i]));
  48. }
  49. String revStr = data.toString();
  50. // String ret = revStr.substring(6,8);
  51. System.out.println("Received data: " + revStr);
  52. // System.out.println("ret data: " + ret);
  53. } catch (Exception e) {
  54. e.printStackTrace();
  55. serialPort.closePort();
  56. } finally {
  57. }
  58. }
  59. public static void closeDevice(SerialPort serialPort) {
  60. if(serialPort ==null || !serialPort.isOpen()){
  61. serialPort = reconnect(serialPort);
  62. }
  63. try {
  64. String writeString = "010600000001"; // 开
  65. String crc = getCRC16_Modbus_Str(writeString);
  66. byte[] writeBuffer = hexStringToByteArray(writeString+crc);
  67. serialPort.writeBytes(writeBuffer, writeBuffer.length);
  68. // 接收数据
  69. byte[] readBuffer = new byte[512]; // 调整数组大小以适应预期的响应长度
  70. int numRead = serialPort.readBytes(readBuffer, readBuffer.length);
  71. System.out.println("Read " + numRead + " bytes.");
  72. // 将读取的字节转换为十六进制字符串
  73. StringBuilder data = new StringBuilder();
  74. for (int i = 0; i < numRead; i++) {
  75. data.append(String.format("%02X", readBuffer[i]));
  76. }
  77. String revStr = data.toString();
  78. // String ret = revStr.substring(6,8);
  79. System.out.println("Received data: " + revStr);
  80. // System.out.println("ret data: " + ret);
  81. } catch (Exception e) {
  82. e.printStackTrace();
  83. serialPort.closePort();
  84. } finally {
  85. }
  86. }
  87. public static Boolean readCoil(SerialPort serialPort,int pos) {
  88. if(serialPort ==null || !serialPort.isOpen()){
  89. serialPort = reconnect(serialPort);
  90. }
  91. try {
  92. String writeString = "010100000"+pos+"01"; // 线圈地址 0/1,目前只有2路
  93. String crc = getCRC16_Modbus_Str(writeString);
  94. byte[] writeBuffer = hexStringToByteArray(writeString+crc);
  95. serialPort.writeBytes(writeBuffer, writeBuffer.length);
  96. // 接收数据
  97. byte[] readBuffer = new byte[512]; // 调整数组大小以适应预期的响应长度
  98. int numRead = serialPort.readBytes(readBuffer, readBuffer.length);
  99. System.out.println("Read " + numRead + " bytes.");
  100. // 将读取的字节转换为十六进制字符串
  101. StringBuilder data = new StringBuilder();
  102. for (int i = 0; i < numRead; i++) {
  103. data.append(String.format("%02X", readBuffer[i]));
  104. }
  105. String revStr = data.toString();
  106. String ret = revStr.substring(6,8);
  107. System.out.println("Received data: " + revStr);
  108. System.out.println("ret data: " + ret);
  109. if(ret.equals("01")){
  110. MesClient.setPublicSerialStatus("采集:true",0);
  111. return true;
  112. }else{
  113. MesClient.setPublicSerialStatus("采集:false",0);
  114. return false;
  115. }
  116. } catch (Exception e) {
  117. e.printStackTrace();
  118. MesClient.setPublicSerialStatus("串口断线",-1);
  119. serialPort.closePort();
  120. return false;
  121. }
  122. }
  123. /**
  124. * CRC16(modbus)校验
  125. * 获取crc16校验码,参数data中不能有空格
  126. * @param data
  127. * @return
  128. */
  129. public static String getCRC16_Modbus_Str(String data) {
  130. data = data.replace(" ", "");
  131. int len = data.length();
  132. if (!(len % 2 == 0)) {
  133. return "0000";
  134. }
  135. int num = len / 2;
  136. byte[] para = new byte[num];
  137. for (int i = 0; i < num; i++) {
  138. int value = Integer.valueOf(data.substring(i * 2, 2 * (i + 1)), 16);
  139. para[i] = (byte) value;
  140. }
  141. return getCRC(para);
  142. }
  143. /**
  144. * 计算CRC16校验码
  145. * @param bytes
  146. * 字节数组
  147. * @return {@link String} 校验码
  148. * @since 1.0
  149. */
  150. public static String getCRC(byte[] bytes) {
  151. // CRC寄存器全为1
  152. int CRC = 0x0000ffff;
  153. // 多项式校验值
  154. int POLYNOMIAL = 0x0000a001;
  155. int i, j;
  156. for (i = 0; i < bytes.length; i++) {
  157. CRC ^= ((int) bytes[i] & 0x000000ff);
  158. for (j = 0; j < 8; j++) {
  159. if ((CRC & 0x00000001) != 0) {
  160. CRC >>= 1;
  161. CRC ^= POLYNOMIAL;
  162. } else {
  163. CRC >>= 1;
  164. }
  165. }
  166. }
  167. // 结果转换为16进制
  168. String result = Integer.toHexString(CRC).toUpperCase();
  169. if (result.length() != 4) {
  170. StringBuffer sb = new StringBuffer("0000");
  171. result = sb.replace(4 - result.length(), 4, result).toString();
  172. }
  173. //高位在前地位在后
  174. //return result.substring(2, 4) + " " + result.substring(0, 2);
  175. // 交换高低位,低位在前高位在后
  176. return result.substring(2, 4) + result.substring(0, 2);
  177. }
  178. public static byte[] hexStringToByteArray(String hexString) {
  179. // 去除字符串前后的空格
  180. hexString = hexString.trim();
  181. // 确保字符串的长度是偶数
  182. if (hexString.length() % 2 != 0) {
  183. throw new IllegalArgumentException("Invalid hex string");
  184. }
  185. // 将字符串转换为BigInteger对象
  186. BigInteger bigInt = new BigInteger(hexString, 16);
  187. // 获取BigInteger表示的字节数组
  188. byte[] byteArray = bigInt.toByteArray();
  189. // 处理符号位,如果数组的长度大于字符串的长度,则将符号位字节去除
  190. if (byteArray.length > hexString.length() / 2) {
  191. byte[] trimmedArray = new byte[hexString.length() / 2];
  192. System.arraycopy(byteArray, 1, trimmedArray, 0, trimmedArray.length);
  193. return trimmedArray;
  194. }
  195. return byteArray;
  196. }
  197. }