福兮祸所伏, 祸兮福所倚。(现在发生在你身上的都是好事,福祸相伴)
这些源码应该都可以看的懂 我就不解释了。
public void Connect(String comPort) throws Exception {// 类似于串口连接(个人理解)this.portIdentifier = CommPortIdentifier.getPortIdentifier(comPort);if (this.portIdentifier.isCurrentlyOwned()) {System.out.println("Error: Port is currently in use");} else {int timeout = 2000;// 串口对象CommPort commPort = this.portIdentifier.open(this.getClass().getName(), timeout);if (commPort instanceof SerialPort) {this.serialPort = (SerialPort)commPort;this.serialPort.setSerialPortParams(9600, 8, 1, 2);this.serialPort.enableReceiveTimeout(1000);this.serialPort.disableReceiveThreshold();this.in = this.serialPort.getInputStream();this.out = this.serialPort.getOutputStream();this.serialflag = true;} else {System.out.println("Error: Only serial ports are handled by this example.");}}}
那咱们就运行 ,结果。。。。。。。。。。。
少了个处理串口的依赖包 (我用的是RXTX 2.2,当时找的时候 网上那些都是粘贴,估计怎么搞得 他们都不知道 搞得我晕头转向的 真的是误人子弟。上解决方法)
下载RXTX2.2(包括各个系统版本)
将RXTXcomm.jar以上面相同的方式 引入到你的项目
我的是64的 我直接说64的 32位的会有所不同 留给你们自己去探索吧
- 找到RXTXcomm.jar 复制你的java_home下jre\lib和jre\lib\ext
- 点击进入win64 复制rxtxSerial.dll 到\jre\bin
那接下来是不是可以见证奇迹了呢 还要再等下
- 如果单单是串口读取的话 我们现在的代码就可以完全操作了
- 如果说是wifi (就一ip地址+端口,局域网, 不要想的那么复杂) 如果说 我搞个虚拟串口的话 是不是 我直接操作虚拟串口就可以了呢(我直接给串口发数据,然后直接使用咱们的上面代码就可以搞定了吧。)
- 如果说是GPRS呢? wifi我可以处理 你外网我当然可以处理 同理 在云服务器上嫁接个虚拟串口 完全ok。
- 补充一点:wifi和GPRS都可以理解为TCP协议。
先给你们个虚拟串口工具的直通车
V-COM虚拟串口工具
这个工具的话 在使用中 如果说 你删除串口的话 还提示串口被占用的话 其他的不要多想 直接去服务里面找到v-com-Service 枪杀了它 就OK了 或者重启当前服务也可以
补充: 其他人都不知道 这可是我自己研究出来的。啧啧
不多比比了 看效果
解释下 咱们发送命令是怎么产生
02 03 00 01 00 04 15 FA
02对应的是咱们java的
modbusClient.setUnitIdentifier((byte)1);也就是DTU的id
03 是功能码 对应咱们的
modbusClient.ReadHoldingRegisters (只要是这个方法的就是03)
00 01 对应的是咱们的
modbusClient.ReadHoldingRegisters(1, 4)的第一个参数 也就是寄存器的起始地址
00 04 对应的是咱们的
modbusClient.ReadHoldingRegisters(1, 4)的第二个参数 也就是读取寄存器的长度 物联网的寄存器也就是软件的内存地址 可以这样理解。
15 FA 对CRC校验码 是根据 02 03 00 01 00 04 这些数据 生成的 就类似于微信官方接口的凭证
DTU返回的数据(02 03 08 00 00 07 79 00 01 80 d3 77 73)解释:
02 03 不解释了
08代表的是数据是后面的8个字节 00 00 07 79 00 01 80 d3 4个对应一个值 这些都是16进制 需要转化(放心,会把我写工具类给你 你拿去用就好。)
77 73 CRC校验码
最后 把写的工具类给你们吧 针对于modbus协议 基本上都使用的
public static String getAlValue(int al1High, int al1Low) {int highAl1 = 0;int lowAl1 = 0;if (al1High >= 0) {highAl1 = al1High * 65536;System.out.println("highAl1的值为:" + highAl1);} else {highAl1 = Integer.valueOf(getAlHex(al1High));System.out.println("highAl1的值为:" + highAl1);}if (al1Low >= 0) {lowAl1 = al1Low;System.out.println("lowAl1的值为:" + lowAl1);} else {lowAl1 = Integer.valueOf(getAlHex(al1Low));System.out.println("lowAl1的值为:" + lowAl1);}return String.valueOf(highAl1 + lowAl1);}
private static String getAlHex(int lowOrder) {// 去掉符号位lowOrder = Math.abs(lowOrder);// 转为2进制String al1Str = Integer.toBinaryString(lowOrder);String zorn = "";if (al1Str.length() < 16) {for (int i = 0; i< 16 - al1Str.length(); i++) {zorn += "0";}}al1Str = zorn + al1Str;/*** * 转为数组 遍历循环 取补码*/// 转为数组String[] alArrStr = al1Str.split("");// 先转反码 再转为补码String str = getComplement(alArrStr);// 转为10进制int bitStr = Integer.parseInt(str, 2);// 返回16进制return String.valueOf(bitStr);}
private static String getComplement (String[] alArrStr) {StringBuilder str = new StringBuilder();// 遍历 获取反码for (int i = 0; i < alArrStr.length; i++) {if (MeterConstant.BIT_ZERO_FLAG.equals(alArrStr[i])) {str.append(MeterConstant.BIT_ONE_FLAG);} else {str.append(MeterConstant.BIT_ZERO_FLAG);}}String[] code = str.toString().split("");Boolean isCarry = false;// 再去补码for (int i = code.length - 1; i < code.length; i--) {if (MeterConstant.BIT_ZERO_FLAG.equals(code[i])) {if (isCarry) {code[i] = MeterConstant.BIT_ONE_FLAG;isCarry = false;}break;} else {code[i] = MeterConstant.BIT_ZERO_FLAG;isCarry = true;}}return org.apache.commons.lang3.StringUtils.join(code);}
这是我项目中的数据读取效果。好好看下 应该可以看懂
工具类 写的有点乱,也有点low 也懒得改了 但是绝对好用。就到这里吧 如果感觉有用的话 就打赏下小弟吧。