本文仅用于本人学习记录,参考摘录了以下大佬的文章:

CRC8算法_算法_简单的过客-GitCode 开源社区 (csdn.net)

CRC算法原理、推导及实现 - QIYUEXIN - 博客园 (cnblogs.com)

目录

1.CRC8标准生成多项式

2.CRC校验算法

3.算法推导

3.1 仿人算方法

4.直接计算法:

5.查表法


1.CRC8标准生成多项式

CRC-8       x8+x5+x4+1              0x31(0x131)

CRC-8       x8+x2+x1+1              0x07(0x107)

CRC-8       x8+x6+x4+x3+x2+x1       0x5E(0x15E)

注:由于多项式的最高为都为1,并且在代码的crc8计算中,最高位也是不使用的,所以在多项式记录时都去掉了最高位。

2.CRC校验算法

        CRC校验算法,简而言之就是把需要校验的数据与多项式进行循环异或(XOR),XOR的方式与数据传输方式的高位先行(MSB)和低位先行(LSB)有关。

        对于MSB:XOR从数据的高位开始,暂时定义为顺序异或;

        对于LSB:XOR从数据的低位开始,暂时定义为反序异或;

        两种不同的异或方式,即使对应相同的多项式,计算出来的结果也不一样。

3.算法推导

        CRC的算法是基于除法,但不能直接使用除法运算,由于待校验的数据可能会很长,而MCU可能并没有这么大的寄存器;

3.1 仿人算方法

        现在我们假设一个消息数据为1101011011,选取除数为10011,使用CRC算法将消息除以poly:

            1100001010 = Quotient (nobody cares about the quotient)
       _______________
10011 ) 11010110110000 = Augmented message (1101011011 + 0000)
 =Poly  10011,,.,,..|.
        -----,,.,,|...
         10011,.,,|.|.
         10011,.,,|...
         -----,.,,|.|.
              10110...
              10011.|.
              -----...
               010100.
                10011.
                -----.
                 01110
                 00000
                 -----
                  1110 = Remainder = THE CHECKSUM!!!!

        除数poly的左边的高位的作用其实是给人看的(实际上参与运算的是0011),目的是干掉当前最高位的被除数,本质上是让poly和被除数对齐,然后开始XOR运算。

        那么什么情况算是对齐呢? 从例子上看,当被除数和除数的最高位都是1时,就算是对齐了。因此当多项式为0x131(100110001)时,实际参与运算的是0x31(00110001)

        转换成算法的思路就是,你也可以理解成一长串的数据不断的从右边移位到寄存器中,当寄存器最左边溢出的数值是1的时候,那么当前寄存器的数据就可以和poly异或运算了,用算法表示,大概是这样:

                  3   2   1   0   Bits
                +---+---+---+---+
       Pop! <-- |   |   |   |   | <----- Augmented message
                +---+---+---+---+

             1    0   0   1   1   = The Poly


 

4.直接计算法:

typedef unsigned char           uint8_t; 
typedef unsigned short int      uint16_t;
#define CRC8_POLYNOMIAL         0x31 

/*计算多个字节CRC8校验值的函数*/
uint8_t cal_bytes_crc8(uint8_t *data, uint8_t len){ 
    uint8_t crc8 = 0x00;                         /* 计算的初始crc值 */ 
    uint8_t i ;
    while(len--){
        crc8 ^= *data++;                        /* 每次先与需要计算的数据异或,计算完指向下一数据 */  
        for (i = 8; i > 0; --i) {         /* 下面这段计算过程与计算一个字节crc一样 */  
            crc8 = ( crc8 & 0x80 )
              ? (crc8 << 1) ^ CRC8_POLYNOMIAL
              : (crc8 << 1);
        }
    }
    return crc8 ;
}

        上面的crc计算是纯采用逻辑运行的方式,可以看到,需要的运行量也是不少的,每一个字节都需要进行8次判断、移位、或异或操作。可以采用查表法,大大减少计算量,先计算0x00~0xFF每一个字节的crc校验结果,后面就可以通过表来查出每个字节的crc结果,大大减少计算量。


5.查表法

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

