CRC原理

CRC远没有网上所说那么简单。
 
  首先我们有一个数据流,也就是你需要校验的数据,可以是N BIT,一般我们常用的4,8,16,32,128 BIT,这里我取几个8的倍数,是因为我们的硬件以二进制为基础,所以在存取数据比较容易,无须充填位数来满足寄存器的要求。你用13,17,29 BIT也可以。

  有一点你要记住的是,你选用几个BIT,那么在CRC编码就需要移位几次,8就是移位8次,13就是移位13次,128就是移位128次。

我们看看目前为止的CRC的标准或者行规有:
CRC8  = X8+X5+X4+1
CRC16 = X16+X15+X5+1
CRC12 = X12+X11+X3+X2+1
CRC32 = X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+1
  
CRC-CCITT=X16+X12+X5+1

需要说明的:CRC后所带的数字就是CRC的位数,它与你的数据流是无关的。

CRC8,8位CRC校验。
CRC16,16位CRC校验。
CRC12,12位CRC校验。
CRC32,32位CRC校验。
CRC-CCITT,16位CRC校验。

我们看到5个多项式,它的意义其实就是给出一个与数据流进行异或运算的初始值,
当然你可以更改这个值。比如:

CRC8  = X8+X5+X4+1 》》》 CRC8  = X7+X3+X2+1

CRC16 = X16+X15+X5+1 》》》CRC16 = X15+X5+1

只要你做出的东西是相互连接,不用与其他的机器对接,推荐保密部门使用该方法。
如果修改上述的多项式,那么别人在分析你传送来的数据时,该全部是错码。

补一下课:
异或操作:
              RESULT
  0    0       0
  0    1       1
  1    0       1
  1    1       0

 leasor 发表于 2007-4-5 23:38

2楼: 可靠棵

CRC8  = X8+X5+X4+1

X8 表示第7位需要异或运算
X5 表示第4位需要异或运算
X4 表示第3位需要异或运算
1  表示第0位需要异或运算

如图,首先将CRC所有位清0。
假设我们的数据流为8位,数据流 == 00000011,并且从0位(LSB)开始送入CRC中,则有:

1)1000 1 100
1)1100 1 010
0)0110 0 101
0)1011 1 110
0)0101 1 111
0)1010 0 011
0)1101 1 101
0)1110 0 010

我们看看这个数:
1110 0010 == 0XE2 --- 结果是错的
0100 0111 == 0X47 --- CRC


 leasor 发表于 2007-4-5 23:44

3楼: AAA

CRC16 = X16+X15+X5+1

X16 表示第15位需要异或运算
X15 表示第14位需要异或运算
X5 表示第4位需要异或运算
1  表示第0位需要异或运算

如图,首先将CRC所有位清0。
假设我们的数据流为8位,数据流 == 00000011,并且从0位(LSB)开始送入CRC中,则有:

1)10000 1000000000 1
1)01000 0100000000 0
0)00100 0010000000 0
0)00010 0001000000 0
0)00001 0000100000 0
0)00000 1000010000 0
0)00000 0100001000 0
0)00000 0010000100 0

CRC
0001 0000 1000 0000 == 0X1080

 leasor 发表于 2007-4-5 23:44

4楼: DDDD

CRC12 = X12+X11+X3+X2+1
CRC32 = X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+1

以上述两个例子,自行推倒。

 xwj 发表于 2007-4-5 23:46

5楼: 呵呵,楼上先给我讲讲用^移位8(16)次模2除法是怎么回事好吗?

为什么和十进制、十六进制的除法算出来的模是不同的呢???

呵呵,上次别人发贴偶仔细一算,确实越算越糊涂了:-)


 leasor 发表于 2007-4-5 23:48

6楼: DDDDD

CRC-CCITT=X16+X12+X5+1

比较特殊,所以再说说

CRC-CCITT 不同于 CRC-16在于它是个反相的CRC-16,所谓反相的意义指从第7位(MSB)开始移入CRC移位寄存器,

如图,首先将CRC所有位清0。
假设我们的数据流为8位,数据流 == 00000011,并且从7位(MSB)开始送入CRC中,则有:

