3

我需要帮助在 Java 中使用多项式 x^16 + x^12 + x^5 + 1 (0x1081) 计算 CCITT 标准 CRC。我在互联网上尝试了许多示例,但每个示例都返回示例中的值之外的其他值。

例如对于这个数组 [0xFC] [05] [11],结果需要是 [27] [56]。

使用此代码:

public static void main(String[] args) {
        byte[] array = new byte[3];
        array[0] = (byte) 0xFC;
        array[1] = (byte) 0x05;
        array[2] = (byte) 0x11;
//        array[3] = (byte) 0x00;
//        array[4] = (byte) 0x00;

        System.out.println(Integer.toHexString(crc16(array)));
    }

    private static final int POLYNOMIAL = 0x1081;
    private static final int PRESET_VALUE = 0xFFFF;

    public static int crc16(byte[] data) {
        int current_crc_value = PRESET_VALUE;
        for (int i = 0; i < data.length; i++) {
            current_crc_value ^= data[i] & 0xFF;
            for (int j = 0; j < 8; j++) {
                if ((current_crc_value & 1) != 0) {
                    current_crc_value = (current_crc_value >>> 1) ^ POLYNOMIAL;
                } else {
                    current_crc_value = current_crc_value >>> 1;
                }
            }
        }
        current_crc_value = ~current_crc_value;

        return current_crc_value & 0xFFFF;
    } 

我得到的结果FA DE不是 [27] [56]

使用此代码:

public static void main(String[] args) { 
        int crc = 0x0000;         
        int polynomial = 0x1081;   

        // byte[] testBytes = "123456789".getBytes("ASCII");

//        byte[] array = args[0].getBytes();
        byte[] array = new byte[3];
        array[0] = (byte) 0xFC;
        array[1] = (byte) 0x05;
        array[2] = (byte) 0x11;

        for (byte b : array) {
            for (int i = 0; i < 8; i++) {
                boolean bit = ((b   >> (7-i) & 1) == 1);
                boolean c15 = ((crc >> 15    & 1) == 1);
                crc <<= 1;
                if (c15 ^ bit) crc ^= polynomial;
             }
        }

        crc &= 0xffff;
        System.out.println("CRC16-CCITT = " + Integer.toHexString(crc));
    }

我明白了CRC16-CCITT = 8dca

使用此代码:

private final int polynomial = 0x1081;

    private int[] table = new int[256];

    public int ComputeChecksum(int[] bytes) {
        int crc = 0xffff;
        for (int i = 0; i < bytes.length; ++i) {
            int index = (crc ^ bytes[i]) % 256;
            crc = (crc >> 8) ^ table[index];
        }
        return crc;
    }

    public CRC162() {
        int value;
        int temp;
        for (int i = 0; i < table.length; ++i) {
            value = 0;
            temp = i;
            for (byte j = 0; j < 8; ++j) {
                if (((value ^ temp) & 0x0001) != 0) {
                    value = (value >> 1) ^ polynomial;
                } else {
                    value >>= 1;
                }
                temp >>= 1;
            }
            table[i] = value;
        }
    }

    public static void main(String[] args) {
        CRC162 c = new CRC162();
        int[] arr = new int[]{0xFC, 0x05, 0x11};
        System.out.println(Integer.toHexString(c.ComputeChecksum(arr)));
    }

我明白了521

希望可以有人帮帮我。我需要这个来与使用 ID003 协议的设备进行通信。

编辑:在http://www.lammertbies.nl/comm/info/crc-calculation.html使用这个在线计算器输入 FC0511 我从 CRC-CCITT (Kermit) 得到 0x2756。

4

4 回答 4

7

x^16 + x^12 + x^5 + 1 不是 0x1081。它是 0x1021。x^5 是 20,而不是 80。(请注意,x^16 已删除。)

此外,反映了您需要的 Kermit CRC,因此多项式被反转,得到 0x8408。

