java 集成 ModbusTCP/RTU 使用Modbus4J


自己摸索了一周并测试可用,做了一些总结,希望可以帮到你! ^ _ ^

1.导入maven

<dependencies>
	<dependency>
          <groupId>com.infiniteautomation</groupId>
          <artifactId>modbus4j</artifactId>
          <version>3.0.3</version>
      </dependency>
  </dependencies>

<repositories>
    <repository>
        <releases>
            <enabled>false</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
        <id>ias-snapshots</id>
        <name>Infinite Automation Snapshot Repository</name>
        <url>https://maven.mangoautomation.net/repository/ias-snapshot/</url>
    </repository>
    <repository>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
        <id>ias-releases</id>
        <name>Infinite Automation Release Repository</name>
        <url>https://maven.mangoautomation.net/repository/ias-release/</url>
    </repository>
</repositories>

2.添加Modbus4jUtils.java

@Slf4j
public class Modbus4jUtils {
    /**
     * 工厂。
     */
    static ModbusFactory modbusFactory;

    //建立链接
    static public ModbusMaster tcpMaster;

    static {
        if (modbusFactory == null) {
            modbusFactory = new ModbusFactory();
            tcpMaster = getMaster("192.168.2.100", 10001);  // 填写要连接的TCP server
        }
    }

    /**
     * 获取master
     *
     * @return
     * @throws ModbusInitException
     */
    public static ModbusMaster getMaster(String ip, Integer port) {
        	IpParameters params = new IpParameters();
       		params.setHost(ip);
       		params.setPort(port);

			// RTU 协议-设备是modbus rtu就用他 注意哦
	        // params.setEncapsulated(true);
	        // ModbusMaster master = modbusFactory.createTcpMaster(params, true);
	        // TCP 协议
	        ModbusMaster master = modbusFactory.createTcpMaster(params, false);

	        try {
	            //设置超时时间---发现设置他没用,还会报错,所以屏蔽
				// master.setTimeout(5000);
	            //设置重连次数---发现设置他没用,还会报错,所以屏蔽
				//master.setRetries(3);
	            //初始化
	            master.init();
	        } catch (ModbusInitException e) {
	            e.printStackTrace();
	        }
	        return master;
	    }

	/**
     * 读取保持寄存器 功能码[03]
     *
     * @param start     开始地址
     * @param readLenth 读取数量
     * @return
     * @throws ModbusInitException
     */
    public static ByteQueue modbusTCP03(int slaveId, ModbusMaster tcpMaster, int start, int readLenth) throws ModbusInitException {
        //发送请求
        ModbusRequest modbusRequest = null;
        try {
            modbusRequest = new ReadHoldingRegistersRequest(slaveId, start, readLenth);//功能码03
        } catch (ModbusTransportException e) {
            e.printStackTrace();
        }
        //收到响应
        ModbusResponse modbusResponse = null;
        try {
            modbusResponse = tcpMaster.send(modbusRequest);
        } catch (ModbusTransportException e) {
            e.printStackTrace();
        }
        ByteQueue byteQueue = new ByteQueue(12);
        modbusResponse.write(byteQueue);
        System.out.println("功能码:" + modbusRequest.getFunctionCode());
        System.out.println("从站地址:" + modbusRequest.getSlaveId());
        System.out.println("开始地址:" + start);
        System.out.println("收到的响应信息大小:" + byteQueue.size());
        System.out.println("收到的响应信息值:" + byteQueue);
        return byteQueue;
    }

