基于Java实现的ModbusCRC校验工具

循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或电脑文件等数据产生简短固定位数校验码的一种散列函数,主要用来检测或校验数据传输或者保存后可能出现的错误,它是利用除法及余数的原理来作错误侦测的。本文是基于Java语言来实现对Modbus数据的CRC校验的一种实现,可移植性强,主要针对公司嵌入式软件(或系统)传输到上位机的字节数组进行校验和上位机根据指定的数据生成CRC。

1、CRC循环冗余错误校验计算方法

ModbusCRC-16C(循环冗余错误校验)生成CRC-16校验字节的步聚如下:

2、代码实现

public class ModbusCRC {

    private byte[] mCRC = new byte[2];
    private byte[] source;
    private byte data;
    private byte[] reg = new byte[2];
    private byte[] ploy = new byte[2];
    private byte Op;

    public ModbusCRC(byte[] source) {
        this.source = source;
        //初始化多项式
        int temp = 0xA001;
        ploy = inttoByteArray(temp, 2);
        //初始化寄存器
        temp = 0xFFFF;
        reg = inttoByteArray(temp, 2);
        for (int i = 0; i < source.length; i++) {
            //获取数据
            data = source[i];
            //与寄存器中数据进行异或操作(特别注意是低位)
            reg[0] = (byte) (reg[0] ^ data);
            //移动数据
            for (int j = 0; j < 8; j++) {
                //获取数据的最后一位,即被移动出的数据判断是否与多项式异或
                Op = reg[0];
                //右移一位
                reg = inttoByteArray(byteArraytoInt(reg) >> 1, 2);
                //如果移出数据为1
                if ((Op & 0x01) == 1) {
                    //与多项式进行异或操作
                    reg[0] = (byte) (reg[0] ^ ploy[0]);
                    reg[1] = (byte) (reg[1] ^ ploy[1]);
                }
            }
        }
        mCRC = reg;
    }

    /**
     * 只获取CRC校验结果
     */
    public byte[] getCRC() {
        return mCRC;
    }

    /**
     * 获取带CRC检验的数据
     */
    public byte[] getSourceWithCRC() {
        byte[] sourceWithCRC = new byte[source.length + mCRC.length];
        System.arraycopy(source, 0, sourceWithCRC, 0, source.length);
        System.arraycopy(mCRC, 0, sourceWithCRC, source.length, mCRC.length);
        return sourceWithCRC;
    }

    /**
     * 整型转字节数组
     */
    private byte[] inttoByteArray(int iSource, int iArrayLen) {
        byte[] bLocalArr = new byte[iArrayLen];
        for (int i = 0; (i < 4) && (i < iArrayLen); i++) {
            bLocalArr[i] = (byte) (iSource >> 8 * i & 0xFF);
        }
        return bLocalArr;
    }

    /**
     * 字节数组转整型
     */
    private int byteArraytoInt(byte[] bRefArr) {
        int iOutcome = 0;
        byte bLoop;

        for (int i = 0; i < bRefArr.length; i++) {
            bLoop = bRefArr[i];
            iOutcome += (bLoop & 0xFF) << (8 * i);
        }
        return iOutcome;
    }

    /**
     * 输入带CRC的元数据,校验CRC是否正确
     *
     * 如果正确则返回true,反之返回false
     */
    public static boolean checkCRC(byte[] sourceWithCRC) {
        if (sourceWithCRC.length <= 2) {
            return false;
        }
        byte[] source = new byte[sourceWithCRC.length - 2];
        byte[] crcBytes = new byte[2];
        System.arraycopy(sourceWithCRC, source.length, crcBytes, 0, 2);
        System.arraycopy(sourceWithCRC, 0, source, 0, source.length);
        ModbusCRC crc = new ModbusCRC(source);
        return crc.getCRC()[0] == crcBytes[0] && crc.getCRC()[1] == crcBytes[1];
    }
}

3、使用方式

该工具使用简单,现在针对常用的场景进行介绍。

    ModbusCRC.checkCRC(sourceWithCRC) 
    ModbusCRC crc = new ModbusCRC(source);
    //获取带CRC校验结果的数据
    crc.getSourceWithCRC();
    //只获取 CRC校验结果
    crc.getCRC();

标签:Java, 循环冗余校验, Modbus CRC