// 下面是一个表生成程序:
void  create_crc_table(void)
{
    uint16_t i;
    uint8_t j;
 
    for (i=0; i<=0xFF; i++)
    {
        if (0 == (i%16))
            printf("\n");
 
        j = i&0xFF;
            printf("0x%.2x, ", cal_table_high_first (j));  /*依次计算每个字节的crc校验值*/
    }
}




// 按照多项式 X^8+X^2+X^1+1 生成。
static const unsigned int crc8_table[256] =
{
  0x00, 0x31, 0x62, 0x53, 0xc4, 0xf5, 0xa6, 0x97, 0xb9, 0x88, 0xdb, 0xea, 0x7d, 0x4c, 0x1f, 0x2e, 
  0x43, 0x72, 0x21, 0x10, 0x87, 0xb6, 0xe5, 0xd4, 0xfa, 0xcb, 0x98, 0xa9, 0x3e, 0x0f, 0x5c, 0x6d, 
  0x86, 0xb7, 0xe4, 0xd5, 0x42, 0x73, 0x20, 0x11, 0x3f, 0x0e, 0x5d, 0x6c, 0xfb, 0xca, 0x99, 0xa8, 
  0xc5, 0xf4, 0xa7, 0x96, 0x01, 0x30, 0x63, 0x52, 0x7c, 0x4d, 0x1e, 0x2f, 0xb8, 0x89, 0xda, 0xeb, 
  0x3d, 0x0c, 0x5f, 0x6e, 0xf9, 0xc8, 0x9b, 0xaa, 0x84, 0xb5, 0xe6, 0xd7, 0x40, 0x71, 0x22, 0x13, 
  0x7e, 0x4f, 0x1c, 0x2d, 0xba, 0x8b, 0xd8, 0xe9, 0xc7, 0xf6, 0xa5, 0x94, 0x03, 0x32, 0x61, 0x50, 
  0xbb, 0x8a, 0xd9, 0xe8, 0x7f, 0x4e, 0x1d, 0x2c, 0x02, 0x33, 0x60, 0x51, 0xc6, 0xf7, 0xa4, 0x95, 
  0xf8, 0xc9, 0x9a, 0xab, 0x3c, 0x0d, 0x5e, 0x6f, 0x41, 0x70, 0x23, 0x12, 0x85, 0xb4, 0xe7, 0xd6, 
  0x7a, 0x4b, 0x18, 0x29, 0xbe, 0x8f, 0xdc, 0xed, 0xc3, 0xf2, 0xa1, 0x90, 0x07, 0x36, 0x65, 0x54, 
  0x39, 0x08, 0x5b, 0x6a, 0xfd, 0xcc, 0x9f, 0xae, 0x80, 0xb1, 0xe2, 0xd3, 0x44, 0x75, 0x26, 0x17, 
  0xfc, 0xcd, 0x9e, 0xaf, 0x38, 0x09, 0x5a, 0x6b, 0x45, 0x74, 0x27, 0x16, 0x81, 0xb0, 0xe3, 0xd2, 
  0xbf, 0x8e, 0xdd, 0xec, 0x7b, 0x4a, 0x19, 0x28, 0x06, 0x37, 0x64, 0x55, 0xc2, 0xf3, 0xa0, 0x91, 
  0x47, 0x76, 0x25, 0x14, 0x83, 0xb2, 0xe1, 0xd0, 0xfe, 0xcf, 0x9c, 0xad, 0x3a, 0x0b, 0x58, 0x69, 
  0x04, 0x35, 0x66, 0x57, 0xc0, 0xf1, 0xa2, 0x93, 0xbd, 0x8c, 0xdf, 0xee, 0x79, 0x48, 0x1b, 0x2a, 
  0xc1, 0xf0, 0xa3, 0x92, 0x05, 0x34, 0x67, 0x56, 0x78, 0x49, 0x1a, 0x2b, 0xbc, 0x8d, 0xde, 0xef, 
  0x82, 0xb3, 0xe0, 0xd1, 0x46, 0x77, 0x24, 0x15, 0x3b, 0x0a, 0x59, 0x68, 0xff, 0xce, 0x9d, 0xac

};

//采用查表法计算crc代码如下:
uint8_t cal_crc_table(uint8_t *data, uint8_t len){

        uint8_t crc8 = 0x00;

        while (len --){
                crc8 = crc8_table[crc8 ^ *data++];
        }
        return crc8 ;
}




 

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