0)00000  0000000  0000
0)00000  0000000  0000
0)00000  0000000  0000
0)00000  0000000  0000
0)00000  0000000  0000
0)00000  0000000  0000
1)10000  1000000  1000
1)11000  1100000  1100

CRC
0011 0000 0110 0011 == 0X3063


 leasor 发表于 2007-4-5 23:48

7楼: JJJ

请教高手:

全字节和半字节查表CRC的工作原理的不同在那里?谢谢!


 leasor 发表于 2007-4-5 23:57

8楼: 别急5楼,我来了


   我觉得没有任何问题哦!

   十进制数除数/ 16 == 十进制的商,将除数和商换成二进制,比对结果

   你要问的是不是左右移位的问题?

   右移1位的结果:11001010 》》1100101,原来的数/2
  
   左移1位的结果:11001010 》》110010100,原来的数*2

 

 leasor 发表于 2007-4-6 00:02

9楼: see you later

    如果原来的数不能被2整除的话,好像不能适用移位的方法。

    如果涉及好二进制小数的话,有一个误区:

    (二进制数)11.11
    (十进制数)3.75
     这里0.1 == 0.5 ,0.01 == 0.25

     希望对你有帮助!我下了,明天见

 

 xwj 发表于 2007-4-6 00:13

10楼: 不是的,比如0x0001的CRC是1021,但用计算器什么算都不是这个数啊

比如按这个多项式:CRC-CCITT=X16+X12+X5+1
0x0001 的CRC=0x1021
0x0003 的CRC=0x3063

用什么杨的数学公式能得到这个值呢???

 

 yewuyi 发表于 2007-4-6 08:30

11楼: 呵呵,LZ只是负责转贴

 
签名:

xinyuanpic@163.com
走两步

 

 lixun00 发表于 2007-4-6 09:30

12楼: 如下,

unsigned int cal_crc(unsigned char *pt, unsigned char len)
{
    unsigned char i;
    unsigned int crc=0;
    unsigned char *ptr = pt;
    while(len--!=0)
    {
        for(i=0x80; i!=0; i/=2)
        {
            if((crc&0x8000)!=0)
            {
                crc*=2; crc^=0x1021;
            } /* 余式CRC 乘以2 再求CRC */
            else
                crc*=2;
            if((*ptr&i)!=0)
                crc^=0x1021; /* 再加上本位的CRC */
        }
        ptr++;
    }

    return(crc);
}
 

 leasor 发表于 2007-4-7 11:44

13楼: dddd

让我研究研究答复你~~~~~~~~~


 

 lixun00 发表于 2007-4-7 13:35

14楼: 这里讲的很清楚,不清楚的可以看下高等代数

http://bbs.21ic.com/upfiles/img/20074/20074713353824.pdf
 

 hotpower 发表于 2007-4-7 14:24

15楼: 倒塌了~~~不会CRC算法,只知道结果~~~~

汽车电子失踪了~~~

给我的网站被黑了~~~赶紧备份,因为我自己都没保留~~~
还好,这黑客还有良心~~~

这个程序是我研究CRC多年的总结笔记吧,实际内含加密和解密.
把CRC应用引伸了一节~~~
"计算"实际是加密过程.
"还原"实际是解密过程.


CRC/PEC网上通用计数器
 

 hotpower 发表于 2007-4-7 14:46

16楼: 楼主给的我真算不出来,只会算xwj给出的结果

 xwj 发表于 2007-4-8 23:34

17楼: 研究出来了:

对于但字节,CRC结果不是模,而是0x11021-左移16位的模

既:

CRC(n)=0x11021-(n<<16)%0x11021;

CRC(n)=0x11021-(n*0x10000)%0x11021;

这样,对于有乘加指令的DSP就可以不用查表而 一步算出答案 了

对于多字节的结果不对,还得继续研究下合并规律的简化...

 xwj 发表于 2007-4-8 23:40

18楼: PS: hotpower的程序可以简化了,不用一步步移位了

呵呵

 

 xwj 发表于 2007-4-9 00:11

