首页 > 编程语言 >物联网---04.java对Modbus数据解析与对象互转

物联网---04.java对Modbus数据解析与对象互转

时间:2023-04-22 11:11:40浏览次数:38  
标签:java int return Modbus length 互转 Integer byte public

一、Modbus 互转代码

1.实现代码

@Data
public class ModbusTools {
    /**
     * modbus数据转对象
     * @param data 串口数据
     * @param dataType 1代表16位读取2个byte数据,2代表32位读取4个byte数据
     */
    public static ModbusDataAnalyzeBean dataAnalyze(byte []data, int dataType)
    {
        int readByteNum=0;//一次要读取多少个byte
        if (dataType==1)
        {
            readByteNum=2;
        }
        else if (dataType>1)
        {
            readByteNum=dataType*dataType;
        }

        ModbusDataAnalyzeBean modbusDataAnalyzeBean =new ModbusDataAnalyzeBean();
        modbusDataAnalyzeBean.setAddr(Integer.parseInt(getOctFromHexBytes(data,0)));//获取地址
        modbusDataAnalyzeBean.setFuncode(Integer.parseInt(getOctFromHexBytes(data,1)));//获取功能码
        modbusDataAnalyzeBean.setDataType(dataType);//数据类型
        int byteNum=Integer.parseInt(getOctFromHexBytes(data,2));//统计有效byte数据个数

        ArrayList<Double> arrayListVlaue=new ArrayList();
        for (int n=1;n<(byteNum/readByteNum)+1;n++)
        {
            arrayListVlaue.add(Double.parseDouble(getOctFromHexBytes(data,3+readByteNum*(n-1),3+readByteNum*n-1)));//获取值
        }
        modbusDataAnalyzeBean.setValues(arrayListVlaue);//将取到的值存进返回对象
        return modbusDataAnalyzeBean;
    }

    /**
     *  对象转modbus数据
     * @param modbusDataFormationBean
     * @return
     */

    public static byte[] data(ModbusDataFormationBean modbusDataFormationBean)
    {
        int readByteNum=0;//一次要读取多少个byte
        if (modbusDataFormationBean.getDataType()==1)
        {
            readByteNum=2;
        }
        else if (modbusDataFormationBean.getDataType()>1)
        {
            readByteNum=modbusDataFormationBean.getDataType()*modbusDataFormationBean.getDataType();
        }
        byte[] command={};
        command = append(command,octInt2ByteArray( modbusDataFormationBean.getAddr(), 1));//设置地址
        command = append(command,octInt2ByteArray( modbusDataFormationBean.getFuncode(), 1)); //设置功能码
        command = append(command,octInt2ByteArray( modbusDataFormationBean.getPortNumber(), 2));//设置寄存器起始地址
        command = append(command,octInt2ByteArray( modbusDataFormationBean.getValue(), readByteNum));//设置数据值
        command = append(command, octInt2ByteArray( getCRC162Int(command,true), 2) );// 设置CRC16校验

        return command;
    }


