赢一个双肩背包 有多难? 戳一下试试看! →_→ 百度上介绍CRC计算原理和方法的文章一大推,也许是我太愚笨,花了几个小时的时间也没有完全看明白。最终经过我不断的尝试和研究,终于把整个计算过程搞清楚了。做个记录总结一下。。。 下面直奔主题,网上找了两个计算CRC的软件,输入同样的数据,选择同样的算法,得到的结果一样, 这两个软件的对应关系如下: 把CRC Calculator Info 中的这几个参数弄明白,CRC的过程你也就清楚了 Name:就是算法的名称,比如对于16bit的CRC来说就有好多个名字,也就是虽然多事16 bit CRC,但是计算方式也有好多种 Width:指的CRC校验值的长度,通常有8bit,16bit,24bit,32bit等。 Poly:是多项式的值,以上面图中的CRC-8:x8+x2+x+1为例,它表示二进制为100000111, 去掉最高位的1,十六进制表示就是0x07 Init: Init 的位数和Poly的位数相同,它的值为全0或者全F,当全为0时,在算法开始前对数据(这个数据是根据RefIn的值得到的)后面补上CRC位数个0后就可以进行后续计算了。当全为1时,表示在算法开始前对数据的前CRC位数(高位)先和对应位数个1进行异或(即:前CRC位数的值按位取反),再在后面补上CRC位数个0,才进行后续计算。 RefIn和Refout:它们要么全为False,要么全为True, RefIn为False表示,输入的原始数据的每个字节的第7位作为最高有效位,第0为作为最低有效位,即正常计算即可 当RefIn为True时,输入的原始数据的每个字节需要做个逆序的处理,注意:针对的每个字节,而不是整个数据,以一个4字节的原始数据为例: 当Refout为False时,输出不做处理,当Refout为True,需要对输出数据做一次整个数据的逆序处理,注意:这里做的逆序和RefIn不同,它不是按字节逆序,而是整个逆序,以CRC-32为例来说明,最后的数据为32位,当Refout为True时,翻转如下: XorOut:表示根据上面参数计算完后,和这个数再进行一次异或。 下面分析一下上面的结果0x79的由来: 1) 0x13 对应二进制为00010011 2) 由于RefIn为False,所以0x13不做处理还是00010011 3) 因为Init为0x00,00010011后面加8个0即可,输入数据变为0001001100000000 4) 多项式为x8+x2+x+1 对应二进制100000111,将上述0001001100000000 除以该多项式对应的100000111 整个计算过程如下: 10011 QUOTIENT _________________ 100000111 ) 0001001100000000 DIVIDEND DIVISOR ) 100000111 ------------- 110111000 100000111 --------- 异或运算 101111110 100000111 --------- 01111001 REMAINDER 说明:上述的计算没有使用通常除法运算中用到的减法,这里用异或代替了减法 最后得到余数:01111001 7)由于RefOuT为False,所以余数不变,还为01111001 8)由于Xorout为0,表示不用再取反,所以最终的结果就是01111001,即十六进制0x79 算一个不过瘾,我们再来计算一个 这一次和上面唯一的不同是将初始值由原来的0x00换为了0xFF,没错这个例子就是给大家演示初始值到底什么意思. 下面分析一下上面的结果0x79的由来: 1) 0x13 对应二进制为00010011 2) 由于RefIn为False,所以0x13不做处理还是00010011 3)因为Init为0xFF,00010011的高8位要先与0xFF异或,输入数据变为11101100,后面再加入8个0,变为 1110110000000000 4) 多项式为x8+x2+x+1 对应二进制100000111,将上述1110110000000000 除以该多项式对应的100000111 整个计算过程如下: 11101110 QUOTIENT _________________ 100000111 ) 1110110000000000 DIVIDEND DIVISOR ) 100000111 ------------- 110111110 100000111 --------- 异或运算 101110010 100000111 --------- 111010100 100000111 --------- 110100110 100000111 --------- 101000010 100000111 --------- 10001010 00000000 --------- 10001010 REMAINDER 最后得到余数:10001010 7)由于RefOuT为False,所以余数不变,还为10001010 8)由于Xorout为0,表示不用再取反,所以最终的结果就是10001010,即十六进制0x8A 这个例子演示了初始值的含义,我们再看最后一个例子,这个例子演示了RefIn和RefOut为True的具体含义 1) 0x13 对应二进制为00010011 2) 由于RefIn为True,所以0x13需要逆序一下得到11001000 3) 因为Init为0x00,所以2)的到11001000后面直接添加4个0即可,得到110010000000 4) 多项式为x4+x+1 对应二进制10011,将上述110010000000 除以10011 整个计算过程如下: 11011110 QUOTIENT ______________ 10011 ) 110010000000 DIVIDEND DIVISOR ) 10011 ------------- 10100 10011 --------- 11100 10011 --------- 11110 10011 --------- 11010 10011 --------- 10010 10011 --------- 00010 00000 --------- 0010 REMAINDER 最后得到余数:0010 7)由于RefOuT为True,所以余数要逆序变为0100 8)由于Xorout为0,表示不用再取反,所以最终的结果就是0100 相信大家把上述那个计算过程弄明白,CRC的计算原理也就清楚了。至于软件代码上如何具体实现,以后再探讨。对于Kinetis MCU来说,很多MCU本身集成了硬件CRC模块,你只需要配置配置寄存器,就可以算出CRC结果了。但是不管对于软件实现还是硬件实现,理论基础永远是第一位的。
|
|