19楼: 呵呵,都怪资料不准确,害我去由运算结果反推算法,真是晕死了

研究这个主要是因为看到(找到)的程序大家不管是用什么CPU:电脑、单片机、DSP,写的CRC程序都是用的循环移位异或的方式,也就是模2除法。

这个模2除法是针对没有除法器的CPU搞出来的用加减异或指令完成的除法算法啊,只有没有除法器的CPU才会这样算啊!那个效率有多么的低是可想而知的!
而我们实际使用的CPU大多数是有乘法器和除法器的,就算没有用查表也会快很多很多倍,而我看到所有的CRC算法大家都是循环移位异或的方式来算,甚至于电脑上的程序都这样算!
这。。。真是食而不化了...

呵呵,偶以后看到这样写CRC程序的一律BS之!
:-)


资料上说CRC的算法是:
16 位的CRC 码产生的规则是先将要发送的二进制序列数左移16 位(既乘以216 )后,
再除以一个多项式,最后所得到的余数既是CRC 码,如式(2-1)式所示,其中B(X)表
示n 位的二进制序列数,G(X)为多项式,Q(X)为整数,R(X)是余数(既CRC 码)。

     (X)·2^16               R(X)
    ----------   =  Q(X) + ----------
       G(X)                  G(X)


那CRC的结果应该就是:

CRC(X) = R(X) = ((X)<<16) % G(X);

而实际测试的结果却是:
CRC(X) = R(X) = G(X) - ((X)<<16) % G(X);

应该是:R(X)是余数(CRC 码为 G(X)-R(X),这样整个位串再合并上CRC 码就刚好能被多项式G(X)整除)。

对于CRC-CCITT的多项式:X16+X12+X5+1
就是
CRC(n)=0x11021-(n<<16)%0x11021;

CRC(n)=0x11021-(n*0x10000)%0x11021;

唉,CRC的资料只说“R(X)是余数(既CRC 码)”,自己没去仔细看E文资料,就信以为真了,结果全然不对啊,最好竟然去由运算结果反推算法,真是晕死了...

:-(

 
 xwj 发表于 2007-4-9 15:10

21楼: 直接和字节间的关系如下,好像没法进一步化简了:-(

CRC(ABCD)={ CRC(AB)<<8  ^   CRC(  (CRC(AB)/256 ^ CD ) ) }  &  0xffff;
             高字节CRC              CRC:(高字节CRC低8位^低字节)
             只取低16位,高位截除
             --由于有溢出,截除的高位不知道,所以用多项式验证整个16位数得不到正确的结果了

好像没法进一步化简了,
只好按字节执行循环运算了 :-(

 

 xwj 发表于 2007-4-9 15:52

22楼: 整理了下多字节CRC步骤


多字节CRC步骤
 
字节3
字节2
字节1
字节0
说明

 
 
 
AB
CD
源数据

1
AB
00
00
 
高8位左移16位

2
 
CRC(AB)高
CRC(AB)低
 
高8位取模运算

 

3
 
CD
00
00
低8位左移16位

4
 
CD = CRC(AB)高 ^ CD
CD对应CRC(AB)高

5
 
 
CRC(CD)高
CRC(CD)低
低8位取模运算

6
 
 
CRC(ABCD)高
CRC(ABCD)低
高低CRC结果合并

7
 
 
CRC(ABCD) &= 0xffff;
结果只取低16位

下一字节运算 依次循环步骤3~7,直到位串结束。


--由于结果只取低16位,高位截除,而多字节运算是必然有溢出,截除的高位不知道,所以用多项式验证整个16位数得不到正确的结果了

//程序如下,全局int变量crc中保留了前一次的CRC运算结果:
uint table_crc(uchar *ptr,uchar len) // 字节查表法求CRC,查表操作就是一次CRC运算
{
    uchar da;
    while(len--!=0)
    {
        da=(uchar) (crc/256); // 以8 位二进制数暂存CRC 的高8 位
        crc<<=8;              // 左移8 位
        crc^=crc_ta[da^*ptr]; // 高字节和当前数据XOR 再查表
        ptr++;
    }
    return(crc);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值