依赖
<dependency>
<groupId>com.intelligt.modbus</groupId>
<artifactId>jlibmodbus</artifactId>
<version>1.2.9.7</version>
</dependency>
public interface ModbusEventListener {
int[] readHoldingRegisterRange(int offset, int quantity);
int[] readInputRegisterRange(int offset, int quantity);
void onWriteToSingleCoil(int address, boolean value);
void onWriteToMultipleCoils(int address, int quantity, boolean[] values);
void onWriteToSingleHoldingRegister(int address, int value);
void onWriteToMultipleHoldingRegisters(int address, int quantity, int[] values);
}
import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.data.ModbusHoldingRegisters;
import com.intelligt.modbus.jlibmodbus.exception.IllegalDataAddressException;
import com.intelligt.modbus.jlibmodbus.exception.IllegalDataValueException;
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 org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
//springboot启动时创建tcp slave
@Component
public class ModbusSlaveUtil implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
Thread.sleep(10000);
new Thread(new Runnable() {
@Override
public void run() {
createSalve();
}
}).start();
}
// public static void main(String[] args) {
// ModbusSlaveUtil ModbusSlaveUtil = new ModbusSlaveUtil();
// ModbusSlaveUtil.createSalve();
// }
private static int[] arr = new int[]{0, 0};
public static ModbusSlave slave;
public void createSalve() {
try {
initSlave();
System.out.println("slave start...........");
createDataHolder();
closeSlave();
} catch (Exception e) {
System.out.println("启动异常........");
}
}
public static void initSlave() throws UnknownHostException, ModbusIOException {
TcpParameters tcpParameters = new TcpParameters();// 设置从机TCP参数
InetAddress adress = InetAddress.getByName("127.0.0.1");// 设置TCP的ip地址
// getLocalHost()返回的是本机地址
tcpParameters.setHost(InetAddress.getLocalHost());
// tcpParameters.setHost(adress); // 为从机TCP设置上述ip地址参数
// 设置从机TCP的是否长连接,通俗点讲就是一直保持连接,一次连接完下次就不要在连接了
tcpParameters.setKeepAlive(true);
tcpParameters.setPort(Modbus.TCP_PORT);// 设置从机TCP的端口
// 创建一个从机
slave = ModbusSlaveFactory.createModbusSlaveTCP(tcpParameters);
// 设置控制台输出主机和从机命令交互日志
Modbus.setLogLevel(Modbus.LogLevel.LEVEL_DEBUG);
}
public void createDataHolder() throws ModbusIOException {
// 创建从机的寄存器
MyOwnDataHolder dh = new MyOwnDataHolder();
// 为从机寄存器添加监听事件,这里的监听事件主要是主机如果发送写命令修改从机则控制台输出
dh.addEventListener(new ModbusEventListener() {
@Override
public int[] readHoldingRegisterRange(int offset, int quantity) {
System.out.println("readHoldingRegisterRange: 读取信息 offset = " + offset + ";quantity" + quantity);
try {
updateHoldingRegisters(offset, quantity);
} catch (Exception e) {
e.printStackTrace();
}
return arr;
}
@Override
public int[] readInputRegisterRange(int offset, int quantity) {
System.out.println("readInputRegisterRange: 读取信息 offset = " + offset + ";quantity" + quantity);
try {
updateInputRegisters(offset, quantity);
} catch (Exception e) {
e.printStackTrace();
}
return arr;
}
@Override
public void onWriteToSingleCoil(int address, boolean value) {
System.out
.print("onWriteToSingleCoil: address " + address + ", value " + value);
}
@Override
public void onWriteToMultipleCoils(int address, int quantity, boolean[] values) {
System.out.print("onWriteToMultipleCoils: address " + address + ", quantity "
+ quantity);
}
@Override
public void onWriteToSingleHoldingRegister(int address, int value) {
System.out.print("onWriteToSingleHoldingRegister: address " + address
+ ", value " + value);
}
@Override
public void onWriteToMultipleHoldingRegisters(int address, int quantity,
int[] values) {
System.out.print("onWriteToMultipleHoldingRegisters: address " + address
+ ", quantity " + quantity);
}
});
// 为从机设置寄存器
slave.setDataHolder(dh);
// 设置从机的读超时时间,建议主机读的超时时间小于该值
slave.setReadTimeout(15000);
// 为从机设置从机服务地址slaveid
slave.setServerAddress(1);
// 开启从机监听事件,必须要这一句
slave.listen();
}
public static void closeSlave() throws InterruptedException, ModbusIOException {
//这部分代码主要是设置Java虚拟机关闭的时候需要做的事情,即本程序关闭的时候需要做的事情,直接使用即可
if (slave.isListening()) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
synchronized (slave) {
slave.notifyAll();
}
}));
synchronized (slave) {
slave.wait();
}
slave.shutdown();
System.out.println("slave shutdown........");
}
}
public void updateHoldingRegisters(int offset, int quantity) throws IllegalDataAddressException, IllegalDataValueException {
List<Float> list = Arrays.asList(10.1f, 20.3f, 89.5f, 77.353f);
ModbusHoldingRegisters hr = new ModbusHoldingRegisters(50000);
// 修改数值寄存器对应位置的值,第一个参数代表寄存器地址,第二个代表修改的数值
//hr.set有几个方法,根据自己要赋值的数据类型选择,此处示例的是赋值float类型,一个float是4个字节,32bit,对应2个寄存器所以i*2
for (int i = 0; i < list.size(); i++) {
hr.setFloat32At(i * 2, list.get(i));
}
hr.setInt16At(42, 0x64);
hr.setInt16At(43, 50);
hr.setInt16At(2200, 0x2000);
slave.getDataHolder().setHoldingRegisters(hr);
}
public void updateInputRegisters(int offset, int quantity) throws IllegalDataAddressException, IllegalDataValueException, ModbusIOException {
List<Float> list = Arrays.asList(10.1f, 20.3f, 89.5f, 77.353f);
ModbusHoldingRegisters hr = new ModbusHoldingRegisters(10000);
// 修改数值寄存器对应位置的值,第一个参数代表寄存器地址,第二个代表修改的数值
for (int i = 0; i < list.size(); i++) {
hr.setFloat32At(i * 2, list.get(i));
}
slave.getDataHolder().setInputRegisters(hr);
}
}
import com.intelligt.modbus.jlibmodbus.data.DataHolder;
import com.intelligt.modbus.jlibmodbus.exception.IllegalDataAddressException;
import com.intelligt.modbus.jlibmodbus.exception.IllegalDataValueException;
import java.util.ArrayList;
import java.util.List;
public class MyOwnDataHolder extends DataHolder {
final List<ModbusEventListener> modbusEventListenerList = new ArrayList<ModbusEventListener>();
public MyOwnDataHolder() {
// you can place the initialization code here
/*
* something like that: setHoldingRegisters(new
* SimpleHoldingRegisters(10)); setCoils(new Coils(128)); ... etc.
*/
}
public void addEventListener(ModbusEventListener listener) {
modbusEventListenerList.add(listener);
}
public boolean removeEventListener(ModbusEventListener listener) {
return modbusEventListenerList.remove(listener);
}
@Override
public int[] readHoldingRegisterRange(int offset, int quantity) throws IllegalDataAddressException {
for (ModbusEventListener l : modbusEventListenerList) {
l.readHoldingRegisterRange(offset, quantity);
}
return super.readHoldingRegisterRange(offset, quantity);
}
@Override
public int[] readInputRegisterRange(int offset, int quantity) throws IllegalDataAddressException{
for (ModbusEventListener l : modbusEventListenerList) {
l.readInputRegisterRange(offset, quantity);
}
return super.readInputRegisterRange(offset, quantity);
}
@Override
public void writeHoldingRegister(int offset, int value) throws IllegalDataAddressException,
IllegalDataValueException {
for (ModbusEventListener l : modbusEventListenerList) {
l.onWriteToSingleHoldingRegister(offset, value);
}
super.writeHoldingRegister(offset, value);
}
@Override
public void writeHoldingRegisterRange(int offset, int[] range)
throws IllegalDataAddressException, IllegalDataValueException {
for (ModbusEventListener l : modbusEventListenerList) {
l.onWriteToMultipleHoldingRegisters(offset, range.length, range);
}
super.writeHoldingRegisterRange(offset, range);
}
@Override
public void writeCoil(int offset, boolean value) throws IllegalDataAddressException,
IllegalDataValueException {
for (ModbusEventListener l : modbusEventListenerList) {
l.onWriteToSingleCoil(offset, value);
}
super.writeCoil(offset, value);
}
@Override
public void writeCoilRange(int offset, boolean[] range) throws IllegalDataAddressException,
IllegalDataValueException {
for (ModbusEventListener l : modbusEventListenerList) {
l.onWriteToMultipleCoils(offset, range.length, range);
}
super.writeCoilRange(offset, range);
}
}