概念
Modbus是一种串行通信协议,Modbus协议目前存在用于串口、以太网以及其他支持互联网协议的网络的版本。
大多数Modbus设备通信通过串口EIA-485物理层进行。
通讯格式
| 地址域 | 功能码 | 数据 | CRC校验(低字节在前) |
|---|---|---|---|
| 1字节 | 1字节 | N字节 | 2字节 |
功能码说明
实际用途中常用的功能码有:
- 0x03用来读取单片机寄存器的数据
- 0x06用来给单片机写入数据
功能码0x03:读单个或多个保持寄存器
| 设备地址(1字节) | 功能码(1字节) | 寄存器起始地址(2字节) | 寄存器数量(2字节) | CRC校验(2字节) |
|---|---|---|---|---|
| XX | 03 | XX XX | XX XX | XX XX |
响应:
| 设备地址(1字节) | 功能码(1字节) | 数据长度(2字节) | 数据(N字节) | CRC校验(2字节) |
|---|---|---|---|---|
| XX | 03 | XX XX | N字节 | XX XX |
| 设备地址(1字节) | 功能码(1字节) | 数据长度(2字节) | 数据(N字节) | CRC校验(2字节) |
|---|---|---|---|---|
| 01 | 03 | 00 01 | 00 01 | D5 CA |
查询设备类型响应
| 设备地址(1字节) | 功能码(1字节) | 数据长度(2字节) | 数据(N字节) | CRC校验(2字节) |
|---|---|---|---|---|
| 01 | 03 | 02 | 00 21 | 78 5C |
功能码0x06:写单个寄存器
| 设备地址(1字节) | 功能码(1字节) | 寄存器地址(2字节) | 数据(N字节) | CRC校验(2字节) |
|---|---|---|---|---|
| XX | 06 | XX XX | N字节 | XX XX |
响应:
| 设备地址(1字节) | 功能码(1字节) | 寄存器地址(2字节) | 数据(N字节) | CRC校验(2字节) |
|---|---|---|---|---|
| XX | 06 | XX XX | N字节 | XX XX |
| 设备地址(1字节) | 功能码(1字节) | 寄存器地址(2字节) | 数据(N字节) | CRC校验(2字节) |
|---|---|---|---|---|
| 01 | 06 | 00 14 | 00 00 | C9 CE |
Java版modbus协议代码:
package com.wrs.project.modbus; import java.util.ArrayList; import java.util.List; public class ModbusUtils { / * 读指令 * @param deviceAddress 设备地址 * @param registerAddress 寄存器起始地址 * @param registerCount 寄存器个数 * @return */ public static byte[] getReadModbus(int deviceAddress, int registerAddress, int registerCount) { int registerLow = registerAddress & 0xFF; int registerHigh = registerAddress >>> 8; int countLow = registerCount & 0xFF; int countHigh = registerCount >>> 8; int[] data = new int[]{registerHigh, registerLow, countHigh, countLow}; byte[] sendData = getModbusData(deviceAddress, 0x03, data); return sendData; } / * 写指令 * @param deviceAddress 设备地址 * @param registerAddress 寄存器起始地址 * @param writeData 寄存器个数 * @return */ public static byte[] getWriteModbus(int deviceAddress, int registerAddress, int[] writeData) { int registerLow = registerAddress & 0xFF; int registerHigh = registerAddress >>> 8; int[] data = new int[writeData.length + 2]; data[0] = registerHigh; data[1] = registerLow; for (int i = 0; i < writeData.length; i ++) { data[i + 2] = writeData[i]; } byte[] sendData = getModbusData(deviceAddress, 0x06, data); return sendData; } public static List
isValidModbusResponseData(List
list) { if (null != list && list.size() >= 4) { int size = list.size(); int leng = ByteUtils.byteToInt(list.get(2)); int totalSize = leng + 5; if (size < totalSize) { return null; } List tempList = list.subList(0, totalSize - 2); byte[] tempData = ArrayUtils.listTobyte(tempList); int crc = CRCUtils.getCRC(tempData); int low = crc & 0xFF; int high = crc >>> 8; byte lowData = list.get(totalSize - 2); byte hightData = list.get(totalSize - 1); if (low == ByteUtils.byteToInt(lowData) && high == ByteUtils.byteToInt(hightData)) { return list.subList(0, totalSize); } else { return null; } } else { return null; } } public static byte[] getModbusData(int address, int function, int[] data) { int leng = 2; if (null != data) { leng += data.length; } byte[] tempData = new byte[leng]; tempData[0] = ByteUtils.intToByte(address); tempData[1] = ByteUtils.intToByte(function); if (null != data) { for (int i = 0; i < data.length; i++) { tempData[i + 2] = ByteUtils.intToByte(data[i]); } } int crc = CRCUtils.getCRC(tempData); int low = crc & 0xFF; int high = crc >>> 8; List list = new ArrayList(); list.addAll(ArrayUtils.byteToList(tempData)); list.add(ByteUtils.intToByte(low)); list.add(ByteUtils.intToByte(high)); return ArrayUtils.listTobyte(list); } }
项目源码:https://codechina.csdn.net/it1/modbusproject
如果觉得可以就点个?吧,欢迎粉丝收藏,土豪打赏,您的关注就是我们创作的动力!
读者有什么想看的相关技术篇章,欢迎评论留言!
交流群:
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/226643.html原文链接:https://javaforall.net
