JAVA使用LRC 校验以及对指令的拼接

因为在做项目的时候,遇到过一种情况 站号为0 ,如果用modbus协议的时候。无法正常发收数据,所以自己做了个对类似modbus发送的报文拼接,由于在网上找的相关LRC的校验,很多有算出来的数据对应不上,然后自己写了一个,如有不足,后续进行修改

3A 30  30  30  36  31  30  30  43  30  30  30  31  44  44  0D   0A

红色部分为站号  

绿色部分为功能码

蓝色部分为地址码

紫色部分为数据


import purejavacomm.NoSuchPortException;
import purejavacomm.PortInUseException;
import purejavacomm.SerialPort;
import purejavacomm.UnsupportedCommOperationException;

import java.io.ByteArrayOutputStream;
import java.util.Scanner;

/**
 * @author
 * @title:
 * @projectName 
 * @description: TODO
 * @date 2021/06/15 001515:07
 */
public class Util {
   //地址码的长度
    private static int ADDRESS_DIGITS = 4;
   //数据位的长度
    private static int DATA_DIGITS = 4;
    private static int SLAVE_DIGITS = 3;
    private static int CODE = 6;
    private static int CODE_DIGITS = 1;

    public static void main(String[] args) {
//     
       byte[]  sendbytes=sendData(0,1,4180);

    }

    /**
     * 
     * 站号 支持 如30 30 30  三位
     * 数据位  30  30  30  31  四位   如果想修改支持的数据位 在代码里面相关数组容量进行修改
     *
     * @param slave
     * @param datanum
     * @return
     */
    public static byte[] sendData(int slave, int datanum, int address) {
        //---------------地址处理
        String addressStr = intToHexStr(address, ADDRESS_DIGITS);
        byte[] addressByte = hexStrToBytes(addressStr, ADDRESS_DIGITS);
        //---------------站号的处理
        String slaveStr = intToHexStr(slave, SLAVE_DIGITS);
        byte[] slaveByte = hexStrToBytes(slaveStr, SLAVE_DIGITS);
        //----------------数据的处理
        String dataStr = intToHexStr(datanum, DATA_DIGITS);
        byte[] dataByte = hexStrToBytes(dataStr, DATA_DIGITS);
        //3A 30  30  30  36  31  30  30  43  30  30  30  31  44  44  0D   0A
        //36->rtu 的 06功能码
        //31  30  30  43 ——>rtu 100C ——>地址码  4180(des)
        //----------------------------功能码
        String codeStr = intToHexStr(CODE, CODE_DIGITS);
        byte[] code = hexStrToBytes(codeStr, CODE_DIGITS);
        byte[] codeAndAddress = merge(code, addressByte);
        byte[] start = new byte[]{0x3A};
        byte[] openByte = merge(start, merge(slaveByte, codeAndAddress));
        //--------------------------------lrc
        String hex = slaveStr + codeStr + addressStr + dataStr;
        byte[] dataLrc = getLrc(decode(hex));
        byte[] startDataBytes = merge(openByte, dataByte);
        //开头+lrc
        byte[] dataAndLrc = merge(startDataBytes, dataLrc);
        //加上结尾
        byte[] endbytes = new byte[]{0x0D, 0x0A};
        byte[] sendBytes = merge(dataAndLrc, endbytes);
        return sendBytes;

    }

