Modbus Java工具包学习记录

Modbus Java工具包

本文承接上文Modbus通信工具学习记录,我们已经了解编程过程中可能用到的小工具,本次介绍三个java项目常用Modbus协议jar包。只做参考,有能力的话还是建议根据需求自行编写协议工具类

  1. 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。但是该工具是同步的不支持异步,实时性要求不强可以使用。
  2. jlibmodbus:支持Modbus-RTU和Modbus-TCP两种协议,支持Modbus-RTU over Serial 、Modbus-RTU over TCP、Modbus-TCP over TCP,Modbus-TCP内部通过socket实现支持异步。Modbus-RTU Serial通过RXTX实现。
  3. modbus-master-tcp:支持Modbus-TCP一种协议,支持Modbus-TCP over TCP,内部通过netty实现支持异步。可以执行扩展使其支持Modbus-RTU over TCP和Modbus-RTU over Serial
  4. 以上三个工具包的所有连接都没有断线重连功能,所以使用时需要自行解决断线重连问题。

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通信驱动
本文只是记录本人学习过程中的理解,可能有部分内容有纰漏,望各位不吝赐教。

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只胖橘丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值