CRC-16/X25、CRC-16/CCITT_FALSE、CRC-16/XMODEM校验码

      这几天做北斗定位设备的协议解析,需要进行CRC-16的校验,设备使用的参数模型是CRC-16/X25,本人使用的是Java语言,网上没找到关于CRC-16/X25 的Java版本,都是C语言的多。转换一下记录在这里,方便以后使用。CRC-16/CCITT_FALSE是引用其它网络文章的,已经忘记在哪里。

       在线CRC工具有:http://www.ip33.com/crc.html。

package com.huan.utils;




/**
 * 查表法生成CRC校验码,支持的参数模型为CRC-16/X25校验码
 * 计算法生成CRC校验码,支持的两个参数模型为CRC-16/CCITT_FALSE、CRC-16/XMODEM
 * 
 * 
 * @date 2018年5月31日 上午11:26:21
 * @author huan
 * @since version
 */
public class CRCUtil {
    private static int crc16_ccitt_table[] = { 0X0000, 0X1189, 0X2312, 0X329B, 0X4624, 0X57AD, 0X6536, 0X74BF, 
   0X8C48, 0X9DC1, 0XAF5A, 0XBED3, 0XCA6C, 0XDBE5, 0XE97E, 0XF8F7, 
   0X1081, 0X0108, 0X3393, 0X221A, 0X56A5, 0X472C, 0X75B7, 0X643E, 
   0X9CC9, 0X8D40, 0XBFDB, 0XAE52, 0XDAED, 0XCB64, 0XF9FF, 0XE876, 
   0X2102, 0X308B, 0X0210, 0X1399, 0X6726, 0X76AF, 0X4434, 0X55BD, 
   0XAD4A, 0XBCC3, 0X8E58, 0X9FD1, 0XEB6E, 0XFAE7, 0XC87C, 0XD9F5, 
   0X3183, 0X200A, 0X1291, 0X0318, 0X77A7, 0X662E, 0X54B5, 0X453C, 
   0XBDCB, 0XAC42, 0X9ED9, 0X8F50, 0XFBEF, 0XEA66, 0XD8FD, 0XC974, 
   0X4204, 0X538D, 0X6116, 0X709F, 0X0420, 0X15A9, 0X2732, 0X36BB, 
   0XCE4C, 0XDFC5, 0XED5E, 0XFCD7, 0X8868, 0X99E1, 0XAB7A, 0XBAF3, 
   0X5285, 0X430C, 0X7197, 0X601E, 0X14A1, 0X0528, 0X37B3, 0X263A, 
   0XDECD, 0XCF44, 0XFDDF, 0XEC56, 0X98E9, 0X8960, 0XBBFB, 0XAA72, 
   0X6306, 0X728F, 0X4014, 0X519D, 0X2522, 0X34AB, 0X0630, 0X17B9, 
   0XEF4E, 0XFEC7, 0XCC5C, 0XDDD5, 0XA96A, 0XB8E3, 0X8A78, 0X9BF1, 
   0X7387, 0X620E, 0X5095, 0X411C, 0X35A3, 0X242A, 0X16B1, 0X0738, 
   0XFFCF, 0XEE46, 0XDCDD, 0XCD54, 0XB9EB, 0XA862, 0X9AF9, 0X8B70, 
   0X8408, 0X9581, 0XA71A, 0XB693, 0XC22C, 0XD3A5, 0XE13E, 0XF0B7, 
   0X0840, 0X19C9, 0X2B52, 0X3ADB, 0X4E64, 0X5FED, 0X6D76, 0X7CFF, 
   0X9489, 0X8500, 0XB79B, 0XA612, 0XD2AD, 0XC324, 0XF1BF, 0XE036, 
   0X18C1, 0X0948, 0X3BD3, 0X2A5A, 0X5EE5, 0X4F6C, 0X7DF7, 0X6C7E, 
   0XA50A, 0XB483, 0X8618, 0X9791, 0XE32E, 0XF2A7, 0XC03C, 0XD1B5, 
   0X2942, 0X38CB, 0X0A50, 0X1BD9, 0X6F66, 0X7EEF, 0X4C74, 0X5DFD, 
   0XB58B, 0XA402, 0X9699, 0X8710, 0XF3AF, 0XE226, 0XD0BD, 0XC134, 
   0X39C3, 0X284A, 0X1AD1, 0X0B58, 0X7FE7, 0X6E6E, 0X5CF5, 0X4D7C, 
   0XC60C, 0XD785, 0XE51E, 0XF497, 0X8028, 0X91A1, 0XA33A, 0XB2B3, 
   0X4A44, 0X5BCD, 0X6956, 0X78DF, 0X0C60, 0X1DE9, 0X2F72, 0X3EFB, 
   0XD68D, 0XC704, 0XF59F, 0XE416, 0X90A9, 0X8120, 0XB3BB, 0XA232, 
   0X5AC5, 0X4B4C, 0X79D7, 0X685E, 0X1CE1, 0X0D68, 0X3FF3, 0X2E7A, 
   0XE70E, 0XF687, 0XC41C, 0XD595, 0XA12A, 0XB0A3, 0X8238, 0X93B1, 
   0X6B46, 0X7ACF, 0X4854, 0X59DD, 0X2D62, 0X3CEB, 0X0E70, 0X1FF9, 
   0XF78F, 0XE606, 0XD49D, 0XC514, 0XB1AB, 0XA022, 0X92B9, 0X8330, 
   0X7BC7, 0X6A4E, 0X58D5, 0X495C, 0X3DE3, 0X2C6A, 0X1EF1, 0X0F78  
};  