对于此 CRC,您使用零进行初始化并且不对结果进行补码。

因此,相应地修改您的第一个示例,这将计算您想要的内容:

public static void main(String[] args) {
    byte[] array = new byte[3];
    array[0] = (byte) 0xFC;
    array[1] = (byte) 0x05;
    array[2] = (byte) 0x11;
    //        array[3] = (byte) 0x00;
    //        array[4] = (byte) 0x00;

    System.out.println(Integer.toHexString(crc16(array)));
}

private static final int POLYNOMIAL = 0x8408;
private static final int PRESET_VALUE = 0;

public static int crc16(byte[] data) {
    int current_crc_value = PRESET_VALUE;
    for (int i = 0; i < data.length; i++) {
        current_crc_value ^= data[i] & 0xFF;
        for (int j = 0; j < 8; j++) {
            if ((current_crc_value & 1) != 0) {
                current_crc_value = (current_crc_value >>> 1) ^ POLYNOMIAL;
            } else {
                current_crc_value = current_crc_value >>> 1;
            }
        }
    }

    return current_crc_value & 0xFFFF;
}
于 2014-07-11T14:58:28.190 回答
4

这是 Kermit CRC 的另一个版本。这是从http://www.lammertbies.nl/comm/info/crc-calculation.html中的 C 代码直接翻译而来的。优化是在类加载时预先计算任何字节的 CRC 值表,因此剩余的 CRC 计算要简单得多。

public class Crc {

    private static final int POLYNOMIAL = 0x8408;
    private static final int PRESET = 0;
    static private int[] tab;

    static {
        tab = new int[256];
        for (int i = 0; i < 256; i++) {
            tab[i] = initial((byte) i);
        }
    }

    private static int initial(byte c) {
        int crc = 0;
        for (int j = 0; j < 8; j++) {
            if (((crc ^ c) & 1) == 1) {
                crc = ((crc >> 1) ^ POLYNOMIAL);
            } else {
                crc = (crc >> 1);
            }
            c = (byte) (c >> 1);
        }
        return crc;
    }

    private static int update_crc(int crc, byte c) {
        int cc = (0xff & c);

        int tmp = (crc ^ cc);
        crc = (crc >> 8) ^ tab[tmp & 0xff];

        return crc;
    }

    private static int swab(int n) {
        return (((n & 0xFF00) >> 8) + ((n & 0xFF) << 8));
    }

    public static int crc(String str) {
        return crcb(str.getBytes());
    }

    public static int crcb(byte... i) {
        int crc = PRESET;
        for (byte c : i) {
            crc = update_crc(crc, c);
        }
        return swab(crc);
    }

    public static void main(String[] args) {
        int crc = Crc.crcb((byte) 0xFC, (byte) 5, (byte) 0x11);
        System.out.println(Integer.toHexString(crc));
        crc = Crc.crc("123456789");
        System.out.println(Integer.toHexString(crc));
    }
}

输出如预期:

2756
8921
于 2014-07-11T16:07:53.230 回答
2

这不是我的,但对我来说很完美,“DatatypeConverter”是我的项目中已经拥有的东西。这对我来说是一个真实的例子,并且有效。

*  Reads in a sequence of bytes and prints out its 16 bit
*  Cylcic Redundancy Check (CRC-CCIIT 0xFFFF).
*
*  1 + x + x^5 + x^12 + x^16 is irreducible polynomial.

import javax.xml.bind.DatatypeConverter;

public class CRC16CCITT {

