最近花了好长时间去研究~上代码
1 package test; 2
3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 import java.nio.charset.StandardCharsets; 7 import java.util.Enumeration; 8 import java.util.TooManyListenersException; 9
10 import com.serotonin.io.serial.SerialPortException; 11
12 import gnu.io.CommPort; 13 import gnu.io.CommPortIdentifier; 14 import gnu.io.PortInUseException; 15 import gnu.io.SerialPort; 16 import gnu.io.SerialPortEvent; 17 import gnu.io.SerialPortEventListener; 18 import gnu.io.UnsupportedCommOperationException; 19
20 public class SerialPortUtils implements SerialPortEventListener { 21 // 检测系统中可用的通讯端口类
22 private CommPortIdentifier commPortId; 23 // 枚举类型
24 private Enumeration<CommPortIdentifier> portList; 25 // RS232串口
26 private SerialPort serialPort; 27 // 输入流
28 private InputStream inputStream; 29 // 输出流
30 private OutputStream outputStream; 31 // 保存串口返回信息
32 private String data; 33 // 保存串口返回信息十六进制
34 private String dataHex; 35
36 /**
37 * 初始化串口
38 *
39 * @throws
40 * @author LinWenLi 41 * @date 2018年7月21日下午3:44:16
42 * @Description: TODO
43 * @param: paramConfig 存放串口连接必要参数的对象(会在下方给出类代码)
44 * @return: void
45 */
46 @SuppressWarnings("unchecked")
47 public void init() throws SerialPortException { 48 // 获取系统中所有的通讯端口
49 portList = CommPortIdentifier.getPortIdentifiers(); 50 // 记录是否含有指定串口
51 boolean isExsist = false;
52 // 循环通讯端口
53 while (portList.hasMoreElements()) { 54 commPortId = portList.nextElement(); 55 // 判断是否是串口
56 if (commPortId.getPortType() == CommPortIdentifier.PORT_SERIAL) { 57 // 比较串口名称是否是指定串口
58 if ("COM7".equals(commPortId.getName())) {
59 // 串口存在
60 isExsist = true;
61 // 打开串口
62 try { 63 // open:(应用程序名【随意命名】,阻塞时等待的毫秒数)
64 serialPort = (SerialPort) commPortId.open(Object.class.getSimpleName(), 2000);
65 // 设置串口监听
66 serialPort.addEventListener(this);
67 // 设置串口数据时间有效(可监听)
68 serialPort.notifyOnDataAvailable(true);
69 // 设置串口通讯参数:波特率,数据位,停止位,校验方式
70 serialPort.setSerialPortParams(9600, 8,
71 1, 0);
72 } catch (PortInUseException e) { 73 throw new SerialPortException("端口被占用");
74 } catch (TooManyListenersException e) { 75 throw new SerialPortException("监听器过多");
76 } catch (UnsupportedCommOperationException e) { 77 throw new SerialPortException("不支持的COMM端口操作异常");
78 }
79 // 结束循环
80 break;
81 }
82 }
83 }
84 // 若不存在该串口则抛出异常
85 if (!isExsist) {
86 throw new SerialPortException("不存在该串口!");
87 }
88 }
89
90 /**
91 * 实现接口SerialPortEventListener中的方法 读取从串口中接收的数据
92 */
93 @Override
94 public void serialEvent(SerialPortEvent event) { 95 }
96
97
98 /**
99 * 读取串口返回信息 100 101 * @author LinWenLi 102 * @date 2018年7月21日下午3:43:04 103 * @return: void 104 /
105 public void readCommPort() throws SerialPortException { 106 } 107
108 /**
109 * 发送信息到串口 110 * 111 * @throws
112 * @author LinWenLi 113 * @date 2018年7月21日下午3:45:22 114 * @param: data 115 * @return: void 116 */
117 public void sendComm(String data) throws SerialPortException { 118 byte[] writerBuffer = null; 119 try { 120 // writerBuffer = hexToByteArray(data);
121 writerBuffer = data.getBytes(StandardCharsets.UTF_8); 122 } catch (NumberFormatException e) { 123 throw new SerialPortException("命令格式错误!"); 124 } 125 try { 126 outputStream = serialPort.getOutputStream(); 127 outputStream.write(writerBuffer); 128 outputStream.flush(); 129 } catch (NullPointerException e) { 130 throw new SerialPortException("找不到串口。"); 131 } catch (IOException e) { 132 throw new SerialPortException("发送信息到串口时发生IO异常"); 133 } 134 } 135
136 /**
137 * 关闭串口 138 * 139 * @throws
140 * @author LinWenLi 141 * @date 2018年7月21日下午3:45:43 142 * @Description: 关闭串口 143 * @param: 144 * @return: void 145 */
146 public void closeSerialPort() throws SerialPortException { 147 if (serialPort != null) { 148 serialPort.notifyOnDataAvailable(false); 149 serialPort.removeEventListener(); 150 if (inputStream != null) { 151 try { 152 inputStream.close(); 153 inputStream = null; 154 } catch (IOException e) { 155 throw new SerialPortException("关闭输入流时发生IO异常"); 156 } 157 } 158 if (outputStream != null) { 159 try { 160 outputStream.close(); 161 outputStream = null; 162 } catch (IOException e) { 163 throw new SerialPortException("关闭输出流时发生IO异常"); 164 } 165 } 166 serialPort.close(); 167 serialPort = null; 168 } 169 } 170
171 /**
172 * 十六进制串口返回值获取 173 */
174 public String getDataHex() { 175 String result = dataHex; 176 // 置空执行结果
177 dataHex = null; 178 // 返回执行结果
179 return result; 180 } 181
182 /**
183 * 串口返回值获取 184 */
185 public String getData() { 186 String result = data; 187 // 置空执行结果
188 data = null; 189 // 返回执行结果
190 return result; 191 } 192
193 /**
194 * Hex字符串转byte 195 196 * @param inHex 待转换的Hex字符串 197 * @return 转换后的byte 198 /
199 public static byte hexToByte(String inHex) { 200 return (byte) Integer.parseInt(inHex, 16); 201 } 202
203 /**
204 * hex字符串转byte数组 205 206 * @param inHex 待转换的Hex字符串 207 * @return 转换后的byte数组结果 208 /
209 public static byte[] hexToByteArray(String inHex) { 210 int hexlen = inHex.length(); 211 byte[] result; 212 if (hexlen % 2 == 1) { 213 // 奇数
214 hexlen++; 215 result = new byte[(hexlen / 2)]; 216 inHex = "0" + inHex; 217 } else { 218 // 偶数
219 result = new byte[(hexlen / 2)]; 220 } 221 int j = 0; 222 for (int i = 0; i < hexlen; i += 2) { 223 result[j] = hexToByte(inHex.substring(i, i + 2)); 224 j++; 225 } 226 return result; 227 } 228
229 /**
230 * 数组转换成十六进制字符串 231 232 * @param bArray 233 * @return HexString 234 /
235 public static final String bytesToHexString(byte[] bArray) { 236 StringBuffer sb = new StringBuffer(bArray.length); 237 String sTemp; 238 for (int i = 0; i < bArray.length; i++) { 239 sTemp = Integer.toHexString(0xFF & bArray[i]); 240 if (sTemp.length() < 2) 241 sb.append(0); 242 sb.append(sTemp.toUpperCase()); 243 } 244 return sb.toString(); 245 } 246
247 /**
248 * 打卡串口 249 * @param portName 串口名 250 * @param baudRate 波特率 251 * @param dataBits 数据位 252 * @param stopBits 停止位 253 * @param parity 校验位 254 * @return 串口对象 255 */
256 public static SerialPort open(String portName, Integer baudRate, Integer dataBits, 257 Integer stopBits, Integer parity) { 258 SerialPort result = null; 259 try { 260 // 通过端口名识别端口
261 CommPortIdentifier identifier = CommPortIdentifier.getPortIdentifier(portName); 262 // 打开端口,并给端口名字和一个timeout(打开操作的超时时间)
263 if(identifier.isCurrentlyOwned()) { 264 return null; 265 } 266 CommPort commPort = identifier.open(portName, 2000); 267 // 判断是不是串口
268 if (commPort instanceof SerialPort) { 269 result = (SerialPort) commPort; 270 // 设置一下串口的波特率等参数
271 result.setSerialPortParams(baudRate, dataBits, stopBits, parity); 272 }else{ 273 } 274 } catch (Exception e) { 275 e.printStackTrace(); 276 } 277 return result; 278 } 279
280 /**
281 * 关闭串口 282 * @param serialPort 283 */
284 public static void close(SerialPort serialPort) { 285 if (serialPort != null) { 286 serialPort.close(); 287 } 288 } 289
290 }
1 package modbus_rtu; 2
3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6
7 import org.slf4j.Logger; 8 import org.slf4j.LoggerFactory; 9
10 import com.serotonin.modbus4j.serial.SerialPortWrapper; 11
12 import gnu.io.SerialPort; 13 import test.SerialPortUtils; 14
15 /**
16 * 自定义串口封装
17 *
18 * @author wusq 19 * @date 2021/1/3
20 */
21 public class SerialPortWrapperImpl implements SerialPortWrapper { 22
23 private final Logger log = LoggerFactory.getLogger(this.getClass());
24
25 /**
26 * 串口对象
27 */
28 private SerialPort serialPort; 29
30 /**
31 * 串口
32 */
33 private String port; 34
35 /**
36 * 波特率
37 */
38 private Integer baudRate; 39
40 /**
41 * 数据位的位数,RTU是8位,ASCII是7位
42 */
43 private Integer dataBits; 44
45 /**
46 * 停止位的位数,如果无奇偶校验为2,有奇偶校验为1
47 */
48 private Integer stopBits; 49
50 /**
51 * 奇偶校验位,无校验是0,奇校验是1,偶校验是2
52 */
53 private Integer parity; 54
55 /**
56 * 硬件之间输入流应答控制
57 */
58 private Integer flowControlIn; 59
60 /**
61 * 硬件之间输出流应答控制
62 */
63 private Integer flowControlOut; 64
65 public SerialPortWrapperImpl() { 66 super();
67 }
68
69 public SerialPortWrapperImpl(String port, int baudRate, int dataBits, int stopBits, int parity, 70 int flowControlIn, int flowControlOut) { 71 this.port = port; 72 this.baudRate = baudRate; 73 this.dataBits = dataBits; 74 this.stopBits = stopBits; 75 this.parity = parity; 76 this.flowControlIn = flowControlIn; 77 this.flowControlOut = flowControlOut; 78 }
79
80 @Override
81 public void close() throws Exception { 82 SerialPortUtils.close(serialPort);
83 }
84
85 @Override
86 public void open() throws Exception { 87 serialPort = SerialPortUtils.open(port, baudRate, dataBits, stopBits, parity); 88 }
89
90 @Override
91 public InputStream getInputStream() { 92 InputStream in = null;
93 try { 94 in = serialPort.getInputStream(); 95 } catch (IOException e) { 96 log.error("获取串口输入流错误", e);
97 }
98
99 return in; 100 } 101
102 @Override 103 public OutputStream getOutputStream() { 104 OutputStream out = null; 105 try { 106 out = serialPort.getOutputStream(); 107 } catch (IOException e) { 108 log.error("获取串口输出流错误", e); 109 } 110
111 return out; 112 } 113
114 @Override 115 public int getBaudRate() { 116 return this.baudRate; 117 } 118
119 @Override 120 public int getDataBits() { 121 return this.dataBits; 122 } 123
124 @Override 125 public int getStopBits() { 126 return this.stopBits; 127 } 128
129 @Override 130 public int getParity() { 131 return this.parity; 132 } 133
134 public int getFlowControlIn() { 135 return this.flowControlIn; 136 } 137
138 public int getFlowControlOut() { 139 return this.flowControlOut; 140 } 141
142 public SerialPort getSerialPort() { 143 return serialPort; 144 } 145
146 public void setSerialPort(SerialPort serialPort) { 147 this.serialPort = serialPort; 148 } 149
150 public String getPort() { 151 return port; 152 } 153
154 public void setPort(String port) { 155 this.port = port; 156 } 157
158 public void setBaudRate(Integer baudRate) { 159 this.baudRate = baudRate; 160 } 161
162 public void setDataBits(Integer dataBits) { 163 this.dataBits = dataBits; 164 } 165
166 public void setStopBits(Integer stopBits) { 167 this.stopBits = stopBits; 168 } 169
170 public void setParity(Integer parity) { 171 this.parity = parity; 172 } 173
174 public void setFlowControlIn(Integer flowControlIn) { 175 this.flowControlIn = flowControlIn; 176 } 177
178 public void setFlowControlOut(Integer flowControlOut) { 179 this.flowControlOut = flowControlOut; 180 } 181 }
1 package modbus_rtu; 2
3 import javax.annotation.Resource; 4
5
6 import com.serotonin.modbus4j.ModbusFactory; 7 import com.serotonin.modbus4j.ModbusMaster; 8 import com.serotonin.modbus4j.exception.ModbusTransportException; 9 import com.serotonin.modbus4j.msg.ReadHoldingRegistersRequest; 10 import com.serotonin.modbus4j.msg.ReadHoldingRegistersResponse; 11 import com.serotonin.modbus4j.msg.WriteRegisterRequest; 12 import com.serotonin.modbus4j.msg.WriteRegisterResponse; 13 import com.serotonin.modbus4j.msg.WriteRegistersRequest; 14 import com.serotonin.modbus4j.msg.WriteRegistersResponse; 15 import com.serotonin.modbus4j.sero.util.queue.ByteQueue; 16
17 public class ModbusRtuMaster { 18 // 检测系统中可用的通讯端口类
19 private static SerialPortWrapperImpl wrapper; 20
21 private static ModbusMaster master; 22
23 private static ModbusFactory modbusFactory; 24
25
26 //private static ModbusRtuMaster modbusRtuMaster;
27
28 public ModbusRtuMaster() { 29
30 }
31
32 /*
33 * public static synchronized ModbusRtuMaster getInstance() { if(modbusRtuMaster
34 * == null) { modbusRtuMaster = new ModbusRtuMaster(); } return modbusRtuMaster;
35 * }
36 */
37 /**
38 * 端口是否在使用
39 * @param serialNumber 40 * @return
41 */
42 public boolean inUse(String serialNumber) { 43 boolean bl = false;
44 if(this.wrapper == null) {
45 return bl; 46 }
47 if(this.wrapper.getPort() !=null && this.wrapper.getPort().equalsIgnoreCase(serialNumber)) {
48 bl = master.isInitialized(); 49 }
50 return bl; 51 }
52
53 public void createRtuMaster(String serialNumber,int baudRate,int dataBit,int stopBit,int checkoutBit) throws Exception{//relayParamConfig.getSerialNumber(), relayParamConfig.getBaudRate(),
54 //relayParamConfig.getDataBit(),relayParamConfig.getStopBit(), relayParamConfig.getCheckoutBit()
55 // 设置串口参数,串口是COM1,波特率是9600
56 wrapper = new SerialPortWrapperImpl(serialNumber, baudRate, 57 dataBit,stopBit, checkoutBit,0,0);//SerialPort.PARITY_NONE
58 modbusFactory = new ModbusFactory(); 59 // System.out.println("relayParamConfig.getSerialNumber()->"+relayParamConfig.getSerialNumber());
60 master = modbusFactory.createRtuMaster(wrapper); 61 master.init();
62 // 从站设备ID是1 63 // int slaveId = 1; 64
65 // 读取保持寄存器 66 // readHoldingRegisters(master, slaveId, 0, 3); 67 // 将地址为0的保持寄存器数据修改为0 68 // writeRegister(master, slaveId, offset, value); 69 // 再读取保持寄存器 70 // readHoldingRegisters(master, slaveId, 0, 3); 71 // short[] s = {00}; 72 // controlRelay(master, slaveId, 0, s); 73 // RtuMasterTest.writeRegistersTest(master, slaveId, 0, s);
74 }
75
76 /*
77 * public void init(RelayParamConfig relayParamConfig) throws Exception {
78 * this.relayParamConfig = relayParamConfig;
79 * if(!this.inUse(relayParamConfig.getSerialNumber())) { this.createRtuMaster();
80 * } }
81 */
82
83 public void closeRtuMaster() throws Exception{ 84 wrapper.close();
85 }
86
87 public void controlRelay(int slaveId, int offset, int value) throws Exception{ 88 writeRegister(master, slaveId, offset, value);
89 // this.closeRtuMaster();
90 }
91 // int slaveId = 1; 92
93 // 读取保持寄存器 94 // readHoldingRegisters(master, slaveId, 0, 3); 95 // 将地址为0的保持寄存器数据修改为0 96 // writeRegister(master, slaveId, offset, value);
97
98 private void readHoldingRegisters(ModbusMaster master, int slaveId, int start, int len) throws Exception{ 99 ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, start, len); 100 ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.send(request); 101 if (response.isException()){ 102 System.out.println("读取保持寄存器错误,错误信息是" + response.getExceptionMessage()); 103 }else { 104 // System.out.println("读取保持寄存器=" + Arrays.toString(response.getShortData()));
105 } 106 } 107
108 private void writeRegister(ModbusMaster master, int slaveId, int offset, int value) throws Exception{ 109 WriteRegisterRequest request = new WriteRegisterRequest(slaveId, offset, value); 110 ByteQueue queue = new ByteQueue(); 111
112 WriteRegisterResponse response = (WriteRegisterResponse) master.send(request); 113 if (response.isException()){ 114 System.out.println("写保持寄存器错误,错误信息是" + response.getExceptionMessage()); 115 }else{ 116 System.out.println("指令发送成功!"); 117 } 118 } 119
120 public void writeRegistersTest(ModbusMaster master, int slaveId, int start, short[] values) { 121 try { 122 WriteRegistersRequest request = new WriteRegistersRequest(slaveId, start, values); 123 System.out.println("request:"+request); 124 System.out.println("FunctionCode:"+request.getFunctionCode()); 125 System.out.println("SlaveId:"+request.getSlaveId()); 126 WriteRegistersResponse response = (WriteRegistersResponse) master.send(request); 127
128 if (response.isException()) 129 System.out.println("Exception response: message=" + response.getExceptionMessage()); 130 else { 131 System.out.println("Success"); 132 } 133 } 134 catch (ModbusTransportException e) { 135 e.printStackTrace(); 136 } 137 } 138 public static void main(String[] args) { 139 ModbusRtuMaster rmt = new ModbusRtuMaster(); 140 try { 141 rmt.createRtuMaster("COM7",9600,8,1,0); 142 rmt.controlRelay(1,1,0); 143 } catch (Exception e) { 144 // TODO Auto-generated catch block
145 e.printStackTrace(); 146 } 147 } 148 }
上述程序所需关键包我上传到了百度云盘
链接:https://pan.baidu.com/s/1JaZaNcnQu1fp7DBIuowazg
提取码:us3z
原网址: 访问
创建于: 2023-08-31 10:34:26
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论