花花_新世界
从【程序猿】到【程序员】的进化历程

最近花了好长时间去研究~上代码

  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 }

上述程序所需关键包我上传到了百度云盘

微信扫描二维码关注一下公众号,回复ModbusRTU即可

 

posted on 2021-04-29 17:06  花花_新世界  阅读(9223)  评论(2编辑  收藏  举报