    /**
    * 采用查表法,根据数据生成CRC校验码
    * 
    * @param message  校验值,为需要校验的字节
    * @return 
    */
    public static String CRC_16_X25(byte[] message) {
        int crc_reg = 0xffff;//CRC校验时初值
        for (int i = 0; i < message.length; i++) {
            crc_reg = (crc_reg >> 8) ^ crc16_ccitt_table[(crc_reg ^ message[i]) & 0xff];
        }
        return Integer.toHexString(~crc_reg & 0xffff).toUpperCase();
    }


    public static String CRC_16_CCITT_FALSE(byte[] bytes, int length) {
        int crc = 0xffff; // initial value
        int polynomial = 0x1021; // poly value
        for (int index = 0; index < bytes.length; index++) {
            byte b = bytes[index];
            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;
        // 输出String字样的16进制
        String strCrc = Integer.toHexString(crc).toUpperCase();
        return strCrc;
    }


    public static String CRC_16_XMODEM(byte[] bytes, int length) {
        int crc = 0x0000; // initial value
        int polynomial = 0x1021; // poly value
        for (int index = 0; index < bytes.length; index++) {
            byte b = bytes[index];
            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;
        // 输出String字样的16进制
        String strCrc = Integer.toHexString(crc).toUpperCase();
        return strCrc;
    }


    public static void main(String[] arg) {
        byte[] data2 = new byte[] { (byte) 0xAA, 0x0C, 0x01, 0x00, 0x01, 0x00, 0x00, 0x04, 0x05, 0x17, 0x05, 0x01,
(byte) 0xA0, (byte) 0x86, 0x01, 0x00 };
        //例如:
        //AA 0C 01 00 01 00 00 04 05 17 05 01 A0 86 01 00

        //使用CRC-16/CCITT-FALSE计算得到F2E3
        //使用CRC-16/XMODEM计算得到98E9
        //使用CRC-16/X25计算得到A27A
        //验证结果如下


        String result1 = CRC_16_CCITT_FALSE(data2, data2.length); //F2E3
        String result2 = CRC_16_XMODEM(data2, data2.length); //98E9
        String result3 = CRC_16_X25(data2); //A27A
        System.out.println(result1);
        System.out.println(result2);
        System.out.println(result3);

        System.out.println(HexStringBytesUtil.bytes2HexString(data2));
    }

}

辅助类:

package com.huan.utils;

public class HexStringBytesUtil {
    //十六进制的字节数组转十六进制形式的字符串
    public static String bytes2HexString(byte[] b) {
        String ret = "";
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret += hex.toUpperCase();
        }
        return ret;

    }

    //十六进制形式的字符串转十六进制的字节数据
    public static byte[] hexStr2BinArr(String hexString){  
        //hexString的长度对2取整,作为bytes的长度  
        int len = hexString.length()/2;  
        byte[] bytes = new byte[len];  
        byte high = 0;//字节高四位  
        byte low = 0;//字节低四位  
        for(int i=0;i

验证程序结果,打开在线工具 http://www.ip33.com/crc.html:

CRC-16/X25、CRC-16/CCITT_FALSE、CRC-16/XMODEM校验码_第1张图片

你可能感兴趣的:(CRC-16)