Crc_algorithm

CRC

循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用除法及余数的原理来作错误侦测的。

CRC8

常用CRC8的生成多项式 Poly(最终只取低8Bits) Reverse order is from (Bin & 0xFF) Eg.0x31(0011 0001)变成了0x8C (1000 1100)

Type Poly Bin Poly val Raw val Reverse order
CRC-8 x8+x2+x1+1 1 0000 0111 0x07 (0x107) 0xE0
CRC-8/MAXIM x8+x5+x4+1 1 0011 0001 0x31 (0x131) 0x8C
CRC-8 x8+x6+x4+x3+x2+x1 1 0101 1110 0x5E (0x15E) 0x7A


XOR从数据的高位开始,称为顺序异或;对于数据低位先 传的方式,XOR从数据的低位开始,称之为反序异或

  • 区别1:CRC判断的高低位区别,0x01 or 0x80
  • 区别2:CRC poly 不同,顺序和逆序值二进制方式颠倒

顺序异或CRC8

unsigned char crc_msb(unsigned char *ptr, unsigned char len)
{
    unsigned char poly = 0x07;//0x31;
    unsigned char init = 0x00;/* 初始crc值 */
    unsigned char i;

    unsigned char crc=init;
    while(len--)
    {
        crc ^= *ptr++;    /* 每次先与需要计算的数据异或,计算完指向下一数据 */
        for(i=0;i<8;i++)  /* 计算一个字节crc */
        {
            if (crc & 0x80)
                crc = (crc << 1) ^ poly;
            else
                crc = (crc << 1);
        }
    }
    return (crc);
}

逆序异或CRC8

unsigned char crc_lsb(unsigned char *ptr, unsigned char len)
{
    unsigned char poly_inverse = 0xE0;//0x8C;
    unsigned char init = 0x00;/* 初始crc值 */
    unsigned char i;

    unsigned char crc=init;
    while(len--)
    {
        crc ^= *ptr++;  /* 每次先与需要计算的数据异或,计算完指向下一数据 */
        for(i=0;i<8;i++)/* 同样需要计算8次 */
        {
            if (crc & 0x01)  /* 反序异或变成判断最低位是否为1 */
                /* 数据变成往右移位了 */
                /* 计算的多项式从0x31(0011 0001)变成了0x8C (1000 1100) */
                /* 多项式d值,原来的最高位变成了最低位,原来的最低位变成最高位,8位数据高低位交换一下位置 */
                crc = (crc >> 1) ^ poly_inverse;
            else
                crc = (crc >> 1);
        }
    }
    return (crc);
}

CRC8测试用例

demo:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

//DA 01 A0 FF FF 19 14 07 D0 25 6D FF 74 FF 32 02 B8 6D FF FF FF FF FF FF FF FF FF FF FF FF 4B FF
unsigned char data_raw[] = {0xDA,0x01,0xA0,0xFF,0xFF,0x19,0x14,0x07,0xD0, \
                            0x25,0x6D,0xFF,0x74,0xFF,0x32,0x02,0xB8,0x6D, \
                            0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
                            0xFF,0xFF,0xFF,0x4B,0xFF};// CRC8 0x77   maxim

//16 f1 34 12 11
unsigned char data_raw2[] = {0x16, 0xf1, 0x34, 0x12, 0x11};// CRC8---- 0xC7

unsigned char crc_msb(unsigned char *ptr, unsigned char len)
{
    unsigned char poly = 0x07;//0x31;
    unsigned char init = 0x00;/* 初始crc值 */
    unsigned char i;

    unsigned char crc=init;
    while(len--)
    {
        crc ^= *ptr++;    /* 每次先与需要计算的数据异或,计算完指向下一数据 */
        for(i=0;i<8;i++)  /* 下面这段计算过程与计算一个字节crc一样 */
        {
            if (crc & 0x80)
                crc = (crc << 1) ^ poly;
            else
                crc = (crc << 1);
        }
    }
    return (crc);
}

