Modbus Java工具包学习记录
Modbus Java工具包
本文承接上文Modbus通信工具学习记录,我们已经了解编程过程中可能用到的小工具,本次介绍三个java项目常用Modbus协议jar包。只做参考,有能力的话还是建议根据需求自行编写协议工具类
- modbus4j:支持Modbus-RTU、Modbus-ASCI和Modbus-TCP三种协议,支持Modbus-RTU over Serial 、Modbus-RTU over TCP/UDP 、Modbus-ASCII over Serial 和 Modbus-TCP over TCP/UDP。但是该工具是同步的不支持异步,实时性要求不强可以使用。
- jlibmodbus:支持Modbus-RTU和Modbus-TCP两种协议,支持Modbus-RTU over Serial 、Modbus-RTU over TCP、Modbus-TCP over TCP,Modbus-TCP内部通过socket实现支持异步。Modbus-RTU Serial通过RXTX实现。
- modbus-master-tcp:支持Modbus-TCP一种协议,支持Modbus-TCP over TCP,内部通过netty实现支持异步。可以执行扩展使其支持Modbus-RTU over TCP和Modbus-RTU over Serial
- 以上三个工具包的所有连接都没有断线重连功能,所以使用时需要自行解决断线重连问题。
Modbus4J
maven依赖
<dependency>
<groupId>com.infiniteautomation</groupId>
<artifactId>modbus4j</artifactId>
<version>3.0.3</version>
</dependency>
read
/**
*
* 创建人:AFatOrange
*
*/
public class Modbus4jReadUtils {
static Log log = LogFactory.getLog(Modbus4jReadUtils.class);
static ModbusFactory modbusFactory;
static {
if (modbusFactory == null) {
modbusFactory = new ModbusFactory();
}
}
/**
* 获取master
*
* @return
* @throws ModbusInitException
*/
public static ModbusMaster getTCPMaster() throws ModbusInitException {
IpParameters ipParams = new IpParameters();
ipParams.setHost("localhost");
ipParams.setPort(502);
//这个属性确定了协议帧是否是通过tcp封装的RTU结构,采用modbus tcp/ip时,要设为false, 采用modbus rtu over tcp/ip时,要设为true
// ipParams.setEncapsulated(true);
// UDP 协议
ModbusMaster master = modbusFactory.createUdpMaster(ipParams);
// TCP 协议
// ModbusMaster master = modbusFactory.createTcpMaster(ipParams, false);
master.init();
return master;
}
public static ModbusMaster getMaster() throws ModbusInitException {
SerialPortWrapper serialParams = new SerialPortWrapperImpl("COM2", 9600, 8, 1, 0, 0, 0);
ModbusMaster master = modbusFactory.createRtuMaster(serialParams); // RTU 协议
// ModbusMaster master = modbusFactory.createAsciiMaster(serialParams); // ASCII 协议
master.init();
return master;
}
/**
* 批量读取使用方法
* 可以理解为读取一段,再根据需求截取出.只发出了一个指令一个回复.
* batch.addLocator(0, BaseLocator.holdingRegister(1, 7, DataType.TWO_BYTE_INT_UNSIGNED));
* batch.addLocator(1, BaseLocator.holdingRegister(1, 5, DataType.TWO_BYTE_INT_UNSIGNED));
* 发送指令格式是从5寄存器开始读取3个长度,返回5后两个字节\和7后两个字节
*
* @throws ModbusTransportException
* @throws ErrorResponseException
* @throws ModbusInitException
*/
public static void batchRead() throws ModbusTransportException, ErrorResponseException, ModbusInitException {
BatchRead<Integer> batch = new BatchRead<Integer>();
batch.addLocator(0, BaseLocator.holdingRegister(1, 9, DataType.TWO_BYTE_INT_UNSIGNED));
batch.addLocator(1, BaseLocator.holdingRegister(1, 5, DataType.TWO_BYTE_INT_UNSIGNED));
ModbusMaster master = getMaster();
batch.setContiguousRequests(false);
BatchResults<Integer> results = master.send(batch);
log.info("results.getValue(0):"+results.getValue(0));
log.info("results.getValue(1):"+results.getValue(1));
}
/**
* 读保持寄存器上的内容
* @param master 主站
* @param slaveId 从站地址
* @param start 起始地址的偏移量
* @param len 待读寄存器的个数
*/
private static void readHoldingRegistersTest(int slaveId, int start, int len) throws ModbusTransportException, ErrorResponseException, ModbusInitException {
try {
ModbusMaster master = getMaster();
ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, start, len);
ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse)master.send(request);
if (response.isException()) {
log.info("Exception response: message=" + response.getExceptionMessage());
} else {
log.info(Arrays.toString(response.getShortData()));
short[] list = response.getShortData();
for (int i = 0; i < list.length; i++) {
log.info(list[i] + " ");
}
}
} catch (ModbusTransportException e) {
e.printStackTrace();
}
}
/**
* 测试
*
* @param args
*/
public static void main(String[] args) {
try {
// 批量读取
batchRead();
readHoldingRegistersTest(1, 0, 2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
write
/**
*
* 创建人:AFatOrange
*
*/
public class Modbus4jWriteUtils {
static Log log = LogFactory.getLog(Modbus4jWriteUtils.class);
static ModbusFactory modbusFactory;
static {
if (modbusFactory == null) {
modbusFactory = new ModbusFactory();
}
}
/**
* 获取tcpMaster
*
* @return
* @throws ModbusInitException
*/
public static ModbusMaster getTCPMaster() throws ModbusInitException {
IpParameters params = new IpParameters();
params.setHost("localhost");
params.setPort(502);
// ipParams.setEncapsulated(true);
// UDP 协议
ModbusMaster master = modbusFactory.createUdpMaster(ipParams);
// TCP 协议
// ModbusMaster master = modbusFactory.createTcpMaster(ipParams, false);
return tcpMaster;
}
public static ModbusMaster getMaster() throws ModbusInitException {
SerialPortWrapper serialParams = new SerialPortWrapperImpl("COM2", 9600, 8, 1, 0, 0, 0);
ModbusMaster master = modbusFactory.createRtuMaster(serialParams);
// ModbusMaster master = modbusFactory.createAsciiMaster(serialParams);
master.init();
return master;
}
/**
* 写入数字类型的模拟量(如:写入Float类型的模拟量、Double类型模拟量、整数类型Short、Integer、Long)
*
* @param slaveId
* @param offset
* @param value
* 写入值,Number的子类,例如写入Float浮点类型,Double双精度类型,以及整型short,int,long
* @param registerCount
* ,com.serotonin.modbus4j.code.DataType
* @throws ModbusTransportException
* @throws ErrorResponseException
* @throws ModbusInitException
*/
public static void writeHoldingRegister(int slaveId, int offset, Number value, int dataType)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 获取master
ModbusMaster tcpMaster = getMaster();
// 类型
BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, dataType);
tcpMaster.setValue(locator, value);
}
public static void main(String[] args) {
try {
//写模拟量
writeHoldingRegister(1,0, 10, DataType.FOUR_BYTE_INT_UNSIGNED);
} catch (Exception e) {
e.printStackTrace();
}
}
}
JLibModbus
maven依赖
<dependency>
<groupId>com.intelligt.modbus</groupId>
<artifactId>jlibmodbus</artifactId>
<version>1.2.9.7</version>
</dependency>
read TCP
/**
*
* 创建人:AFatOrange
*
*/
public class JlibmodbusTCPUtils {
static Log log = LogFactory.getLog(JlibmodbusTCPUtils.class);
public void modbusMasterTCPInit() {
try {
// 设置主机TCP参数
TcpParameters tcpParameters = new TcpParameters();
// 设置TCP的ip地址
InetAddress adress = InetAddress.getByName("127.0.0.1");
tcpParameters.setHost(adress);
// TCP设置长连接
tcpParameters.setKeepAlive(true);
// TCP设置端口,这里设置是默认端口502
tcpParameters.setPort(Modbus.TCP_PORT);
// 创建一个主机
ModbusMaster master = ModbusMasterFactory.createModbusMasterTCP(tcpParameters);
Modbus.setAutoIncrementTransactionId(true);
int serverAddress = 1; // 从机地址
int startAddress = 0; // 寄存器读取开始地址
int quantity = 10; // 读取的寄存器数量
try {
if (!master.isConnected()) {
master.connect(); // 开启连接
}
// 读取对应从机的数据,readInputRegisters读取的写寄存器,功能码04
// int[] registerValues = master.readInputRegisters(serverAddress, startAddress, quantity);
// 每两位byte转为无符号整型
int[] readHoldingRegistersValues = master.readHoldingRegisters(serverAddress, startAddress, quantity);
// 控制台输出
for (int i = 0; i < readHoldingRegistersValues.length; i++) {
int value = readHoldingRegistersValues[i];
log.info("Index: " + i + ", Value: " + value);
}
} catch (ModbusProtocolException e) {
e.printStackTrace();
} catch (ModbusNumberException e) {
e.printStackTrace();
} catch (ModbusIOException e) {
e.printStackTrace();
} finally {
try {
master.disconnect();
} catch (ModbusIOException e) {
e.printStackTrace();
}
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JlibmodbusTCPUtils jlibmodbusUtils = new JlibmodbusTCPUtils();
jlibmodbusUtils.modbusMasterTCPInit();
}
}
read RTU
/**
*
* 创建人:AFatOrange
*
*/
public class JlibmodbusRTUUtils {
static Log log = LogFactory.getLog(JlibmodbusRTUUtils.class);
public void modbusMasterRTUInit() {
try {
// 设置主机TCP参数
SerialParameters serialParameters = new SerialParameters();
serialParameters.setDevice("COM2");
serialParameters.setBaudRate(SerialPort.BaudRate.BAUD_RATE_9600);
// serialParameters.setDataBits(8);
// serialParameters.setStopBits(1);
// serialParameters.setParity(SerialPort.Parity.NONE);
// 创建一个主机
ModbusMaster master = ModbusMasterFactory.createModbusMasterRTU(serialParameters);
Modbus.setAutoIncrementTransactionId(true);
int serverAddress = 1; // 从机地址
int startAddress = 0; // 寄存器读取开始地址
int quantity = 10; // 读取的寄存器数量
try {
if (!master.isConnected()) {
master.connect(); // 开启连接
}
// 读取对应从机的数据,readInputRegisters读取的写寄存器,功能码04
// int[] registerValues = master.readInputRegisters(serverAddress, startAddress, quantity);
// 每两位byte转为无符号整型
boolean[] readCoilsValues = master.readCoils(serverAddress, startAddress, quantity);
// 控制台输出
for (int i = 0; i < readCoilsValues.length; i++) {
boolean value = readCoilsValues[i];
log.info("Index: " + i + ", Value: " + value);
}
int[] readHoldingRegistersValues = master.readHoldingRegisters(serverAddress, startAddress, quantity);
// 控制台输出
for (int i = 0; i < readHoldingRegistersValues.length; i++) {
int value = readHoldingRegistersValues[i];
log.info("Index: " + i + ", Value: " + value);
}
} catch (ModbusProtocolException e) {
e.printStackTrace();
} catch (ModbusNumberException e) {
e.printStackTrace();
} catch (ModbusIOException e) {
e.printStackTrace();
} finally {
try {
master.disconnect();
} catch (ModbusIOException e) {
e.printStackTrace();
}
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JlibmodbusRTUUtils jlibmodbusUtils = new JlibmodbusRTUUtils();
jlibmodbusUtils.modbusMasterRTUInit();
}
}
modbus-master-tcp
maven依赖
<dependency>
<groupId>com.digitalpetri.modbus</groupId>
<artifactId>modbus-master-tcp</artifactId>
<version>1.1.0</version>
</dependency>
read TCP
/**
*
* 创建人:AFatOrange
*
*/
public class ModbusMasterTCPReadUtils {
static Log log = LogFactory.getLog(ModbusMasterTCPReadUtils.class);
static ModbusTcpMaster master;
/**
* 获取TCP协议的Master
*
* @return
*/
public static void initModbusTcpMaster() {
if (master == null) {
// 创建配置
ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder("localhost").setPort(502).build();
master = new ModbusTcpMaster(config);
}
}
/***
* 释放资源
*/
public static void release() {
if (master != null) {
master.disconnect();
}
Modbus.releaseSharedResources();
}
/**
* 读取HoldingRegister数据
*
* @param address
* 寄存器地址
* @param quantity
* 寄存器数量
* @param unitId
* id
* @return 读取结果
* @throws InterruptedException
* 异常
* @throws ExecutionException
* 异常
*/
public static Number readHoldingRegisters(int address, int quantity, short unitId)
throws InterruptedException, ExecutionException {
Number result = null;
CompletableFuture<ReadHoldingRegistersResponse> future = master
.sendRequest(new ReadHoldingRegistersRequest(address, quantity), unitId);
// 同步返回
ReadHoldingRegistersResponse readHoldingRegistersResponse = future.get();
if (readHoldingRegistersResponse != null) {
ByteBuf buf = readHoldingRegistersResponse.getRegisters();
result = buf.readFloat();
ReferenceCountUtil.release(readHoldingRegistersResponse);
}
// 异步返回
// future.whenComplete((readHoldingRegistersResponse, ex) -> {
// if (readHoldingRegistersResponse != null) {
// ByteBuf buf = readHoldingRegistersResponse.getRegisters();
// Number num = buf.readFloat();
// ReferenceCountUtil.release(readHoldingRegistersResponse);
// System.out.println("num:"+num);
// } else {
// // 任务异常结束
// future.completeExceptionally(ex);
// }
// });
return result;
}
public static void main(String[] args) {
try {
// 初始化资源
initModbusTcpMaster();
// 读取模拟量
log.info("readHoldingRegisters1:"+readHoldingRegisters(0, 2, (short)1));
log.info("readHoldingRegisters2:"+readHoldingRegisters(2, 2, (short)1));
log.info("readHoldingRegisters3:"+readHoldingRegisters(4, 2, (short)1));
// 释放资源
release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
write TCP
/**
*
* 创建人:AFatOrange
*
*/
public class ModbusMasterTCPWriteUtils {
static Log log = LogFactory.getLog(ModbusMasterTCPWriteUtils.class);
static ModbusTcpMaster master;
/**
* 获取TCP协议的Master
*
* @return
*/
public static void initModbusTcpMaster() {
if (master == null) {
// 创建配置
ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder("localhost").setPort(502).build();
master = new ModbusTcpMaster(config);
}
}
/***
* 释放资源
*/
public static void release() {
if (master != null) {
master.disconnect();
}
Modbus.releaseSharedResources();
}
public static Number writeHoldingRegisters(int address, int value, short unitId)
throws InterruptedException, ExecutionException{
Number result = null;
CompletableFuture<WriteSingleRegisterResponse> future = master
.sendRequest(new WriteSingleRegisterRequest(address, value), unitId);
// 同步返回
WriteSingleRegisterResponse writeSingleRegisterResponse = future.get();
if (writeSingleRegisterResponse != null) {
result = writeSingleRegisterResponse.getValue();
ReferenceCountUtil.release(writeSingleRegisterResponse);
}
return result;
}
public static void main(String[] args) {
try {
// 初始化资源
initModbusTcpMaster();
log.info("writeHoldingRegisters1:"+writeHoldingRegisters(0, 12, 1));
// 释放资源
release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
后记
三个工具jar包截至发文时都是长时间无更新的状态,所以只作为了解学习,实际与设备通信时最好还是自行编写Modbus通信驱动
本文只是记录本人学习过程中的理解,可能有部分内容有纰漏,望各位不吝赐教。