    /**
     * 取得十制数组的from~to位,并按照十六进制转化值
     *
     * @param data
     * @param from
     * @param to
     * @return
     */
    private static String getOctFromHexBytes(byte[] data, Object from, Object... to) {
        if (data != null && data.length > 0 && from != null) {
            try {
                byte[] value;
                int fromIndex = Integer.parseInt(from.toString());
                if (to != null && to.length > 0) {
                    int toIndex = Integer.parseInt(to[0].toString());
                    if (fromIndex >= toIndex || toIndex <= 0) {
                        value = Arrays.copyOfRange(data, fromIndex, fromIndex + 1);
                    } else {
                        value = Arrays.copyOfRange(data, fromIndex, toIndex + 1);
                    }
                } else {
                    value = Arrays.copyOfRange(data, fromIndex, fromIndex + 1);
                }
                if (value != null && value.length > 0) {
                    long octValue = 0L;
                    int j = -1;
                    for (int i = value.length - 1; i >= 0; i--, j++) {
                        int d = value[i];
                        if (d < 0) {
                            d += 256;
                        }
                        octValue += Math.round(d * Math.pow(16, 2 * j + 2));
                    }
                    return new Long(octValue).toString();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 十进制的字符串表示转成字节数组
     *
     * @param octString
     *            十进制格式的字符串
     * @param capacity
     *            需要填充的容量(可选)
     * @return 转换后的字节数组
     **/
    private static byte[] octInt2ByteArray(Integer oct, int... capacity) {
        return hexString2ByteArray(Integer.toHexString(oct), capacity);
    }
    /**
     * 16进制的字符串表示转成字节数组
     *
     * @param hexString
     *            16进制格式的字符串
     * @param capacity
     *            需要填充的容量(可选)
     * @return 转换后的字节数组
     **/
    private static byte[] hexString2ByteArray(String hexString, int... capacity) {
            hexString = hexString.toLowerCase();
            if (hexString.length() % 2 != 0) {
                hexString = "0" + hexString;
            }
            int length = hexString.length() / 2;
            if (length < 1) {
                length = 1;
            }
            int size = length;
            if (capacity != null && capacity.length > 0 && capacity[0] >= length) {
                size = capacity[0];
            }
            final byte[] byteArray = new byte[size];
            int k = 0;
            for (int i = 0; i < size; i++) {
                if (i < size - length) {
                    byteArray[i] = 0;
                } else {
                    byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
                    if (k + 1 < hexString.length()) {
                        byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
                        byteArray[i] = (byte) (high << 4 | low);
                    } else {
                        byteArray[i] = (byte) (high);
                    }
                    k += 2;
                }
            }
            return byteArray;

    }

    /**
     * 连接字节流
     *
     * @return
     */
    private static byte[] append(byte[] datas, byte[] data) {
        if (datas == null) {
            return data;
        }
        if (data == null) {
            return datas;
        } else {
            return concat(datas, data);
        }
    }

    /**
     * 字节流拼接
     *
     * @param data
     *            字节流
     * @return 拼接后的字节数组
     **/
    private static byte[] concat(byte[]... data) {
        if (data != null && data.length > 0) {
            int size = 0;
            for (int i = 0; i < data.length; i++) {
                size += data[i].length;
            }
            byte[] byteArray = new byte[size];
            int pos = 0;
            for (int i = 0; i < data.length; i++) {
                byte[] b = data[i];
                for (int j = 0; j < b.length; j++) {
                    byteArray[pos++] = b[j];
                }
            }
            return byteArray;
        }
        return null;
    }
    private static Integer getCRC162Int(byte[] bytes,Boolean flag) {
        int CRC = 0x0000ffff;
        int POLYNOMIAL = 0x0000a001;

        int i, j;
        for (i = 0; i < bytes.length; i++) {
//	            CRC ^= (int) bytes[i];

            if(bytes[i] <0 ){
                CRC ^= (int) (bytes[i]+256)  ;
            }else{
                CRC ^= (int) bytes[i]  ;
            }


            for (j = 0; j < 8; j++) {
                if ((CRC & 0x00000001) == 1) {
                    CRC >>= 1;
                    CRC ^= POLYNOMIAL;
                } else {
                    CRC >>= 1;
                }
            }
        }
        //高低位转换,看情况使用(譬如本人这次对led彩屏的通讯开发就规定校验码高位在前低位在后,也就不需要转换高低位)
        if(flag){
            CRC = ( (CRC & 0x0000FF00) >> 8) | ( (CRC & 0x000000FF ) << 8);
        }
        return CRC;
    }
}

2 modbus解析为对象的实体类

@Data
public class ModbusDataAnalyzeBean {
    private Integer addr;//地址
    private Integer funcode;//功能码
    private Integer dataType;//1代表16位int,2代表32位Double
    private ArrayList<Double> values;//寄存器值

    public Integer getAddr() {
        return addr;
    }

    public void setAddr(Integer addr) {
        this.addr = addr;
    }

    public Integer getFuncode() {
        return funcode;
    }

    public void setFuncode(Integer funcode) {
        this.funcode = funcode;
    }



    public ArrayList<Double> getValues() {
        return values;
    }

    public void setValues(ArrayList<Double> values) {
        this.values = values;
    }

    public Integer getDataType() {
        return dataType;
    }

    public void setDataType(Integer dataType) {
        this.dataType = dataType;
    }
}

3 拼接为modbus数据的实体类

@Data
public class ModbusDataFormationBean {
    private Integer addr;//地址
    private Integer funcode;//功能码
    private Integer portNumber;//寄存器起始地址
    private Integer dataType;//1代表16位int,2代表32位Double
    private Integer value;//值

    public Integer getAddr() {
        return addr;
    }

    public void setAddr(Integer addr) {
        this.addr = addr;
    }

    public Integer getFuncode() {
        return funcode;
    }

    public void setFuncode(Integer funcode) {
        this.funcode = funcode;
    }

    public Integer getDataType() {
        return dataType;
    }

    public void setDataType(Integer dataType) {
        this.dataType = dataType;
    }



    public Integer getPortNumber() {
        return portNumber;
    }

    public void setPortNumber(Integer portNumber) {
        this.portNumber = portNumber;
    }

    public Integer getValue() {
        return value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }
}

二、开始使用

1.代码调用

 public static void main(String []ags)
    {
        //模拟向2号寄存器写入100
        ModbusDataFormationBean modbusDataFormationBean=new ModbusDataFormationBean();
        modbusDataFormationBean.setAddr(1);//地址1
        modbusDataFormationBean.setFuncode(5);//功能码5代表写入寄存器
        modbusDataFormationBean.setPortNumber(2);//2代表寄存器起始位为2
        modbusDataFormationBean.setValue(100);//向2号寄存器写入100
        modbusDataFormationBean.setDataType(1);//1代表写入的值是16位的
        byte[] modbusData=ModbusTools.data(modbusDataFormationBean);//对象转modbus数据


        //模拟读取返回的3个寄存器数据
        byte[] data={(byte)0x01,(byte)0x03,(byte)0x06,(byte)0x01,(byte)0x67,(byte) 0xff,(byte) 0xb5,(byte)0x00,(byte)0x64,(byte)0xd7,(byte)0x5e};
        ModbusDataAnalyzeBean modbusDataAnalyzeBean =ModbusTools.dataAnalyze(data,1);
        System.out.println("modbus数据解析为对象:"+modbusDataAnalyzeBean.toString());//modbus数据转对象

    }

  测试结果:

       

 

标签:java,int,return,Modbus,length,互转,Integer,byte,public
From: https://www.cnblogs.com/clf125800/p/17342631.html

相关文章

  • 物联网---03.Modbus协议实现与设备的通讯,收发信息,实现对设备信息的采集
    一、扫盲:什么是modbus?       Modbus是由Modicon(现为施耐德电气公司的一个品牌)在1979年发明的,是全球第一个真正用于工业现场的总线协议    Modbus协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通......
  • JavaWeb回顾与小结(一)
    初识前端网页有哪些部分组成文字,图片,音频,视频,超链接网页的本质程序员写的HTML,CSS,JavaScript前端代码前端代码如何转换成网页通过浏览器解析和渲染成用户看到的网页web标准也称网页标准,由一系列的标准组成,大部分由W3C(WorldWideWebConsortium,万维网联盟)复制制......
  • Java:LocalDateTime获取今天的开始时间和结束时间
    代码示例LocalDateTimenow=LocalDateTime.now();intyear=now.getYear();intmonth=now.getMonthValue();intday=now.getDayOfMonth();System.out.println(String.format("%d-%d-%d",year,month,day));//2023-4-21LocalDateTimestartTime=Loca......
  • Java:ArrayList初始化赋值
    测试环境$java-versionjavaversion"1.8.0_251"Java(TM)SERuntimeEnvironment(build1.8.0_251-b08)JavaHotSpot(TM)64-BitServerVM(build25.251-b08,mixedmode)方式一:常规方式List<Integer>list=newArrayList<>();list.add(1);list.add(......
  • 物联网---02.Modbus协议
    一、简介Modbus由MODICON公司于1979年开发,是一种工业现场总线协议标准。1996年施耐德公司推出基于以太网TCP/IP的Modbus协议:ModbusTCP。Modbus协议是一项应用层报文传输协议,包括ASCII、RTU、TCP三种报文类型。标准的Modbus协议物理层接口有RS232、RS422、RS485和以......
  • JavaScript学习笔记
    数组什么是数组?字面理解就是数字的组合其实不太准确,准确的来说数组是一个数据的集合也就是我们把一些数据放在一个盒子里面,按照顺序排好[1,2,3,'hello',true,false]这个东西就是一个数组,存储着一些数据的集合数据类型分类number/string/boolean/undefined/null/ob......
  • java获取到heapdump文件后,如何快速分析?
    原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,非公众号转载保留此声明。简介在之前的OOM问题复盘之后,本周,又一Java服务出现了内存问题,这次问题不严重,只会触发堆内存占用高报警,没有触发OOM,但好在之前的复盘中总结了dump脚本,会在堆占用高时自动执行jstack与jmap,使得我们成功保留了......
  • Java异常中处理return
    Java中的return语句在Java中,return语句用于从一个方法中返回结果,并终止当前方法的执行。在方法中使用return语句后,后续的语句将不会执行。javaCopyCodepublicintadd(inta,intb){intresult=a+b;returnresult;}上面的代码就是一个简单的加法方法,它接受......
  • Java中处理高精度数据计算
    1、为什么要使用高精度计算拿整数举例:在Java中,int和long是两种基本数据类型,而BigInteger是一个对象类型。它们的取值范围如下:-int:32位有符号整数,取值范围为-2^31~2^31-1(即-2147483648~2147483647)。-long:64位有符号整数,取值范围为-2^63~2^63-1(即-9223......
  • Java基础知识点API之Runtime
    一:Runtime的介绍Runtime表示当前虚拟机的运行状态二:Runtime的常用方法方法名说明publicstaticRuntimegetRuntime()当前系统的运行环境publicvoidexit(intstatus)停止虚拟机publicintavailableProcessors()获取cpu线程数publiclongmaxMemoryJVM能从系统中获取总内存大小(单......