概述
使用Java创建ModbusMaster实例和ModbusSlave实例,并且ModbusMaster实例可以读取ModbusSlave实例中Holding寄存器的值
1.引入依赖
出于简便,直接使用springboot引入jlibmodbus组件
<dependency>
<groupId>com.intelligt.modbus</groupId>
<artifactId>jlibmodbus</artifactId>
<version>1.2.9.7</version>
</dependency>
<!-- 方便构造随机值 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<!-- 把字节数据转成易懂的16进制数据 -->
<dependency>
<groupId>org.apache.commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
2. ModbusSlave实例
import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.data.DataHolder;
import com.intelligt.modbus.jlibmodbus.data.ModbusHoldingRegisters;
import com.intelligt.modbus.jlibmodbus.exception.ModbusIOException;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlave;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlaveFactory;
import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;
import com.intelligt.modbus.jlibmodbus.utils.FrameEvent;
import com.intelligt.modbus.jlibmodbus.utils.FrameEventListener;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.RandomUtils;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* ModbusSlaveExample
*/
public class ModbusSlaveExample {
public static void main(String[] args) throws Exception {
int sizeOfHoldingRegisters = 10;
// 获取ModbusSlave实例
ModbusSlave modbusSlave = getModbusSlave("127.0.0.1", 9527, sizeOfHoldingRegisters);
// 随机设置寄存器的值
println("开始随机设置寄存器的值");
for (int i = 0; i < sizeOfHoldingRegisters; i++) {
int val = RandomUtils.nextInt(0, 1000);
modbusSlave.getDataHolder().writeHoldingRegister(i, val);
println("地址偏移量:" + i + " 值:" + val);
}
println("完成随机设置寄存器的值");
// 停止ModbusSlave实例
close(modbusSlave);
}
private static void close(ModbusSlave slave) throws InterruptedException, ModbusIOException {
if (slave.isListening()) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
synchronized (slave) {
slave.notifyAll();
}
}));
synchronized (slave) {
slave.wait();
}
slave.shutdown();
println("ModbusSlave停止完成");
}
}
/**
* @param host ModbusSlave IP
* @param port ModbusSlave端口
* @param sizeOfHoldingRegisters HoldingRegisters数量
* @return ModbusSlave实例
*/
private static ModbusSlave getModbusSlave(String host, Integer port, Integer sizeOfHoldingRegisters) throws UnknownHostException, ModbusIOException {
// modbus全局设置
Modbus.setLogLevel(Modbus.LogLevel.LEVEL_WARNINGS);
// 构造ModbusSlave
TcpParameters tcpParameters = new TcpParameters();
tcpParameters.setHost(InetAddress.getByName(host)); // 指定ModbusSlave地址
tcpParameters.setKeepAlive(true);
tcpParameters.setPort(port); // 指定ModbusSlave端口
ModbusSlave slave = ModbusSlaveFactory.createModbusSlaveTCP(tcpParameters);
DataHolder holder = new DataHolder();
holder.setHoldingRegisters(new ModbusHoldingRegisters(sizeOfHoldingRegisters));
slave.setDataHolder(holder);
slave.addListener(new FrameEventListener() {
@Override
public void frameSentEvent(FrameEvent event) {
// println("frame send event: " + Hex.encodeHexString(event.getBytes()));
}
@Override
public void frameReceivedEvent(FrameEvent event) {
// println("frame receive event: " + Hex.encodeHexString(event.getBytes()));
}
});
// 设置ModbusSlave的读超时时间,建议ModbusMaster的读超时时间小于该值
// slave.setReadTimeout(1500);
slave.setServerAddress(1); // ModbusSlave id
slave.listen();
println("ModbusSlave实例化完成");
return slave;
}
private static void println(String msg) {
System.out.println(">>> " + msg);
}
}
备注:如果在springboot中使用,可以通过@PostConstruct初始化ModbusSlave实例,并通过@PreDestroy销毁实例。销毁代码如下:
@PreDestroy
public void destroy() {
if (modbusSlave.isListening()) {
try {
modbusSlave.shutdown();
} catch (ModbusIOException e) {
log.error("modbus shutdown error");
}
}
}
3. ModbusMaster实例
import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.exception.ModbusIOException;
import com.intelligt.modbus.jlibmodbus.master.ModbusMaster;
import com.intelligt.modbus.jlibmodbus.master.ModbusMasterFactory;
import com.intelligt.modbus.jlibmodbus.msg.request.ReadHoldingRegistersRequest;
import com.intelligt.modbus.jlibmodbus.msg.response.ReadHoldingRegistersResponse;
import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;
import com.intelligt.modbus.jlibmodbus.utils.FrameEvent;
import com.intelligt.modbus.jlibmodbus.utils.FrameEventListener;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* ModbusMasterExample
*/
public class ModbusMasterExample {
public static void main(String[] args) throws Exception {
// 获取ModbusMaster实例
ModbusMaster master = getModbusMaster("127.0.0.1", 9527);
// 模拟请求
println("开始模拟请求并打印输出");
for (int i = 0; i < 2; i++) {
println("=====第" + (i + 1) + "遍=====");
// 读取多个Holding寄存器
ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest();
request.setTransactionId(i);
request.setProtocolId(Modbus.PROTOCOL_ID);
request.setServerAddress(1); // ModbusSlave id
int offset = 0;
request.setStartAddress(offset); // 每次请求起始地址(偏移量)
int quantity = 10; // 每次请求数量
request.setQuantity(quantity);
ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.processRequest(request);
// 打印输出
for (int j = 0; j < quantity; j++) {
int val = response.getHoldingRegisters().getInt16At(j);
println("地址偏移量:" + (offset + j) + " 值:" + val);
}
// 短暂暂停。注意:测试发现设置为1000毫秒时会出现后续请求失败
Thread.sleep(500L);
}
println("ModbusMaster停止完成");
}
/**
* @param host ModbusSlave IP
* @param port ModbusSlave端口
* @return ModbusMaster实例
*/
private static ModbusMaster getModbusMaster(String host, Integer port) throws UnknownHostException, ModbusIOException {
// modbus全局设置
Modbus.setLogLevel(Modbus.LogLevel.LEVEL_WARNINGS);
Modbus.setAutoIncrementTransactionId(true);
// 构造ModbusMaster
TcpParameters tcpParameters = new TcpParameters();
tcpParameters.setHost(InetAddress.getByName(host)); // 指定ModbusSlave地址
tcpParameters.setKeepAlive(true);
tcpParameters.setPort(port); // 指定ModbusSlave端口
ModbusMaster master = ModbusMasterFactory.createModbusMasterTCP(tcpParameters);
// master.setResponseTimeout(2000);
master.addListener(new FrameEventListener() {
@Override
public void frameSentEvent(FrameEvent event) {
// println("frame send event: " + Hex.encodeHexString(event.getBytes()));
}
@Override
public void frameReceivedEvent(FrameEvent event) {
// println("frame receive event: " + Hex.encodeHexString(event.getBytes()));
}
});
master.connect();
println("ModbusMaster实例化完成");
return master;
}
private static void println(String msg) {
System.out.println(">>> " + msg);
}
}
4. 执行结果
ModbusSlave输出如下:
>>> ModbusSlave实例化完成
>>> 开始随机设置寄存器的值
>>> 地址偏移量:0 值:498
>>> 地址偏移量:1 值:196
>>> 地址偏移量:2 值:701
>>> 地址偏移量:3 值:99
>>> 地址偏移量:4 值:681
>>> 地址偏移量:5 值:213
>>> 地址偏移量:6 值:855
>>> 地址偏移量:7 值:365
>>> 地址偏移量:8 值:848
>>> 地址偏移量:9 值:390
>>> 完成随机设置寄存器的值
ModbusMaster输出如下:
>>> ModbusMaster实例化完成
>>> 开始模拟请求并打印输出
>>> =====第1遍=====
>>> 地址偏移量:0 值:498
>>> 地址偏移量:1 值:196
>>> 地址偏移量:2 值:701
>>> 地址偏移量:3 值:99
>>> 地址偏移量:4 值:681
>>> 地址偏移量:5 值:213
>>> 地址偏移量:6 值:855
>>> 地址偏移量:7 值:365
>>> 地址偏移量:8 值:848
>>> 地址偏移量:9 值:390
>>> =====第2遍=====
>>> 地址偏移量:0 值:498
>>> 地址偏移量:1 值:196
>>> 地址偏移量:2 值:701
>>> 地址偏移量:3 值:99
>>> 地址偏移量:4 值:681
>>> 地址偏移量:5 值:213
>>> 地址偏移量:6 值:855
>>> 地址偏移量:7 值:365
>>> 地址偏移量:8 值:848
>>> 地址偏移量:9 值:390
>>> ModbusMaster停止完成