CRC16校验原理及实现

来源:互联网 发布:毕业论文算法 编辑:程序博客网 时间:2024/05/29 16:50
 CRC码由发送端计算,放置于发送信息报文的尾部。接收信息的设备再重新计算接收到信息报文的CRC,比较计算得到的CRC是否与接收到的相符,如果两者不相符,则表明出错。 校验码的计算多项式为(X16 + X15 + X2 + 1)。具体CRC16码的计算方法是:        1.预置1个16位的寄存器为十六进制FFFF(即全为1);称此寄存器为CRC寄存器;        2.把第一个8位二进制数据 (既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器;        3.把CRC寄存器的内容右移一 位(朝低位)用0填补最高位,并检查右移后的移出位;        4.如果移出位为0:重复第3步(再次右移一位);        如果移出位为1:CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;(Modbus)        5.重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;        6.重复步骤2到步骤5,进行通讯信息帧下一个字节的处理;        7.将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换;        8.最后得到的CRC寄存器内容即为:CRC码。
具体代码类如下:
public class Crcheck {    private static final int POLYNOMIAL = /*0xA053;*//*0x0589*/0xA001;    /*    02 05 00 03 FF 00 的不同crc计算值:    CRC-16 0x127C    CRC-16 (Modbus)    0x097C 对应的多项式为 0xA001    CRC-16 (Sick)  0xE2F0    CRC-CCITT (XModem) 0xF2B8    CRC-CCITT (0xFFFF) 0xFCA8    CRC-CCITT (0x1D0F) 0xC386    CRC-CCITT (Kermit) 0xA63E    CRC-DNP    0x6E28*/    private static final int PRESET_VALUE = 0xFFFF;    public static String getHexString(int i){        String hexString = String.format("%04x",i);        return hexString;    }    /**     * @param data byte[]     * @return 低位在前,高位在后的16进制字符串     */    public static String getCrc16String(byte[] data){        StringBuilder builder = new StringBuilder();        String hex = getHexString(getCrc16(data));        builder.append(hex.substring(2));        builder.append(hex.substring(0,2));        return builder.toString();    }    /**     * @param data String     * @return 低位在前,高位在后的16进制字符串     */    public static String getCrc16String(String data){        StringBuilder builder = new StringBuilder();        String hex = getHexString(getCrc16(data));        builder.append(hex.substring(2));        builder.append(hex.substring(0,2));        return builder.toString();    }    /**     * @param data byte数组     * @return  CRC16校验得到的十进制int     */    public static int getCrc16(byte[] data){        System.out.println("\nCRC 16 calculation progress:\n");        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;    }    /**     * @param str 16进制字符串     * @return CRC16校验得到的十进制int     */    public static int getCrc16(String str){        byte[] data = hexStringToBytes(str);        System.out.println("\nCRC 16 calculation progress:\n");        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;    }    /**     * byte[] 转 16进制字符     *     * @param b     * @return     */    public static String printHexString(byte[] b) {        StringBuffer returnValue = new StringBuffer();        for (int i = 0; i < b.length; i++) {            String hex = Integer.toHexString(b[i] & 0xFF);            if (hex.length() == 1) {                hex = '0' + hex;            }            if (i % 2 == 0) {                returnValue.append(hex.toUpperCase() + "");            } else {                returnValue.append(hex.toUpperCase() + " ");            }        }        return returnValue.toString();    }    /**     * 16进制字符串转byte[]     *     * @param hexString     * @return     */    public static byte[] hexStringToBytes(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) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));        }        return d;    }    private static byte charToByte(char c) {        return (byte) "0123456789ABCDEF".indexOf(c);    }}