java使用modbus4j读取和存储String字符

一、背景介绍

因为工作中需要用到modbus读取和存储字符串,但是modbus本身并不直接支持字符串类型数据。这里只能将字符串进行转换后进行存储,读的时候也是一样,通过读入一段连续的寄存器地址数据,再转成字符串。

二、环境搭建

参见:https://blog.csdn.net/xixiyuguang/article/details/123353651

三、核心代码

本文使用modbus4j来实现读写modbus

package com.borrow.util;

import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.ip.encap.EncapMessageParser;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.serotonin.modbus4j.msg.*;
import com.serotonin.modbus4j.sero.messaging.IncomingMessage;
import com.serotonin.modbus4j.sero.util.queue.ByteQueue;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * modbus通讯工具类,采用modbus4j实现
 *
 * @author wangwei
 * @dependencies modbus4j-3.0.3.jar
 * @website https://github.com/infiniteautomation/modbus4j
 */
public class ModbusUtil {
    /**
     * 工厂。
     */
    static ModbusFactory modbusFactory;
    static {
        if (modbusFactory == null) {
            modbusFactory = new ModbusFactory();
        }
    }

    /**
     * 获取master
     *
     * @return
     * @throws ModbusInitException
     */
    public static ModbusMaster getMaster() throws ModbusInitException {
        IpParameters params = new IpParameters();
        params.setHost("localhost");
        params.setPort(502);
        //
        // modbusFactory.createRtuMaster(wapper); //RTU 协议
        // modbusFactory.createUdpMaster(params);//UDP 协议
        // modbusFactory.createAsciiMaster(wrapper);//ASCII 协议
        ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
        master.init();

        return master;
    }



