Modbus通讯协议(二)——Java向ModbusSlave模拟器读写数据

本文介绍通过Java程序向modbus slave模拟器工具读写数据。使用TCP的连接方式,modbus rtu通讯协议。

安装Modbus Slave

安装及使用请看上一篇文章:Modbus通讯协议(一)——测试工具ModbusPoll和ModbusSlave,本篇使用的是Modbus Slave 7.3.1 ,过低版本不支持TCP方式上使用modbus rtu

设置参数并开启连接

点击菜单Setup–>Resd/Write Definition 进行参数设置,Function 选01
在这里插入图片描述
点击菜单Connection–>connect F3进行连接,Connection选Modbus RTU Over TCP/IP
在这里插入图片描述

项目中添加依赖

        <!--  串口通讯-->
        <dependency>
            <groupId>org.rxtx</groupId>
            <artifactId>rxtx</artifactId>
            <version>2.1.7</version>
        </dependency>

下载一依赖的SDK:net.wimpi.modbus

Java发送和读取工具类

工具类中有不同变量类型的读取和写数据的方法,方法要与modbus slave 寄存器设置的变量类型保持一致

package io.github.talelin.latticy.util;

import net.wimpi.modbus.io.ModbusRTUTCPTransaction;
import net.wimpi.modbus.msg.*;
import net.wimpi.modbus.net.RTUTCPMasterConnection;
import net.wimpi.modbus.procimg.InputRegister;
import net.wimpi.modbus.util.BitVector;

import java.net.InetAddress;

public class ModbusRtuUtil {

    String ip="192.168.1.232";
    int port=10000;
    int slaveID=254;
    RTUTCPMasterConnection Conn;
    int ErrorCnt=0;
    public void Init(String _ip,int _port,int _slaveID)
    {
        ip = _ip;
        port = _port;
        slaveID = _slaveID;
    }

