CRC CCITT16 原理和实现

在网上找了很多资料, 也看了别人写的CRC的实现代码,但发现都不是很懂,大多都没有注释,于是自己就找一个最简单原理去实现,先后把实现后计算出来的结果和网上一个关于CRC计算的结果相比较,来验证自己是否写的是对的.
这里是一个关于CRC计算的网站.

现在来开始讲解原理部分,我只列出最简单的一部分.
CRC算法将长度为m位的消息对应一个GF(2)多项式M,比如对于4位消息1111,则它对应的多项式为x^3 + x^2 + x^1 + x。发送端和接收端约定一个次数为r的 GF(2)多项式G,称为生成多项式,比如x^3 + 1,r = 3, 它对应的二进制码是1001。在消息后面加上r个0对应的多项式为M’,显然有M’ = Mx^r。用M’除以G将得到一个次数等于或小于r - 1的余数多项式R,其对应的r位数值则为校验码。如下所示:

         1110        商为1110,商有4位,表示进行了4XOR 
     ________ 
1001/1111000        被除数是1111000,除数是1001 
     1001    ^ 
     ---- 
      1100     第一次XOR后得到011,加入下一位0。最高位的0可以消掉了,这样最高位是1,所以下个商是1 
      1001    ^ 
      ---- 
       1010    第二次XOR后得到0101,加入下一位0。最高位的0可以消掉了,这样最高位是1,所以下个商是1 
       1001    ^ 
       ---- 
        0110   第三次XOR后得到0011,加入下一位0。最高位的0可以消掉了,这样最高位是0,所以下个商是0 
        0000    ^ 
        ---- 
         110 ->  最后一次XOR后得到0110,最高位的0可以消掉了,得到余数为110,即为检验码. 
                 注意,余数不是0110,而是110,因为最前面那个0已经被XOR后消掉了! 

可见,除法(XOR)的目的是逐步消掉最高位的1或0!
由于过程是XOR的,所以商是没有意义的,我们不要。我们要的是余数。

上面例子中,生成项是1001,共4位比特,最高位的1,实际上在除法的每次XOR时,都要消掉,所以这个1可不做参考,后3位001才是最重要的!001有3位,所以得到的余数也是3位,因为最后一次除法XOR时,最高位消掉了。所以CRC就是3位比特的。 CRC是3比特,表示它的宽度W=3。也就是说,原始数据后面要加上W=3比特的0进行扩展!

现在开始说说算法的过程了.
“直接计算法”就是直接模拟上面的除法的过程,来得到余数即CRC!
上面的例子中,除数是4位,但最高位是要一直消掉的,所以我们只需要一个3位的寄存器就好了。
计算过程:
待测数据后扩展W=3个比特0,变成1111000;
寄存器初始化置0;
先在寄存器中移入数据111;
寄存器左移一位,并且右边移入下一位数据1。这样最高位1移出,由于最高位是1,故本次的商
是1,要用除数1001来进行XOR,最高位肯定XOR得0,故不管它,只要用低3位001来进行XOR就可
以,即001对寄存器进行XOR,寄存器中得到110,即第一次XOR后的结果(相当于是数据1111与生
成项1001进行了一次XOR,并把最高位0消掉了)。 如果移出的最高位是0,则用0000来进行XOR(0
XOR 后,得到的还是原值)。
一直重复这个过程,就能得到最后余数了。

下面是伪代码:

   声明一个寄存器register并把他中的值置0. 
   把原始的数据后添加w个0. 
   While (还有剩余没有处理的数据) 
      Beginregister中的值左移一位,读入一个新的数据并置于register最低位的位置。 
      If (如果上一步的左移操作中的移出的一位是1) 
         register = register XOR Poly. 
      End 

下面是java代码的实现方式.

public class CRCGenerator {

    /**
     * Convert hex string to bytes array
     * @param hexString
     * @return
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        String allHexChars = "0123456789ABCDEF";
        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;
            byte highByte = (byte) (allHexChars.indexOf(hexChars[pos]) << 4);
            byte lowByte = (byte) (allHexChars.indexOf(hexChars[pos + 1]));
            d[i] = (byte) (highByte | lowByte);
        }
        return d;
    }

    /**
     * Get CRC(CCITT16) code
     * 
     * @param hexString
     * @return
     */
    public static String CCITT16(String hexString) {
        // 1. Initialize crc value to 0;
        int crc = 0x00;

        // 2. Set CRC polynom. CCITT-16: 0x1021 = x16 + x12 + x5 + 1
        int polynomial = 0x1021;

        // 3. Append 4 hex zeros to hex data string as CCITT-16 will generate 16
        // bits(4 hex numbers) of CRC code.
        String hexStringWithZeroEnd = hexString + "0000";

        // 4. Convert complete hex string to bytes array.
        byte[] bytes = hexStringToBytes(hexStringWithZeroEnd);

        // 5. Start doing XOR polynomial
        // 5.1 Move 16 bits data to crc variable from the front two bytes(index
        //  from 0 to 1 totally 2 bytes), you can see that the expression
        //  "crc ^= polynomial" will be not invoked before index is set to 2.
        // 5.2 Start from 3rd byte(index is 2),
        //  Then get highest bit of crc variable.
        //  Then get the next bit of current byte.
        //  Then do "left move 1 bit" to crc variable.
        //  Then put the next bit just got to the lowest bit of crc variable.
        //  Then judge if previous highest bit just got from crc variable is 1.
        //  If yes, then do XOR with polynomial.
        for (int index = 0; index < bytes.length; index++) {
            byte b = bytes[index];

            for (int i = 0; i < 8; i++) {
                // Get highest bit of crc.
                int c15 = crc >> 15 & 0x1;

                // Get the next bit of current byte.
                int bit = b >> (7 - i) & 0x1;

                // Do "left move 1 bit" to crc.
                crc <<= 1;

                // Put the next bit just got to the lowest bit of crc.
                crc |= bit;

                // Judge if previous highest bit just got from crc variable is
                // 1. If yes, then do XOR with polynomial.
                if (c15 == 1) {
                    crc ^= polynomial;
                }
            }
        }

        // 6. Convert int to unsigned int as we just need the last 16 bits data.
        crc &= 0xffff;

        // 7. Convert unsigned int to hex string.
        return Integer.toHexString(crc).toUpperCase();
    }
}   

参考文献:

  • http://my.oschina.net/yumifan/blog/185552
  • http://blog.csdn.net/xiaogugood/article/details/8724745
  • http://www.52rd.com/Blog/Detail_RD.Blog_zx_zx_13124.html
  • http://www.lammertbies.nl/comm/info/crc-calculation.html

你可能感兴趣的:(CRC CCITT16 原理和实现)