首页 > 基础资料 博客日记

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

2024-07-14 07:00:05基础资料围观266

Java资料网推荐Modbus通讯协议——Java通过Jlibmodbus实现Modbus Master(主机)TCP/RTU的Read;Slave(从机)TCP/RTU的Write这篇文章给大家,欢迎收藏Java资料网享受知识的乐趣

一、首先了解一下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/

        <!-- 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


文章来源:https://blog.csdn.net/feiyu97/article/details/137970929
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云