CRC校验的个人理解


一、简介:

我用的是直接计算法,非查表法。直接计算更符合我的项目要求,我是使用在STM32单片机上的用的是KEIL。按道理说跟平台无关,整个用的是C语言编写。在网上也有很多对CRC的讲解,我这里就不班门弄斧了,我也是刚学的,很多网站教程都很详细的讲解了CRC的原理和方法,但是比较少有一个总的总结,在这里我只写我的实现过程,或许能帮到刚学习的朋友,顺便记录一下。
这里推荐一个挺不错的讲解网站看完网站的讲解,再看剩下的流程就明白了。

CRC32为例详细解析(菜鸟至老鸟进阶)

二、步骤:

需要计算的数据:data
POLY:多项式
INIT:初始值

XOROUT :结果异或值

1、对数据data倒置(跟第四步的倒置有区别)

这是是针对的每个字节,而不是整个数据,然后赋回给data
例如:
00101011,10110100,00100101,10000011
倒置:
11010100,00101101,10100100,11000001

2、data = data ^ 初始值 INIT

(一般是0xFFFFFFFF,或者0x00000000,也可以自定义)

3、这里就开始计算

判断data最高位为1还是0,
1:data = data^POLY
0:不处理
然后data左移一位再重复执行步骤3,直到得到一个等于或小于 多项式(其实就是按照数据长度一般都是移多少次,8bit:8次,32bit:32次)

4、输出结果处理

data = data ^ 结果异或值 XOROUT (一般是0xFFFFFFFF,或者0x00000000,也可以自定义)

5、倒置整个结果data,(跟第一步不同)

这个是倒置整个数据。

例如:

00101011,10110100,00100101,10000011

倒置:

11000001,10100100,00101101,11010100

6、得到的 最终数据就是 CRC32 的值

这里附上几个CRC校验的网站:

ip33.com

On-line CRC calculation and free library

步骤计算结果:

三、代码分享

1、这是需要用到的代码倒置函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
功 能:倒置数据  :例如10110010,倒置后:01001101
参 数:datar:需倒置的数据
        dlen:倒置数据的长度 8/16/32
返回值:倒置后的数据
*/
unsigned int zRCR_BitReverse(unsigned int datar,unsigned char dlen)  //倒序数据 8/16/32
{
   unsigned int Rvalue=0;
   unsigned char i;
    for(i=0;i<dlen;i++)   //倒置数据
    {
        Rvalue |=((datar>>i)&0x00000001);
        if(i>=(dlen-1)) break;
        Rvalue<<=1;
    }
   return Rvalue;
}

2、CRC计算函数(输入数据为8bit)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/*
功 能:计算CRC32的值
参 数:*data:需计算的数据
        len:数据个数
        repeat:是否接着上一次计算,0:开始新的一轮计算,1:接着上次计算
返回值:CRC32的值
*/
unsinged int zCRC_Value;
unsigned int zCRC_GetCRC(unsigned char *data,unsigned int len,unsigned char repeat)
{
    unsigned int i;
    unsigned int value_temp;
    if(repeat == 0)  //是否继续上次的数据校验
        zCRC_Value = 0XFFFFFFFF;//zCRC_State.zCRC_InitValue;
    while(len !=0)
    {
        //开启输入数据反转
        //1、倒置数据,单独倒置每个Byte数据,非整个数据倒置
        value_temp = 0;
        value_temp |= (zRCR_BitReverse(((*data)&0xFF),8));
        value_temp <<=24; // 将数据移动最高位
        data++;
        //2、数据与初始值求或
        zCRC_Value ^= value_temp;      
        for(i=0;i<8;i++)
        {
            if(zCRC_State.zCRC_Value&0x80000000)
            {
                zCRC_Value <<=1;
                zCRC_Value ^=0x4C11DB7;
            }
            else
                zCRC_Value <<=1;
        }
        len--;
    }
    return zRCR_BitReverse(zCRC_Value^0XFFFFFFFF,32);
}

2、CRC计算函数(输入数据为32bit)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
unsinged int zCRC_Value;
unsigned int zCRC_GetCRC(unsigned int *data,unsigned int len,unsigned char repeat)
{
    unsigned int i;
    unsigned int value_temp;
    if(repeat == 0)  //是否继续上次的数据校验
        zCRC_Value = 0XFFFFFFFF;
    while(len !=0)
    {
        //1、倒置数据,单独倒置每个Byte数据,非整个数据倒置:例如:00100101,10000011倒置过来>> 10100100,11000001
        value_temp = 0;
        for(i=0;i<32;)//
        {
            //先将数据右移i位取1Byte,将二进制倒置一下,再往左移i位,保存value_temp
            value_temp |= (zRCR_BitReverse(((*data>>i)&0xFF),8)<<i);
            i+=8;//i每次进位8bit,1Byte
        }
        data++;
        //2、数据与初始值求或
        zCRC_State.zCRC_Value ^= value_temp;      
        for(i=0;i<32;i++)
        {
            if(zzCRC_Value&0x80000000)
            {
                zCRC_Value <<=1;
                zCRC_Value ^=0x4C11DB7;
            }
            else
                zCRC_Value <<=1;
        }
        len--;
    }
    return zRCR_BitReverse(zCRC_Value^0XFFFFFFFF,32);
}