Modbus通讯协议——Java通过Jlibmodbus实现Modbus Master(主机)TCP/RTU的Read;Slave(从机)TCP/RTU的Write

混沌中的眼镜 2024-07-25 14:05:02 阅读 68

一、首先了解一下Java实现Modbus的三种jar包

只做参考,有能力的话还是建议根据需求自行编写协议工具类

1. modbus4: 支持Modbus-RTU、 Modbus-ASCl.Modbus-TCP三种协议,支持Modbus-RTU over Senal, Modbus.RTU over TCPUDP、 Modbus-ASCl over sera

和 Modbus-TCP over TCP/UDP。但是该工具是同步的不支持异步,实时性要求不强可以使用。

2. ililbmodbus:支持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和Moc

bus-RTU over Serial

以上三个工具包的所有连接都没有断线重连功能,所以使用时需要自行解决断线重

二、主要针对Jlibmodbus实现Modbus的主机与从机’

1、导入依赖

另附Maven仓库地址:https://mvnrepository.com/

<code> <!-- https://mvnrepository.com/artifact/com.intelligt.modbus/jlibmodbus -->

<dependency>

<groupId>com.intelligt.modbus</groupId>

<artifactId>jlibmodbus</artifactId>

<version>1.2.9.10</version>

</dependency>

2、Master主机模式:

1)、Modbus-TCP

import com.intelligt.modbus.jlibmodbus.Modbus;

import com.intelligt.modbus.jlibmodbus.master.ModbusMaster;

import com.intelligt.modbus.jlibmodbus.master.ModbusMasterFactory;

import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;

import java.math.BigDecimal;

import java.math.BigInteger;

import java.net.InetAddress;

public class JlibmodbusMasterTcpReader {

public static void main(String[] args) throws Exception {

TcpParameters tcpParameters = new TcpParameters();

tcpParameters.setHost(InetAddress.getByName("127.0.0.1"));

tcpParameters.setPort(502);

tcpParameters.setKeepAlive(true);

int[] num = {1};

for (int n : num){

int[] ints = new JlibmodbusMasterTcpReader().modbusReads(n,tcpParameters);

System.out.println(ints[0]);

int second = ints[0];

int first = ints[1];

System.out.println(ints[1]);

// for (int m : ints){

// System.out.print(m);

// }

//在进行字符串转化时,转化的16进制会存在缺少一位的情况,进行左侧补零操作

String hexStr = addZeroForStr(Integer.toHexString(first),4,1)+""+addZeroForStr(Integer.toHexString(second),4,1);

System.out.println(new BigDecimal(sfloat(hexStr)));

System.out.println();

}

}

public int[] modbusReads(int serverAddress, TcpParameters tcpParameters) throws Exception {

ModbusMaster master = ModbusMasterFactory.createModbusMasterTCP(tcpParameters);

master.setResponseTimeout(3000);

master.connect();

Modbus.setAutoIncrementTransactionId(true);

int[] result = master.readInputRegisters(serverAddress,0, 10);

master.disconnect();

return result;

}

//将字符串类型的16进制数据,转化为float字符串

private static String sfloat(String str){

Float value = Float.intBitsToFloat(new BigInteger(str, 16).intValue());

return String.valueOf(value);

}

/**

* 给字符串的左补0或右补0

* @param str 要处理的字符串

* @param length 补0后字符串总长度

* @return 返回补零字符串

*/

public static String addZeroForStr(String str, int length, int type) {

int strLen = str.length();

if (strLen < length) {

while (strLen < length) {

StringBuffer sb = new StringBuffer();

if(type==1){

// 左补0

sb.append("0").append(str);

}else if(type==2){

//右补0

sb.append(str).append("0");

}

str = sb.toString();

strLen = str.length();

}

}

return str;

}

}

2)、Modbus-RTU

import com.intelligt.modbus.jlibmodbus.Modbus;

import com.intelligt.modbus.jlibmodbus.master.ModbusMaster;

import com.intelligt.modbus.jlibmodbus.master.ModbusMasterFactory;

import com.intelligt.modbus.jlibmodbus.serial.*;

import java.io.*;

public class JlibmodbusMasterRtuReader {

public static void main(String[] args) throws Exception {

SerialParameters params = new SerialParameters();

params.setDevice("COM2"); // 串口名称

params.setBaudRate(SerialPort.BaudRate.getBaudRate(9600)); // 波特率

params.setDataBits(8); // 数据位

params.setStopBits(1); // 停止位

params.setParity(SerialPort.Parity.getParity(0)); // 无校验

ModbusMaster master = ModbusMasterFactory.createModbusMasterRTU(params);

Modbus.setAutoIncrementTransactionId(true);

master.connect();

int[] registers = master.readHoldingRegisters(1, 0, 10);

BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("C:\\Users\\user\\Desktop\\data.txt"));

for (int reg : registers){

System.out.println(reg);

bufferedWriter.write(reg + " ");

}

bufferedWriter.newLine();

bufferedWriter.close();

master.disconnect();

}

}