	/*
     * 写 多个寄存器 功能码[16] - 相当厂家文档写单个和多个。一样可以
     * WriteCoilRequest  05
     * WriteRegisterRequest 06
     * WriteRegistersRequest 16
     *
     */
    public static ByteQueue modbusTCP16(int slaveId, ModbusMaster tcpMaster, int writeOffset, short[] data) throws Exception {
        WriteRegistersRequest writeRegistersRequest = null;
        //收到响应
        ModbusResponse modbusResponse = null;
        try {
            writeRegistersRequest = new WriteRegistersRequest(slaveId, writeOffset, data);
            modbusResponse = tcpMaster.send(writeRegistersRequest);
            if (modbusResponse.isException()) {
                System.out.println("Exception response: message=" + modbusResponse.getExceptionMessage());
            } else {
                System.out.println("Success");
            }
        } catch (ModbusTransportException e) {
            e.printStackTrace();
        }
        ByteQueue byteQueue = new ByteQueue(12);
        modbusResponse.write(byteQueue);
        System.out.println("功能码:" + writeRegistersRequest.getFunctionCode());
        System.out.println("从站地址:" + writeRegistersRequest.getSlaveId());
        System.out.println("收到的响应信息大小:" + byteQueue.size());
        System.out.println("收到的响应信息值:" + byteQueue);
        return byteQueue;
    }

 
	 public static void main(String[] args) {
        try {
				// start 需要将16进制转10机制哦
	            int start = 0;
	            // 设备通讯地址-看情况需要转换会10机制哦
	            int slaveId = 1;
				// 读 电表
	            start = get16to10("aa00"); //  总电能-这个值看厂家文档
	            // 参数 2 是2个寄存器-这个值看厂家文档
	            ByteQueue byteQueue = modbusTCP03(slaveId , tcpMaster, start, 2);		            
	            // 这是把 '响应的报文' 做一些转换,更多转换参考文章下面
	            byte[] bytes1 = byteQueue.peekAll();
	            // 这里是对 '响应的报文' 截取后面4位
	            byte[] bytes2 = Arrays.copyOfRange(bytes1, bytes1.length - 4, bytes1.length);
	            System.out.println(Arrays.toString(bytes2));
	            System.out.println(toDouble(bytes2));

	            // 写 电表
	            start = get16to10("aa01"); // 电器控制值-这个值看厂家文档
	            short[] fenZha = {0x00}; // 分闸-这个值看厂家文档
	            // short[] hrzha = {(short) 0b1111111111111111}; // 合闸-这个值看厂家文档 是这个0x01/0xff ,但是不行!
	            ByteQueue byteQueue = modbusTCP16(slaveId, tcpMaster, start, fenZha);

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


}

一些字节转换,肯定用得上!精髓

	/**
     * 将byte数组转换为浮点数
     */
    public static double toDouble(byte[] bytes) {
        return ByteBuffer.wrap(bytes).getFloat();
    }

    /**
     * 将byte数组转换为浮点数-并保留最后两位小数点
     */
    public static double toDouble00(byte[] bytes) {
        double f = ByteBuffer.wrap(bytes).getFloat();
        return toDouble00(f);
    }

    /**
     * double 保留最后两位小数点
     */
    public static double toDouble00(double f) {
        BigDecimal b = new BigDecimal(f);
        // 是小数点后只有两位的双精度类型数据
        double f1 = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        return f1;
    }

    /**
     * 将16进制转10进制-s去掉前缀0x
     * 也可以手动改后面16参数,改自己要的字节
     */
    public static int get16to10(String s) {
        return Integer.parseInt(s, 16);
    }

    /**
     * 将byte[]转为各种进制的字符串
     *
     * @param bytes byte[]
     * @param radix 基数可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制
     * @return 转换后的字符串
     * <p>
     * 类型 占用 bit(位)
     * byte(字节) 8
     * short(短整型) 16
     * int(整型) 32
     * long(长整型) 64
     * float(单精度浮点型) 32
     * double(双精度浮点型) 64
     * char(字符) 16
     * boolean(布尔型) 1
     */
    public static String binary(byte[] bytes, int radix) {
        return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
    }

    /**
     * 将byte数组转换为整数
     * 转换为bit后,最左边的那位表示,符号位(有符号/无符号)
     */
    public static int bytesToInt(byte[] bs) {
        int a = 0;
        for (int i = bs.length - 1; i >= 0; i--) {
            a += bs[i] * Math.pow(255, bs.length - i - 1);
        }
        return a;
    }

    /**
     * 将byte数组转换为short
     */
    public static short bytesToshort(byte[] b) {
        short l = 0;
        for (int i = 0; i < 2; i++) {
            l <<= 8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
            l |= (b[i] & 0xff); //和上面也是一样的  l = l | (b[i]&0xff)
        }
        return l;
    }

好了!以上是 读 / 写 测试,谢谢

  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
支持Modbus TCP转Modubus RTURTU可以为RS232或者RS485。 支持RTU做主站或者Modubs TCP做主站。 支持多主机访问支持,最多连接100个TCP客户端。 支持所有的Modubus功能码和寄存器范围。 同时也可以做普通串口服务器使用。 ZLAN5142 概述 ZLAN5142 Modbus网关是上海卓岚信息科技有限公司开发的一款在Modbus TCPModbus RTU之间进行协议转化的转换器,其中Modbus RTU可以是RS485也可以是RS232接口。 ZLAN5142具备了强大的多主机访问支持功能和RS485总线冲突控制功能。所谓多主机功能是指,ZLAN5142作为Modbus TCP服务器时可以支持多达100个TCP客户端同时连接,多个TCP连接可以随机性的访问,ZLAN5142能够分别对不同的连接给出正确应答,保证数据稳定不丢包。相对于RS485总线只能够有一个主机进行访问,ZLAN5142实现了“多主机”功能。ZLAN5142实现了RS485总线的冲突控制,防止了多主机时的串口总线抢占问题。 另外,将ZLAN5142的“转化协议”选择为“无”,也可以当作普通的透明传输的串口服务器使用。但是不同于普通的串口服务器例如ZLAN5102,ZLAN5142即使作为普通串口服务器模式下也可以支持“多主机”功能,可解决多个计算机或主站如何同时监控一个串口设备的难题。 特点 支持Modbus TCP转Modubus RTURTU可以为RS232或者RS485。 支持RTU做主站或者TCP做主站。 支持多主机访问支持,最多连接100个TCP客户端。 支持1200~460800波特率。 支持RS485总线冲突调度机制,防止总线冲突。 支持所有的Modubus功能码和寄存器范围。 可作为普通的透传串口服务器使用,具备ZLAN5102相同功能。 小于1W的低功耗设计。 内嵌485防雷保护功能,适合室外485通信。 支持DNS,满足通过域名实现通信的要求。支持DHCP。 2KV网络浪涌保护。 外壳采用抗辐射的SECC板,保证在高电磁辐射区也能够正常工作。 规格 网络界面 以太网 10/100 Mbps, RJ45 保护 内建2KV电磁隔离 串口界面 界面 RS-232/485 串口数 1 校验位 None, Even, Odd, Space, Mark 数据位 5~9 停止位 1,2 流控 RTS/CTS,DTR/DCR, XON/XOFF 速率 1200bps~460800bps 软件特性 协议 TCP,HTTP,UDP,ICMP,ARP,IP,DNS,DHCP 虚拟串口平台 Windows 95/98/ME/NT/2000/XP/WIN7/WIN8 配置方式 Web浏览器、卓岚ZLVirCom、串口类AT命令 电器特性 电压输入 DC9~24V,100mA 机械特性 外壳材料 抗电磁材料SECC钢板 尺寸 长×宽×高=9.4cm×6.5cm×2.5cm 工作环境 工作温度,湿度 -45~85℃,5~95% RH 储存温度,湿度 -45~165℃,5~95% RH W

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值