    /**
     * 写 [01 Coil Status(0x)]写一个 function ID = 5
     *
     * @param slaveId
     *            slave的ID
     * @param writeOffset
     *            位置
     * @param writeValue
     *            值
     * @return 是否写入成功
     * @throws ModbusTransportException
     * @throws ModbusInitException
     */
    public static boolean writeCoil(int slaveId, int writeOffset, boolean writeValue)
            throws ModbusTransportException, ModbusInitException {
        // 获取master
        ModbusMaster tcpMaster = getMaster();
        // 创建请求
        WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);
        // 发送请求并获取响应对象
        WriteCoilResponse response = (WriteCoilResponse) tcpMaster.send(request);
        if (response.isException()) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 写[01 Coil Status(0x)] 写多个 function ID = 15
     *
     * @param slaveId
     *            slaveId
     * @param startOffset
     *            开始位置
     * @param bdata
     *            写入的数据
     * @return 是否写入成功
     * @throws ModbusTransportException
     * @throws ModbusInitException
     */
    public static boolean writeCoils(int slaveId, int startOffset, boolean[] bdata)
            throws ModbusTransportException, ModbusInitException {
        // 获取master
        ModbusMaster tcpMaster = getMaster();
        // 创建请求
        WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, bdata);
        // 发送请求并获取响应对象
        WriteCoilsResponse response = (WriteCoilsResponse) tcpMaster.send(request);
        if (response.isException()) {
            return false;
        } else {
            return true;
        }

    }

    /***
     * 写[03 Holding Register(4x)] 写一个 function ID = 6
     *
     * @param slaveId
     * @param writeOffset
     * @param writeValue
     * @return
     * @throws ModbusTransportException
     * @throws ModbusInitException
     */
    public static boolean writeRegister(int slaveId, int writeOffset, short writeValue)
            throws ModbusTransportException, ModbusInitException {
        // 获取master
        ModbusMaster tcpMaster = getMaster();
        // 创建请求对象
        WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue);
        WriteRegisterResponse response = (WriteRegisterResponse) tcpMaster.send(request);
        if (response.isException()) {
            System.out.println(response.getExceptionMessage());
            return false;
        } else {
            return true;
        }

    }

    /**
     *
     * 写入[03 Holding Register(4x)]写多个 function ID=16
     *
     * @param slaveId
     *            modbus的slaveID
     * @param startOffset
     *            起始位置偏移量值
     * @param sdata
     *            写入的数据
     * @return 返回是否写入成功
     * @throws ModbusTransportException
     * @throws ModbusInitException
     */
    public static boolean writeRegisters(int slaveId, int startOffset, short[] sdata)
            throws ModbusTransportException, ModbusInitException {
        // 获取master
        ModbusMaster tcpMaster = getMaster();
        // 创建请求对象
        WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, sdata);
        // 发送请求并获取响应对象
        ModbusResponse response = tcpMaster.send(request);
        if (response.isException()) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 写入数字类型的模拟量(如:写入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);
    }



    /**
     *     工具类方法 setString()主要进行了一下数据类型转换
     * @param value
     * @return
     */
    public static short[] SetString(String value) {
        byte[] bytesTemp = value.getBytes(StandardCharsets.UTF_8);
        byte[] bytes;
        if (bytesTemp.length % 2 > 0) {
            bytes = Arrays.copyOf(bytesTemp, bytesTemp.length + 1);
        } else {
            bytes = bytesTemp;
        }
        return bytesToShort(bytes);
    }

    /**
     * Byte数组转short数组
     *
     * @param bytes
     * @return
     */
    public static short[] bytesToShort(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        short[] shorts = new short[bytes.length / 2];
        ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
        return shorts;

    }




    /**
     *工具类方法getString()  类型转换
     * @param src
     * @param start
     * @param len
     * @return
     */
    public static String GetString(short[] src, int start, int len) throws UnsupportedEncodingException
    {
        short[] temp = new short[len];
        for (int i = 0; i < len; i++)
        {
            temp[i] = src[i + start];
        }
        byte[] bytesTemp = shorts2Bytes(temp);
        for (int i = 0; i < bytesTemp.length; i++) {
            byte b = bytesTemp[i];
        }
        String str = new String(bytesTemp, "UTF-8");
        return str;
    }
    /**
     *short数组转byte
     * @param data
     * @return
     */
    public static byte [] shorts2Bytes(short [] data){
        byte[] byteValue = new byte[data.length * 2];
        for (int i = 0; i < data.length; i++) {
            byteValue[i * 2] = (byte) (data[i] & 0xff);
            byteValue[i * 2 + 1] = (byte) ((data[i] & 0xff00) >> 8);
        }
        return byteValue;
    }

    /**

     * 读保持寄存器上的内容

     * @param master 主站

     * @param slaveId 从站地址

     * @param start 起始地址的偏移量

     * @param len 待读寄存器的个数

     */

    private static String readHoldingRegistersToString(ModbusMaster master, int slaveId, int start, int len) {
        String s = "";
        try {
            ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, start, len);
            ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.send(request);
            if (response.isException())
                System.out.println("Exception response: message=" + response.getExceptionMessage());
            else
                s = GetString(response.getShortData(),0,len);
        }
        catch (ModbusTransportException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return s;
    }
    /**
     * 测试modbus读写字符
     *
     * @param args
     */
    public static void main(String[] args) {
        try {
            //往modbus中写入字符
            short[] t = SetString("测试读取中文字符");
            boolean f = writeRegisters(1,1,t);
            //从modbus读取数据,并转换为字符
            String str = readHoldingRegistersToString(getMaster(),1,1,23);
            System.out.println("读取的字符:"+str);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}



控制台输出结果:
在这里插入图片描述

modbus slave结果:
在这里插入图片描述

以下是使用 C++ 语言实现 Modbus 协议字符串的示例代码: ```c++ #include <iostream> #include <cstring> #include <modbus/modbus.h> int main() { modbus_t *ctx = NULL; uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH]; uint8_t response[MODBUS_TCP_MAX_ADU_LENGTH]; int rc; const char *ip = "127.0.0.1"; int port = 502; // 连接 Modbus 服务器 ctx = modbus_new_tcp(ip, port); if (ctx == NULL) { std::cerr << "Unable to allocate libmodbus context" << std::endl; return -1; } if (modbus_connect(ctx) == -1) { std::cerr << "Connection failed: " << modbus_strerror(errno) << std::endl; modbus_free(ctx); return -1; } // 准备 Modbus 请求 int address = 0x01; int function = MODBUS_FC_WRITE_MULTIPLE_REGISTERS; int start_register = 0x0000; int num_registers = 8; uint16_t data[num_registers]; std::string str = "hello"; std::memcpy(data, str.c_str(), str.length()); data[str.length()] = '\0'; // 发送 Modbus 请求 rc = modbus_write_registers(ctx, start_register, num_registers, data); if (rc == -1) { std::cerr << "Write registers failed: " << modbus_strerror(errno) << std::endl; modbus_free(ctx); return -1; } // 断开 Modbus 连接 modbus_close(ctx); modbus_free(ctx); return 0; } ``` 上述示例代码中,我们使用了 libmodbus 库来连接 Modbus 服务器并发送请求。在准备 Modbus 请求时,我们使用了 `MODBUS_FC_WRITE_MULTIPLE_REGISTERS` 功能码来指定写入多个寄存器的操作,同时将字符串转换为 `uint16_t` 类型的数组,并在数组末尾添加了一个 `\0` 字符来表示字符串的结束。最后,我们使用 `modbus_write_registers` 函数来发送 Modbus 请求。需要注意的是,这里我们只是将字符串写入了 Modbus 的寄存器中,如果需要读取字符串,需要使用相应的功能码和读取寄存器的地址和数量。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值