3、Slave-从机模式

1)、Modbus-TCP

import com.intelligt.modbus.jlibmodbus.Modbus;

import com.intelligt.modbus.jlibmodbus.data.DataHolder;

import com.intelligt.modbus.jlibmodbus.data.ModbusCoils;

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.slave.ModbusSlave;

import com.intelligt.modbus.jlibmodbus.slave.ModbusSlaveFactory;

import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;

import java.net.InetAddress;

import java.util.ArrayList;

import java.util.List;

public class JlibmodbusSlaveTcpWriter {

public static void main(String[] args) {

try {

// 设置从机TCP参数

TcpParameters tcpParameters = new TcpParameters();

// 设置TCP的ip地址

InetAddress address = InetAddress.getByName("127.0.0.1");

// getLocalHost()返回的是本机地址

// tcpParameters.setHost(InetAddress.getLocalHost());

// 为从机TCP设置上述ip地址参数

tcpParameters.setHost(address);

// 设置从机TCP的是否长连接,通俗点讲就是一直保持连接,一次连接完下次就不要在连接了

tcpParameters.setKeepAlive(true);

// 设置从机TCP的端口

tcpParameters.setPort(Modbus.TCP_PORT);

// 创建一个从机

ModbusSlave slave = ModbusSlaveFactory.createModbusSlaveTCP(tcpParameters);

// 设置控制台输出主机和从机命令交互日志

Modbus.setLogLevel(Modbus.LogLevel.LEVEL_DEBUG);

// 创建从机的寄存器

MyOwnDataHolder dh = new MyOwnDataHolder();

// 为从机寄存器添加监听事件,这里的监听事件主要是主机如果发送写命令修改从机则控制台输出

dh.addEventListener(new ModbusEventListener() {

@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(1500);

// 设置从机寄存器的03和04功能码对应的数值寄存器

ModbusHoldingRegisters hr = new ModbusHoldingRegisters(10);

// 修改数值寄存器对应位置的值,第一个参数代表寄存器地址,第二个代表修改的数值

hr.set(0, 12345);

hr.set(1, 54321);

// 设置从机寄存器的01和02功能码对应的位寄存器,即只有false和true值(或0和1)

ModbusCoils mc = new ModbusCoils(16);

// 设置对应位寄存器地址的位值

mc.set(0, true);

// 为从机设置04功能码对应的数值寄存器

slave.getDataHolder().setInputRegisters(hr);

// 为从机设置03功能码对应的数值寄存器

slave.getDataHolder().setHoldingRegisters(hr);

// 为从机设置01功能码对应的数值寄存器

// slave.getDataHolder().setCoils(mc);

// 为从机设置从机服务地址slaveid

slave.setServerAddress(1);

// 开启从机监听事件,必须要这一句

slave.listen();

//这部分代码主要是设置Java虚拟机关闭的时候需要做的事情,即本程序关闭的时候需要做的事情,直接使用即可

if (slave.isListening()) {

Runtime.getRuntime().addShutdownHook(new Thread() {

@Override

public void run() {

synchronized (slave) {

slave.notifyAll();

}

}

});

synchronized (slave) {

slave.wait();

}

/*

* using master-branch it should be #slave.close();

*/

slave.shutdown();

}

} catch (RuntimeException e) {

throw e;

} catch (Exception e) {

e.printStackTrace();

}

}

// 监听接口

public interface ModbusEventListener {

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);

}

// 寄存器类定义

public static 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 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);

}

}

}

2)、Modbus-RTU

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.IllegalDataAddressException;

import com.intelligt.modbus.jlibmodbus.exception.IllegalDataValueException;

import com.intelligt.modbus.jlibmodbus.exception.ModbusIOException;

import com.intelligt.modbus.jlibmodbus.serial.SerialParameters;

import com.intelligt.modbus.jlibmodbus.serial.SerialPort;

import com.intelligt.modbus.jlibmodbus.serial.SerialPortException;

import com.intelligt.modbus.jlibmodbus.slave.ModbusSlave;

import com.intelligt.modbus.jlibmodbus.slave.ModbusSlaveFactory;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