    public boolean BeginConnect()
    {
        try {
            InetAddress addr = InetAddress.getByName(ip);

            // creat new tcp
            Conn = new RTUTCPMasterConnection(addr,port);
            Conn.setTimeout(3000);
            Conn.connect();

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

        return IsConnect();
    }

    public boolean  IsConnect()
    {
        if(ErrorCnt>10)
        {
            ErrorCnt = 0;
            if(Conn==null)return false;
            Conn.close();
            Conn = null;
        }
        if(Conn==null)return false;
        return Conn.isConnected();
    }

    public boolean DisConnect()
    {
        if(Conn==null)return false;
        Conn.close();
        return  IsConnect();
    }

    //read the status  of  do . the count is  the number of do channels
    public BitVector readDO(int count) {
        BitVector data = null;
        try {
            if(IsConnect()==false)
            {
                if(BeginConnect()==false)return data;
            }

            if(count==0)return data;

            //默认第一个继电器的地址0
            ReadCoilsRequest req = new ReadCoilsRequest(0, count);

            req.setUnitID(slaveID);

            ModbusRTUTCPTransaction trans = new ModbusRTUTCPTransaction(Conn);

            trans.setRequest(req);

            trans.execute();

            ReadCoilsResponse res = ((ReadCoilsResponse) trans.getResponse());

            data = res.getCoils();

            ErrorCnt = 0;
        } catch (Exception e) {
            e.printStackTrace();
            ErrorCnt++;
        }

        return data;
    }
    //read the coils status?  读取单个继电器状态
    public int readSignalDO(int regAddr	) {
        int data = 0;
        try {
            if(IsConnect()==false)
            {
                if(BeginConnect()==false)return -1;
            }

            ReadCoilsRequest req = new ReadCoilsRequest(regAddr, 1);

            req.setUnitID(slaveID);

            ModbusRTUTCPTransaction trans = new ModbusRTUTCPTransaction(Conn);

            trans.setRequest(req);

            trans.execute();

            ReadCoilsResponse res = ((ReadCoilsResponse) trans.getResponse());

            if(res.getCoils().getBit(0)){
                data = 1;
            }

            ErrorCnt = 0;
        } catch (Exception e) {
            e.printStackTrace();
            ErrorCnt++;
        }

        return data;
    }

    /**
     * 写入数据到真机的DO类型的寄存器上面
     *
     * @param regAddr
     * @param value
     */
    public void writeSignalDO(int regAddr, int value) {
        try {
            if(IsConnect()==false)
            {
                if(BeginConnect()==false)return ;
            }

            ModbusRTUTCPTransaction trans = new ModbusRTUTCPTransaction(Conn);

            WriteCoilRequest req = new WriteCoilRequest(regAddr, value==0?false:true);

            req.setUnitID(slaveID);
            trans.setRequest(req);

            trans.execute();
            ErrorCnt = 0;
        } catch (Exception e) {
            e.printStackTrace();
            ErrorCnt++;
        }
    }
    /**
     * 查询Function 为Input Status的寄存器
     * 读取光耦输入状态
     * @param count
     */
    public BitVector readDI(int count) {
        BitVector data = null;
        try {
            if(IsConnect()==false)
            {
                if(BeginConnect()==false)return data;
            }
            if(count==0)return data;

            // 第一个参数是寄存器的地址,第二个参数是读取多少个
            ReadInputDiscretesRequest req = new ReadInputDiscretesRequest(0, count);

            // 这里设置的Slave Id, 读取的时候这个很重要
            req.setUnitID(slaveID);

            ModbusRTUTCPTransaction trans = new ModbusRTUTCPTransaction(Conn);

            trans.setRequest(req);

            // 执行查询
            trans.execute();

            // 得到结果
            ReadInputDiscretesResponse res = (ReadInputDiscretesResponse) trans.getResponse();

            data = res.getDiscretes();

            ErrorCnt = 0;
        } catch (Exception e) {
            e.printStackTrace();
            ErrorCnt++;
        }

        return data;
    }
    public int readSignalDI(int regAddr) {
        int data = 0;
        try {
            if(IsConnect()==false)
            {
                if(BeginConnect()==false)return -1;
            }

            // 第一个参数是寄存器的地址,第二个参数时读取多少个
            ReadInputDiscretesRequest req = new ReadInputDiscretesRequest(regAddr, 1);

            // 这里设置的Slave Id, 读取的时候这个很重要
            req.setUnitID(slaveID);

            ModbusRTUTCPTransaction trans = new ModbusRTUTCPTransaction(Conn);

            trans.setRequest(req);

            // 执行查询
            trans.execute();

            // 得到结果
            ReadInputDiscretesResponse res = (ReadInputDiscretesResponse) trans.getResponse();

            if(res.getDiscretes().getBit(0)){
                data = 1;
            }

            ErrorCnt = 0;
        } catch (Exception e) {
            e.printStackTrace();
            ErrorCnt++;
        }

        return data;
    }

    public int[] readAI(int count) {
        int[] data = null;
        try {
            if(IsConnect()==false)
            {
                if(BeginConnect()==false)return data;
            }

            if(count==0)return data;

            //这里重点说明下,这个地址和数量一定要对应起来
            ReadInputRegistersRequest req = new ReadInputRegistersRequest(0, count);

            //这个SlaveId一定要正确
            req.setUnitID(slaveID);

            ModbusRTUTCPTransaction trans = new ModbusRTUTCPTransaction(Conn);

            trans.setRequest(req);

            trans.execute();

            ReadInputRegistersResponse res = (ReadInputRegistersResponse) trans.getResponse();

            InputRegister[] rst = res.getRegisters();
            if(rst.length!=count)return data;
            data = new int[count];
            for(int i=0;i<count;i++)
                data[i] = rst[i].getValue();

            ErrorCnt = 0;
        } catch (Exception e) {
            e.printStackTrace();
            ErrorCnt++;
        }

        return data;
    }
    public int readSignalAI(int regAddr) {
        int data = 0;

        try {
            if(IsConnect()==false)
            {
                if(BeginConnect()==false)return -1;
            }

            //这里重点说明下,这个地址和数量一定要对应起来
            ReadInputRegistersRequest req = new ReadInputRegistersRequest(regAddr, 1);

            //这个SlaveId一定要正确
            req.setUnitID(slaveID);

            ModbusRTUTCPTransaction trans = new ModbusRTUTCPTransaction(Conn);

            trans.setRequest(req);

            trans.execute();

            ReadInputRegistersResponse res = (ReadInputRegistersResponse) trans.getResponse();

            data = res.getRegisterValue(0);
            ErrorCnt = 0;
        } catch (Exception e) {
            e.printStackTrace();
            ErrorCnt++;
        }

        return data;
    }

    public int readRegister(int regAddr) {
        int data = 0;
        try {
            if(IsConnect()==false)
            {
                if(BeginConnect()==false)return -1;
            }
            ReadMultipleRegistersRequest req = new ReadMultipleRegistersRequest(regAddr, 1);
            req.setUnitID(slaveID);

            ModbusRTUTCPTransaction trans = new ModbusRTUTCPTransaction(Conn);

            trans.setRequest(req);

            trans.execute();

            ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse) trans.getResponse();

            data = res.getRegisterValue(0);
            ErrorCnt = 0;
        } catch (Exception e) {
            e.printStackTrace();
            ErrorCnt++;
        }

        return data;
    }
}