    /**
     * 把字符串转换成字节数组
     *
     * @param hexString
     * @return
     */
    public static byte[] hexString2Bytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (char2Byte(hexChars[pos]) << 4 | char2Byte(hexChars[pos + 1]));
        }
        return d;
    }

    private static byte char2Byte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    public static final String toHex(byte b) {
        return ("0x" + "0123456789ABCDEF".charAt(0xf & b >> 4) + "0123456789ABCDEF".charAt(b & 0xf));
    }

    /**
     * 把byte[]转成char[]
     *
     * @param bytes
     * @return
     */
    public static char[] bytesToChars(byte[] bytes) {
        String s = new String(bytes);
        char chars[] = s.toCharArray();
        return chars;
    }

    public static int parse(String str) {
//32位 为负数

        if (32 == str.length()) {
            str = "-" + str.substring(1);

            return -(Integer.parseInt(str, 2) + Integer.MAX_VALUE + 1);

        }
        return Integer.parseInt(str, 2);

    }

    /**
     * 字符串转二进制数组
     *
     * @param str
     * @return
     */
    public static byte[] lrcStrToBytes(String str) {

        byte[] bytes1 = str.getBytes();
        StringBuilder binary1 = new StringBuilder();
        for (byte b : bytes1) {
            int val = b;
            for (int i = 0; i < 8; i++) {
                binary1.append((val & 128) == 0 ? 0 : 1);
                val <<= 1;
            }
            // binary.append(' ');
        }
        String[] binaryStr1 = binary1.toString().split(",");
        byte[] byteArray1 = new byte[binaryStr1.length];
        for (int i = 0; i < byteArray1.length; i++) {
            byteArray1[i] = (byte) parse(binaryStr1[i]);
        }
        return byteArray1;
    }

    /**
     * 字符串转16进制字符串
     *
     * @param str
     * @return
     */
    public static String convertStringToHex(String str) {

        char[] chars = str.toCharArray();

        StringBuffer hex = new StringBuffer();
        for (int i = 0; i < chars.length; i++) {
            hex.append(Integer.toHexString((int) chars[i]));
        }

        return hex.toString();
    }

    /**
     * str 转strLength位字符串  不足补0
     *
     * @param str
     * @param strLength
     * @return
     */
    public static String strtoLengthstr(String str, int strLength) {
        int strLen = str.length();
        if (strLen < strLength) {
            while (strLen < strLength) {
                StringBuffer sb = new StringBuffer();
                sb.append("0").append(str);//左补0
//    sb.append(str).append("0");//右补0
                str = sb.toString();
                strLen = str.length();
            }
        }

        return str;
    }


    /**
     * 合并数组
     *
     * @param startbytes
     * @param endbytes
     * @return
     */
    public static byte[] merge(byte[] startbytes, byte[] endbytes) {
        ByteArrayOutputStream sendData = new ByteArrayOutputStream();
        sendData.write(startbytes, 0, startbytes.length);
        sendData.write(endbytes, 0, endbytes.length);
        byte[] bytes = sendData.toByteArray();
        return bytes;
    }

    /**
     * 获取lrc校验
     *
     * @param hex 3030.....的数据
     * @return
     */
    public static byte[] getLrc(String hex) {
        String javaStr = makeChecksum(hex);
        byte[] bytes = parseHexStr2Byte(javaStr);
        byte temp;
        for (int i = 0; i < bytes.length; i++) {
            temp = bytes[i];
            bytes[i] = (byte) (~temp);
        }
        String bths = parseByte2HexStr(bytes);
        String lrc = makeChecksum(bths + "01").toUpperCase();
        String lrc1 = lrc.substring(0, 1).toUpperCase();
        String lrc2 = lrc.substring(1, 2).toUpperCase();
        byte[] byteArray1 = lrcStrToBytes(lrc1);
        byte[] byteArray2 = lrcStrToBytes(lrc2);
        //lrc  校验数组
        byte[] dataLrc = merge(byteArray1, byteArray2);
        return dataLrc;
    }

    /**
     * 十六进制字符串 -----》10进制字符串
     *
     * @param bytes
     * @return
     */

    public static String decode(String bytes) {
        String hexString = "0123456789ABCDEF";
        ByteArrayOutputStream baos = new ByteArrayOutputStream(
                bytes.length() / 2);
        // 将每2位16进制整数组装成一个字节
        for (int i = 0; i < bytes.length(); i += 2)
            baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString
                    .indexOf(bytes.charAt(i + 1))));
        return new String(baos.toByteArray());
    }


    /**
     * 16进制求和
     *
     * @param data
     * @return
     */
    public static String makeChecksum(String data) {
        if (data == null || data.equals("")) {
            return "";
        }
        int total = 0;
        int len = data.length();
        int num = 0;
        while (num < len) {
            String s = data.substring(num, num + 2);
            total += Integer.parseInt(s, 16);
            num = num + 2;
        }
        /**
         * 用256求余最大是255,即16进制的FF
         */
        int mod = total % 256;
        String hex = Integer.toHexString(mod);
        len = hex.length();
        // 如果不够校验位的长度,补0,这里用的是两位校验
        if (len < 2) {
            hex = "0" + hex;
        }
        return hex.toUpperCase();
    }


    /**
     * 将二进制转换成16进制
     *
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 将16进制转换为二进制
     *
     * @param hexStr
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2),
                    16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }


    /**
     * int --->16进制字符串
     *
     * @param num
     * @param length
     * @return
     */
    public static String intToHexStr(int num, int length) {
        String hexStr = Integer.toHexString(num).toUpperCase();
        String completionStr = strtoLengthstr(hexStr, length);
        String dataStr = "";
        for (int i = 0; i < length; i++) {
            dataStr += convertStringToHex(completionStr.substring(i, i + 1));
        }
        return dataStr;
    }

    /**
     * 16进制字符串转byte数组
     *
     * @param dataStr
     * @param length
     * @return
     */
    public static byte[] hexStrToBytes(String dataStr, int length) {

        byte[] bytes = new byte[length];
        for (int i = 0; i < length; i++) {
            String dataStrPT = decode(dataStr.substring(i * 2, i * 2 + 2));
            bytes[i] = lrcStrToBytes(dataStrPT)[0];
        }
        return bytes;

    }
}

还有不足 后续还会继续修改

   

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值