public class JlibmodbusSlaveRtuWriter {

public static void main(String[] args) throws SerialPortException, IllegalDataValueException, IllegalDataAddressException, ModbusIOException {

SerialParameters serialParameters = new SerialParameters();

serialParameters.setDevice("COM1");

serialParameters.setBaudRate(SerialPort.BaudRate.getBaudRate(9600));

serialParameters.setDataBits(8);

serialParameters.setStopBits(1);

serialParameters.setParity(SerialPort.Parity.NONE);

ModbusSlave modbusSlave = ModbusSlaveFactory.createModbusSlaveRTU(serialParameters);

modbusSlave.setReadTimeout(2400);

Modbus.setLogLevel(Modbus.LogLevel.LEVEL_DEBUG);

MyDataHolder myDataHolder = new MyDataHolder();

myDataHolder.addEventListener(new EventListeners() {

@Override

public void readHoldingRegister(int address) {

System.out.println("使用03功能码读取保持寄存器的数据 address = " + address);

}

@Override

public void readHoldingRegisterRange(int address, int quantity) {

try {

ModbusHoldingRegisters integers = updateHoldingRegisters(address, quantity);

modbusSlave.getDataHolder().setHoldingRegisters(integers);

}catch (Exception e){

e.printStackTrace();

}

System.out.println("使用03功能码范围读取保持寄存器的数据 address = " + address + " 读取寄存器个数:" + quantity);

}

@Override

public void writeHoldingRegister(int address, int value) throws IllegalDataValueException, IllegalDataAddressException {

System.out.println("使用03功能码写入保持寄存器 address = " + address + " 值:" + value);

}

@Override

public void writeHoldingRegisterRange(int address, int[] values) {

System.out.println("使用03功能码批量写入保持寄存器 address = " + address + " 值:" + values.toString());

}

});

modbusSlave.setDataHolder(myDataHolder);

modbusSlave.setServerAddress(1);

// ModbusHoldingRegisters mm = new ModbusHoldingRegisters(10);

// mm.set(0, 1223);

// mm.set(1, 321);

// modbusSlave.getDataHolder().setHoldingRegisters(mm);

modbusSlave.listen();

}

public interface EventListeners{

void readHoldingRegister(int address);

void readHoldingRegisterRange(int address, int quantity);

void writeHoldingRegister(int address, int value) throws IllegalDataValueException, IllegalDataAddressException;

void writeHoldingRegisterRange(int address, int[] values);

}

public static class MyDataHolder extends DataHolder{

final List<EventListeners> eventListenerList = new ArrayList<>();

public void addEventListener(EventListeners eventListener){

eventListenerList.add(eventListener);

}

public boolean removeEventListener(EventListeners eventListener){

return eventListenerList.remove(eventListener);

}

@Override

public int readHoldingRegister(int offset) throws IllegalDataAddressException {

for (EventListeners e : eventListenerList){

e.readHoldingRegister(offset);

}

return super.readHoldingRegister(offset);

}

@Override

public int[] readHoldingRegisterRange(int offset, int quantity) throws IllegalDataAddressException {

for (EventListeners e : eventListenerList){

e.readHoldingRegisterRange(offset, quantity);

}

return super.readHoldingRegisterRange(offset, quantity);

}

@Override

public void writeHoldingRegister(int offset, int value) throws IllegalDataAddressException, IllegalDataValueException {

for (EventListeners e : eventListenerList){

e.writeHoldingRegister(offset, value);

}

super.writeHoldingRegister(offset, value);

}

@Override

public void writeHoldingRegisterRange(int offset, int[] range) throws IllegalDataAddressException, IllegalDataValueException {

for (EventListeners e : eventListenerList){

e.writeHoldingRegisterRange(offset, range);

}

super.writeHoldingRegisterRange(offset, range);

}

}

// 为从机设置03功能码对应的数值寄存器

public static ModbusHoldingRegisters updateHoldingRegisters(int offset, int quantity) throws IllegalDataAddressException, IllegalDataValueException {

List<Float> list = Arrays.asList(10.1f,20.3f,89.5f,73.353f);

ModbusHoldingRegisters hr = new ModbusHoldingRegisters(10000);

// 修改数值寄存器对应位置的值,第一个参数代表寄存器地址,第二个代表修改的数值

//hr.set有几个方法,根据自己要赋值的数据类型选择,此处示例的是赋值float类型,一个float是4个字节,32bit,对应2个寄存器所以i*2

for(int i=0;i<list.size();i++){

hr.setFloat32At(i*2, list.get(i));

}

return hr;

}

}

Modbus通讯协议(四)——Java实现ModbusTCP Slave(从机)_java搭建modbus slave-CSDN博客

https://blog.51cto.com/u_13229/8775755

https://blog.51cto.com/u_16099169/8318121



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。