    public static void main(String[] args) {
        int crc = 0xFFFF; // initial value
        int polynomial = 0x1021; // 0001 0000 0010 0001 (0, 5, 12), in your case: 0x1081

        // CRC of this should be 28570
        byte[] testBytes = DatatypeConverter.parseHexBinary("00000000000000000000FA00000002009F1D19B87475445E1122330000000000"); 

        for (byte b : testBytes) {
            for (int i = 0; i < 8; i++) {
                boolean bit = ((b >> (7 - i) & 1) == 1);
                boolean c15 = ((crc >> 15 & 1) == 1);
                crc <<= 1;
                if (c15 ^ bit)
                    crc ^= polynomial;
            }
        }

        crc &= 0xffff;
        System.out.println("CRC16-CCITT = " + Integer.toHexString(crc));
        // 6F9A = 28570
    }

}
于 2018-04-04T14:09:25.773 回答
1
    /**
 * converts the given String to CRC16
 * 
 * @param inputStr
 *            - the input string to get the CRC
 * @param polynomial
 *            - the polynomial (divisor)
 * @param crc
 *            - the CRC mask
 * @param isHex
 *            - if true, treat input string as hex, otherwise, treat as
 *            ASCII
 * @return
 */
public static String getCRC16CCITT(String inputStr, int polynomial,
        int crc, boolean isHex) {

    int strLen = inputStr.length();     
    int[] intArray;

    if (isHex) {
        if (strLen % 2 != 0) {
            inputStr = inputStr.substring(0, strLen - 1) + "0"
                    + inputStr.substring(strLen - 1, strLen);
            strLen++;
        }

        intArray = new int[strLen / 2];
        int ctr = 0;
        for (int n = 0; n < strLen; n += 2) {
            intArray[ctr] = Integer.valueOf(inputStr.substring(n, n + 2), 16);
            ctr++;
        }
    } else {
        intArray = new int[inputStr.getBytes().length];
        int ctr=0;
        for(byte b : inputStr.getBytes()){
            intArray[ctr] = b;
            ctr++;
        }
    }

    // main code for computing the 16-bit CRC-CCITT
    for (int b : intArray) {
        for (int i = 0; i < 8; i++) {
            boolean bit = ((b >> (7 - i) & 1) == 1);
            boolean c15 = ((crc >> 15 & 1) == 1);
            crc <<= 1;
            if (c15 ^ bit)
                crc ^= polynomial;
        }
    }

    crc &= 0xFFFF;
    return Integer.toHexString(crc).toUpperCase();
}

适用于 ASCII 和 HEX 计算。

public static void main(String args[]) {

    String testStr = "9142656";

    // XModem ASCII
    System.out.println("CRC-CCITT (XModem) Ascii: "
            + getCRC16CCITT(testStr, 0x1021, 0x0000, false));

    // 0xFFFF ASCII
    System.out.println("CRC-CCITT (0xFFFF) Ascii: "
            + getCRC16CCITT(testStr, 0x1021, 0xFFFF, false));

    // 0x1D0F ASCII
    System.out.println("CRC-CCITT (0x1D0F) Ascii: "
            + getCRC16CCITT(testStr, 0x1021, 0x1D0F, false));

    // XModem Hex
    System.out.println("CRC-CCITT (XModem) Hex: "
            + getCRC16CCITT(testStr, 0x1021, 0x0000, true));

    // 0xFFFF Hex
    System.out.println("CRC-CCITT (0xFFFF) Hex: "
            + getCRC16CCITT(testStr, 0x1021, 0xFFFF, true));

    // 0x1D0F Hex
    System.out.println("CRC-CCITT (0x1D0F) Hex: "
            + getCRC16CCITT(testStr, 0x1021, 0x1D0F, true));

}

输出:

CRC-CCITT (XModem) Ascii: 87F4
CRC-CCITT (0xFFFF) Ascii: 763A
CRC-CCITT (0x1D0F) Ascii: 9F86
CRC-CCITT (XModem) Hex: 57FF
CRC-CCITT (0xFFFF) Hex: D33F
CRC-CCITT (0x1D0F ) 十六进制:59EF

解决方案基于普林斯顿大学http://introcs.cs.princeton.edu/java/61data/CRC16CCITT.java中的示例

于 2016-09-22T09:03:21.317 回答