测试

package io.github.talelin.latticy;

import io.github.talelin.latticy.util.ModbusRtuUtil;
import net.wimpi.modbus.util.BitVector;
import org.junit.Test;

public class ModbusTest {

    @Test
    public void handleDevice() throws Exception{
        ModbusRtuUtil rtuUtil = new ModbusRtuUtil();

        int MaxDONum = 4;//继电器数量
        int MaxDINum = 4;//光耦输入数量
        int MaxAINum = 4;//模拟量输入通道数量
        //初始化设备
        rtuUtil.Init("127.0.0.1", 502, 1); //ip,端口,slaveID  此处参数要与Modbus Slave中设置的一致
        rtuUtil.BeginConnect();

        System.out.println("写入数据到真机的DO类型的寄存器上面");
        rtuUtil.writeSignalDO(0, 1);//Modbus Slave中Function Code选01

		//读取DO 继电器
        BitVector DOVal= rtuUtil.readDO(MaxDONum);	//Modbus Slave中Function Code选01
//        //读取DI
//        BitVector DIVal= rtuUtil.readDI(MaxDINum);//Modbus Slave中Function Code选02
//        //读取AI
//        int[]     AIVal =null;
//        if(MaxAINum>0)  AIVal= rtuUtil.readAI(MaxAINum);//Modbus Slave中Function Code选04

        if(MaxDONum>0)PrintfDODIVal("DO Status:",DOVal,MaxDONum);
//        if(MaxDINum>0) PrintfDODIVal("DI Status:",DIVal,MaxDINum);
//        if(MaxAINum>0)PrintfAIVal("AI Status:",AIVal);
//        Thread.sleep(1000);

        //equip.DisConnect();
    }

    public static void PrintfDODIVal(String prev,BitVector val,int size)
    {
        System.out.println(prev);
        if(val==null)return;
        for(int i=0;i<size;i++)
            System.out.print("  "+(val.getBit(i)?"1":"0"));
        System.out.println("");

    }
    public static void PrintfAIVal(String prev,int[] val)
    {
        System.out.println(prev);
        if(val==null)return;
        for(int i=0;i<val.length;i++)
            System.out.print(val[i]+"  ");
        System.out.println("");
    }
}

写入成功并接收到响应
在这里插入图片描述

在这里插入图片描述
Function Code选02,并在Modbus Slave中设置值

//读取DI
BitVector DIVal= rtuUtil.readDI(MaxDINum);
if(MaxDINum>0) PrintfDODIVal("DI Status:",DIVal,MaxDINum);

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

三毛村滴雪鱼粉

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

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

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

打赏作者

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

抵扣说明:

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

余额充值