unsigned char crc_lsb(unsigned char *ptr, unsigned char len)
{
    unsigned char poly_inverse = 0xE0;//0x8C;
    unsigned char init = 0x00;/* 初始crc值 */
    unsigned char i;

    unsigned char crc=init;
    while(len--)
    {
        crc ^= *ptr++;  /* 每次先与需要计算的数据异或,计算完指向下一数据 */
        for(i=0;i<8;i++)/* 同样需要计算8次 */
        {
            if (crc & 0x01)  /* 反序异或变成判断最低位是否为1 */
                /* 数据变成往右移位了 */
                /* 计算的多项式从0x31(0011 0001)变成了0x8C (1000 1100) */
                /* 多项式d值,原来的最高位变成了最低位,原来的最低位变成最高位,8位数据高低位交换一下位置 */
                crc = (crc >> 1) ^ poly_inverse;
            else
                crc = (crc >> 1);
        }
    }
    return (crc);
}


int main()
{
    unsigned int crc_value = 0;
    unsigned char data_len = sizeof(data_raw)/sizeof(unsigned char);

    crc_value = crc_msb(data_raw, data_len);
    printf("crc msb is:0x%x\r\n", crc_value);
    crc_value = crc_lsb(data_raw, data_len);
    printf("crc lsb is:0x%x\r\n", crc_value);

    return 0;
}

console output info:

crc msb is:0x69
crc lsb is:0x6f

Process returned 0 (0x0) execution time : 0.035 s
Press any key to continue.


create CRC8 table

生成CRC8 table

unsigned char cal_table_msb(unsigned char value)
{
    unsigned char i, crc;

    crc = value;
    /* 数据往左移了8位,需要计算8次 */
    for (i=8; i>0; --i)
    {
        if (crc & 0x80)  /* 判断最高位是否为1 */
        {
        /* 最高位为1,不需要异或,往左移一位,然后与0x31异或 */
        /* 0x31(多项式:x8+x5+x4+1,100110001),最高位不需要异或,直接去掉 */
            crc = (crc << 1) ^ 0x07;        }
        else
        {
            /* 最高位为0时,不需要异或,整体数据往左移一位 */
            crc = (crc << 1);
        }
    }

    return crc;
}

unsigned char cal_table_lsb(unsigned char value)
{
    unsigned char i, crc;

    unsigned char poly_inverse = 0xE0;//0x8C;

    crc = value;
    /* 数据往左移了8位,需要计算8次 */
    for(i=0;i<8;i++)/* 同样需要计算8次 */
    {
        if (crc & 0x01)  /* 反序异或变成判断最低位是否为1 */
            /* 数据变成往右移位了 */
            /* 计算的多项式从0x31(0011 0001)变成了0x8C (1000 1100) */
            /* 多项式d值,原来的最高位变成了最低位,原来的最低位变成最高位,8位数据高低位交换一下位置 */
            crc = (crc >> 1) ^ poly_inverse;
        else
            crc = (crc >> 1);
    }

    return crc;
}


void  create_crc_table(void)
{
    unsigned short i;
    unsigned char j;

    for (i=0; i<=0xFF; i++)
    {
        if (0 == (i%16))
            printf("\n");

        j = i & 0xFF;
        printf("0x%.2x, ", cal_table_msb(j));  /*依次计算每个字节的crc校验值*/
    }
}

使用CRC8 table

unsigned char cal_crc_table(unsigned char *ptr, unsigned char len) 
{
    unsigned char  crc = 0x00;
    while (len--)
    {
        crc = crc_table[crc ^ *ptr++];
    }
    return (crc);
}



HotPower超级CRC计算器(转载 侵删)

<div style="width:100%; border:none; text-align:left">
    <iframe allowtransparency="yes" frameborder="0" width="700" height="1600" src="/media/HotCRC.html"/>
</div>





作者:EnzoSun
微信关注:勿忘初兴
本文出处:http://sunduoze.github.io/post/crc_algorithm/
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。