CRC16校验原理及实现

 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);
    }
}

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值