【CRC】CRC校验的实现与分析

一、综述

1.引言

在数字世界中,确保数据在传输和存储过程中的准确性至关重要。错误检测机制帮助我们识别和纠正这些过程中可能出现的错误。循环冗余校验(CRC)是一种流行的错误检测技术,它通过特定的算法计算出一个短的校验码,附加在数据包的末尾。自20世纪60年代被提出以来,CRC因其简单性和高效性,在各种通信和存储系统中得到了广泛应用。随着技术的发展,CRC校验不断被优化,以适应不同的应用需求,继续在保障数据完整性方面发挥着重要作用。

2.CRC校验原理

2.1CRC校验的基本原理

CRC校验的基本原理是基于二进制除法和余数的概念。在数据传输或存储前,通过CRC算法对待传输或存储的数据进行处理,以生成一个短的校验码。这个校验码随后会随数据一起发送或保存,用于接收端或读取时的错误检测。

CRC校验通常需要经过以下步骤:

  1. 数据表示:首先,将待传输或存储的数据序列表示为一个长二进制数。
  2. 生成多项式:选择一个预定的生成多项式,它决定了CRC算法的错误检测能力。
  3. 附加零:在数据的二进制表示后面添加与生成多项式位数(减去一位)相同数量的零。这些零是临时的,用于CRC计算过程中的扩展。
  4. 模2除法:使用模2除法(异或运算)将扩展后的数据除以生成多项式,计算得到余数。
  5. 生成校验码:这个余数(CRC校验码)被附加到原始数据的末尾,形成一个新的数据序列。
  6. 错误检测:在接收端,使用相同的生成多项式对接收到的数据(包括CRC校验码)进行同样的模2除法操作。如果余数为零,则认为数据在传输过程中未发生错误;如果余数不为零,则表明数据可能在传输过程中出现了错误。

2.2生成多项式概念与作用

生成多项式是CRC算法的核心,它是一个预定义的二进制多项式,用于确定CRC校验码的计算方式。生成多项式的选择对CRC校验的性能有着决定性的影响。多项式的位数和系数决定了CRC算法能够检测的错误类型和强度。例如,CRC-16、CRC-32等不同标准的CRC算法使用不同的生成多项式,以适应不同的应用场景和错误检测需求。

3.CRC校验的应用

3.1CRC检验不同领域的应用实例

  • 计算机网络:在以太网和无线网络通信中,CRC校验用于确保数据包的完整性。例如,CRC-32通常用于检测网络数据传输中的错误。

  • 文件系统:在文件传输和存储过程中,CRC校验可以用来验证文件的完整性。软件压缩包如ZIP和RAR等常用CRC校验来检测文件是否在传输或存储过程中被损坏。

  • 硬盘驱动器:硬盘制造商使用CRC校验来保护硬盘上的数据,确保数据的准确性和可靠性。

  • 工业控制系统:在自动化和控制系统中,CRC校验用于确保传感器数据和控制命令的准确传输。

  • 通信协议:许多通信协议,如HDLC、PPP和SCSI,采用CRC校验来确保数据传输的准确性和完整性。

3.2CRC检验的优势与局限

①优势

  • 高效性:CRC校验算法相对简单,计算速度快,适合于实时系统和嵌入式设备。

  • 广泛应用:由于其高效性,CRC校验被广泛应用于各种通信协议和数据存储系统中。

  • 良好的错误检测能力:CRC校验能够有效检测出突发错误,尤其是对于单个位错误和连续位错误。

②局限性

  • 安全性较低:CRC校验主要用于错误检测,并不涉及错误纠正。对于安全敏感的应用,CRC校验可能不足以提供所需的安全级别。

  • 碰撞问题:虽然不常见,但存在不同的数据产生相同CRC校验码的可能性,这在某些安全应用中可能是一个问题。

  • 局限性:对于大量数据的错误检测,CRC校验可能不如其他更复杂的校验方法(如哈希函数)那样有效。

4.研究现状

4.1研究进展概述

  • 生成多项式的优化:研究者们致力于寻找更有效的生成多项式,以提高CRC校验的错误检测能力。这些多项式的选择基于它们能够检测特定类型的错误,如连续错误或突发错误。

  • 算法效率的提高:为了适应高速数据传输的需求,研究者们不断优化CRC算法的计算效率。这包括开发更快的计算方法,如使用查表法(预先计算好的CRC值表)来减少实时计算的复杂性。

  • 硬件实现:随着集成电路技术的进步,CRC校验功能越来越多地被集成到硬件中。这不仅提高了数据处理速度,还降低了功耗,特别是在嵌入式系统和移动设备中。

  • 安全性研究:虽然CRC主要用于错误检测,但近年来,研究者也开始探索如何提高CRC校验的安全性,以抵御恶意攻击,例如通过设计更难被预测的生成多项式。

4.2研究现状与改进

  • CRC-32C:这是一种改进的CRC-32算法,使用不同的生成多项式(0x1EDC6F41),它提供了更好的错误检测性能,特别是在处理错误突发时。

  • 多表CRC算法:为了进一步提高CRC校验的速度,研究者提出了使用多个CRC表的方法。这种方法通过并行处理可以显著减少校验所需的时间。

  • 自适应CRC算法:一些研究聚焦于开发自适应的CRC算法,这些算法可以根据数据的特性动态调整其参数,以优化错误检测的性能。

  • CRC在量子计算中的应用:随着量子计算的兴起,研究者开始探索如何将CRC校验应用于量子通信领域,以确保在量子比特上传输的数据的完整性。

二、设计思路

crcLib.h

//保护宏,防止头文件被多次包含
#ifndef __CRCLIB_H__
#define __CRCLIB_H__

//引入标准整数类型头文件,用于定义固定大小的整数类型
#include "stdint.h"

// 定义计算ITU标准的4位CRC校验码的函数
uint8_t crc4_itu(uint8_t *data, uint16_t length);
// 定义计算EPC标准的5位CRC校验码的函数
uint8_t crc5_epc(uint8_t *data, uint16_t length);
// 定义计算ITU标准的5位CRC校验码的函数
uint8_t crc5_itu(uint8_t *data, uint16_t length);
// 定义计算USB标准的5位CRC校验码的函数
uint8_t crc5_usb(uint8_t *data, uint16_t length);
// 定义计算ITU标准的6位CRC校验码的函数
uint8_t crc6_itu(uint8_t *data, uint16_t length);
// 定义计算MMC标准的7位CRC校验码的函数
uint8_t crc7_mmc(uint8_t *data, uint16_t length);
// 定义计算8位CRC校验码的函数
uint8_t crc8(uint8_t *data, uint16_t length);
// 定义计算ITU标准的8位CRC校验码的函数
uint8_t crc8_itu(uint8_t *data, uint16_t length);
// 定义计算ROHC(Robust Header Compression)标准的8位CRC校验码的函数
uint8_t crc8_rohc(uint8_t *data, uint16_t length);
// 定义计算Maxim公司定义的8位CRC校验码的函数,常用于DS18B20温度传感器
uint8_t crc8_maxim(uint8_t *data, uint16_t length);
// 定义计算IBM标准的16位CRC校验码的函数
uint16_t crc16_ibm(uint8_t *data, uint16_t length);
// 定义计算Maxim公司定义的16位CRC校验码的函数
uint16_t crc16_maxim(uint8_t *data, uint16_t length);
// 定义计算USB标准的16位CRC校验码的函数
uint16_t crc16_usb(uint8_t *data, uint16_t length);
// 定义计算Modbus协议的16位CRC校验码的函数
uint16_t crc16_modbus(uint8_t *data, uint16_t length);
// 定义计算CCITT(国际电信联盟)标准的16位CRC校验码的函数
uint16_t crc16_ccitt(uint8_t *data, uint16_t length);
// 定义计算CCITT标准的另一种16位CRC校验码的函数(可能是指初始化值不同)
uint16_t crc16_ccitt_false(uint8_t *data, uint16_t length);
// 定义计算X.25协议的16位CRC校验码的函数
uint16_t crc16_x25(uint8_t *data, uint16_t length);
// 定义计算XMODEM协议的16位CRC校验码的函数
uint16_t crc16_xmodem(uint8_t *data, uint16_t length);
// 定义计算DNP(分布式网络协议)的16位CRC校验码的函数
uint16_t crc16_dnp(uint8_t *data, uint16_t length);
// 定义计算32位CRC校验码的函数
uint32_t crc32(uint8_t *data, uint16_t length);
// 定义计算MPEG-2标准的32位CRC校验码的函数
uint32_t crc32_mpeg_2(uint8_t *data, uint16_t length);

// 结束保护宏
#endif // __CRCLIB_H__

crcLib.c

每个函数都遵循类似的模式:初始化CRC值、遍历输入数据,对每个数据字节进行处理,最后返回计算得到的CRC值。不同的CRC标准通过改变多项式、初始值、反射处理和最终结果的处理进行区分。

#include "crcLib.h"

/******************************************************************************
 * Name:    CRC-4/ITU           x4+x+1
 * Poly:    0x03
 * Init:    0x00
 * Refin:   True
 * Refout:  True
 * Xorout:  0x00
 * Note:
 *****************************************************************************/
uint8_t crc4_itu(uint8_t *data, uint16_t length)
{
    uint8_t i;             // 循环变量
    uint8_t crc = 0;       // 初始化 CRC 值为 0
    while(length--)        // 循环处理输入数据
    {
        crc ^= *data++;        // 将 CRC 值与数据异或,然后移动到下一个数据位
        for (i = 0; i < 8; ++i) // 对数据进行 8 次处理
        {
            if (crc & 1)       // 如果 CRC 的最低位为 1
                crc = (crc >> 1) ^ 0x0C; // 右移一位后与特定值异或
            else
                crc = (crc >> 1);  // 否则只右移一位
        }
    }
    return crc;              // 返回计算得到的 CRC 值
}

/******************************************************************************
 * Name:    CRC-5/EPC           x5+x3+1
 * Poly:    0x09
 * Init:    0x09
 * Refin:   False
 * Refout:  False
 * Xorout:  0x00
 * Note:
 *****************************************************************************/
uint8_t crc5_epc(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint8_t crc = 0x48;     // 初始化 CRC 值为 0x48
    while(length--)
    {
        crc ^= *data++;        // 同上
        for ( i = 0; i < 8; i++ )
        {
            if ( crc & 0x80 )   // 如果 CRC 的第 8 位(从 0 开始计数)为 1
                crc = (crc << 1) ^ 0x48; // 左移一位后与特定值异或
            else
                crc <<= 1;      // 否则只左移一位
        }
    }
    return crc >> 3;         // 返回计算得到的 CRC 值,右移 3 位
}

/******************************************************************************
 * Name:    CRC-5/ITU           x5+x4+x2+1
 * Poly:    0x15
 * Init:    0x00
 * Refin:   True
 * Refout:  True
 * Xorout:  0x00
 * Note:
 *****************************************************************************/
// 同 crc4_itu 函数,但是初始化的 CRC 值和处理方式有所不同
uint8_t crc5_itu(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint8_t crc = 0;                // Initial value
    while(length--)
    {
        crc ^= *data++;                 // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x15;// 0x15 = (reverse 0x15)>>(8-5)
            else
                crc = (crc >> 1);
        }
    }
    return crc;
}

/******************************************************************************
 * Name:    CRC-5/USB           x5+x2+1
 * Poly:    0x05
 * Init:    0x1F
 * Refin:   True
 * Refout:  True
 * Xorout:  0x1F
 * Note:
 *****************************************************************************/
// 处理过程与 crc4_itu 类似,但是使用的多项式和最终结果的处理不同
uint8_t crc5_usb(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint8_t crc = 0x1F;                // 初始化 CRC 值为 0x1F
    while(length--)
    {
        crc ^= *data++;                 // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x14;// 0x14 = (reverse 0x05)>>(8-5)
            else
                crc = (crc >> 1);
        }
    }
    return crc ^ 0x1F;// 最后将结果与 0x1F 异或后返回
}

/******************************************************************************
 * Name:    CRC-6/ITU           x6+x+1
 * Poly:    0x03
 * Init:    0x00
 * Refin:   True
 * Refout:  True
 * Xorout:  0x00
 * Note:
 *****************************************************************************/
// 同 crc4_itu 函数,但是 CRC 值的大小和处理方式有所不同
uint8_t crc6_itu(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint8_t crc = 0;         // Initial value
    while(length--)
    {
        crc ^= *data++;        // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x30;// 0x30 = (reverse 0x03)>>(8-6)
            else
                crc = (crc >> 1);
        }
    }
    return crc;
}

/******************************************************************************
 * Name:    CRC-7/MMC           x7+x3+1
 * Poly:    0x09
 * Init:    0x00
 * Refin:   False
 * Refout:  False
 * Xorout:  0x00
 * Use:     MultiMediaCard,SD,ect.
 *****************************************************************************/
// 同 crc4_itu 函数,但是 CRC 值的大小和处理方式有所不同
uint8_t crc7_mmc(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint8_t crc = 0;        // Initial value
    while(length--)
    {
        crc ^= *data++;        // crc ^= *data; data++;
        for ( i = 0; i < 8; i++ )
        {
            if ( crc & 0x80 )
                crc = (crc << 1) ^ 0x12;        // 0x12 = 0x09<<(8-7)
            else
                crc <<= 1;
        }
    }
    return crc >> 1;
}

/******************************************************************************
 * Name:    CRC-8               x8+x2+x+1
 * Poly:    0x07
 * Init:    0x00
 * Refin:   False
 * Refout:  False
 * Xorout:  0x00
 * Note:
 *****************************************************************************/
// 同 crc4_itu 函数,但是 CRC 值的大小和处理方式有所不同
uint8_t crc8(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint8_t crc = 0;        // Initial value
    while(length--)
    {
        crc ^= *data++;        // crc ^= *data; data++;
        for ( i = 0; i < 8; i++ )
        {
            if ( crc & 0x80 )
                crc = (crc << 1) ^ 0x07;
            else
                crc <<= 1;
        }
    }
    return crc;
}

/******************************************************************************
 * Name:    CRC-8/ITU           x8+x2+x+1
 * Poly:    0x07
 * Init:    0x00
 * Refin:   False
 * Refout:  False
 * Xorout:  0x55
 * Alias:   CRC-8/ATM
 *****************************************************************************/
// 同 crc8 函数,但是初始化的 CRC 值和最终结果的处理不同
uint8_t crc8_itu(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint8_t crc = 0;        // Initial value
    while(length--)
    {
        crc ^= *data++;        // crc ^= *data; data++;
        for ( i = 0; i < 8; i++ )
        {
            if ( crc & 0x80 )
                crc = (crc << 1) ^ 0x07;
            else
                crc <<= 1;
        }
    }
    return crc ^ 0x55;
}

/******************************************************************************
 * Name:    CRC-8/ROHC          x8+x2+x+1
 * Poly:    0x07
 * Init:    0xFF
 * Refin:   True
 * Refout:  True
 * Xorout:  0x00
 * Note:
 *****************************************************************************/
 // 同 crc8 函数,但是初始化的 CRC 值和处理方式有所不同
uint8_t crc8_rohc(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint8_t crc = 0xFF;         // Initial value
    while(length--)
    {
        crc ^= *data++;            // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xE0;        // 0xE0 = reverse 0x07
            else
                crc = (crc >> 1);
        }
    }
    return crc;
}

/******************************************************************************
 * Name:    CRC-8/MAXIM         x8+x5+x4+1
 * Poly:    0x31
 * Init:    0x00
 * Refin:   True
 * Refout:  True
 * Xorout:  0x00
 * Alias:   DOW-CRC,CRC-8/IBUTTON
 * Use:     Maxim(Dallas)'s some devices,e.g. DS18B20
 *****************************************************************************/
// 同 crc8 函数,但是使用的多项式和处理方式有所不同
uint8_t crc8_maxim(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint8_t crc = 0;         // Initial value
    while(length--)
    {
        crc ^= *data++;        // crc ^= *data; data++;
        for (i = 0; i < 8; i++)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x8C;        // 0x8C = reverse 0x31
            else
                crc >>= 1;
        }
    }
    return crc;
}

/******************************************************************************
 * Name:    CRC-16/IBM          x16+x15+x2+1
 * Poly:    0x8005
 * Init:    0x0000
 * Refin:   True
 * Refout:  True
 * Xorout:  0x0000
 * Alias:   CRC-16,CRC-16/ARC,CRC-16/LHA
 *****************************************************************************/
// 处理过程与 crc4_itu 类似,但是 CRC 值的大小和处理方式有所不同
uint16_t crc16_ibm(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint16_t crc = 0;        // Initial value
    while(length--)
    {
        crc ^= *data++;        // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xA001;        // 0xA001 = reverse 0x8005
            else
                crc = (crc >> 1);
        }
    }
    return crc;
}

/******************************************************************************
 * Name:    CRC-16/MAXIM        x16+x15+x2+1
 * Poly:    0x8005
 * Init:    0x0000
 * Refin:   True
 * Refout:  True
 * Xorout:  0xFFFF
 * Note:
 *****************************************************************************/
// 同 crc16_ibm 函数,但是最终结果需要取反
uint16_t crc16_maxim(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint16_t crc = 0;        // Initial value
    while(length--)
    {
        crc ^= *data++;        // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xA001;        // 0xA001 = reverse 0x8005
            else
                crc = (crc >> 1);
        }
    }
    return ~crc;    // crc^0xffff
}

/******************************************************************************
 * Name:    CRC-16/USB          x16+x15+x2+1
 * Poly:    0x8005
 * Init:    0xFFFF
 * Refin:   True
 * Refout:  True
 * Xorout:  0xFFFF
 * Note:
 *****************************************************************************/
// 同 crc16_maxim 函数,但是初始化的 CRC 值不同
uint16_t crc16_usb(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint16_t crc = 0xffff;        // Initial value
    while(length--)
    {
        crc ^= *data++;            // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xA001;        // 0xA001 = reverse 0x8005
            else
                crc = (crc >> 1);
        }
    }
    return ~crc;    // crc^0xffff
}

/******************************************************************************
 * Name:    CRC-16/MODBUS       x16+x15+x2+1
 * Poly:    0x8005
 * Init:    0xFFFF
 * Refin:   True
 * Refout:  True
 * Xorout:  0x0000
 * Note:
 *****************************************************************************/
// 同 crc16_usb 函数
uint16_t crc16_modbus(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint16_t crc = 0xffff;        // Initial value
    while(length--)
    {
        crc ^= *data++;            // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xA001;        // 0xA001 = reverse 0x8005
            else
                crc = (crc >> 1);
        }
    }
    return crc;
}

/******************************************************************************
 * Name:    CRC-16/CCITT        x16+x12+x5+1
 * Poly:    0x1021
 * Init:    0x0000
 * Refin:   True
 * Refout:  True
 * Xorout:  0x0000
 * Alias:   CRC-CCITT,CRC-16/CCITT-TRUE,CRC-16/KERMIT
 *****************************************************************************/
// 同 crc16_ibm 函数,但是使用的多项式和处理方式有所不同
uint16_t crc16_ccitt(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint16_t crc = 0;        // Initial value
    while(length--)
    {
        crc ^= *data++;        // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x8408;        // 0x8408 = reverse 0x1021
            else
                crc = (crc >> 1);
        }
    }
    return crc;
}

/******************************************************************************
 * Name:    CRC-16/CCITT-FALSE   x16+x12+x5+1
 * Poly:    0x1021
 * Init:    0xFFFF
 * Refin:   False
 * Refout:  False
 * Xorout:  0x0000
 * Note:
 *****************************************************************************/
// 同 crc16_ccitt 函数,但是不进行反射处理
uint16_t crc16_ccitt_false(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint16_t crc = 0xffff;        //Initial value
    while(length--)
    {
        crc ^= (uint16_t)(*data++) << 8; // crc ^= (uint6_t)(*data)<<8; data++;
        for (i = 0; i < 8; ++i)
        {
            if ( crc & 0x8000 )
                crc = (crc << 1) ^ 0x1021;
            else
                crc <<= 1;
        }
    }
    return crc;
}

/******************************************************************************
 * Name:    CRC-16/X25          x16+x12+x5+1
 * Poly:    0x1021
 * Init:    0xFFFF
 * Refin:   True
 * Refout:  True
 * Xorout:  0XFFFF
 * Note:
 *****************************************************************************/
// 同 crc16_ccitt 函数,但是初始化的 CRC 值和最终结果的处理不同
uint16_t crc16_x25(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint16_t crc = 0xffff;        // Initial value
    while(length--)
    {
        crc ^= *data++;            // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x8408;        // 0x8408 = reverse 0x1021
            else
                crc = (crc >> 1);
        }
    }
    return ~crc;                // crc^Xorout
}

/******************************************************************************
 * Name:    CRC-16/XMODEM       x16+x12+x5+1
 * Poly:    0x1021
 * Init:    0x0000
 * Refin:   False
 * Refout:  False
 * Xorout:  0x0000
 * Alias:   CRC-16/ZMODEM,CRC-16/ACORN
 *****************************************************************************/
// 同 crc16_ccitt_false 函数
uint16_t crc16_xmodem(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint16_t crc = 0;            // Initial value
    while(length--)
    {
        crc ^= (uint16_t)(*data++) << 8; // crc ^= (uint16_t)(*data)<<8; data++;
        for (i = 0; i < 8; ++i)
        {
            if ( crc & 0x8000 )
                crc = (crc << 1) ^ 0x1021;
            else
                crc <<= 1;
        }
    }
    return crc;
}

/******************************************************************************
 * Name:    CRC-16/DNP          x16+x13+x12+x11+x10+x8+x6+x5+x2+1
 * Poly:    0x3D65
 * Init:    0x0000
 * Refin:   True
 * Refout:  True
 * Xorout:  0xFFFF
 * Use:     M-Bus,ect.
 *****************************************************************************/
 // 同 crc16_x25 函数,但是使用的多项式和处理方式有所不同
uint16_t crc16_dnp(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint16_t crc = 0;            // Initial value
    while(length--)
    {
        crc ^= *data++;            // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xA6BC;        // 0xA6BC = reverse 0x3D65
            else
                crc = (crc >> 1);
        }
    }
    return ~crc;                // crc^Xorout
}

/******************************************************************************
 * Name:    CRC-32  x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1
 * Poly:    0x4C11DB7
 * Init:    0xFFFFFFF
 * Refin:   True
 * Refout:  True
 * Xorout:  0xFFFFFFF
 * Alias:   CRC_32/ADCCP
 * Use:     WinRAR,ect.
 *****************************************************************************/
// 处理过程与 crc4_itu 类似,但是 CRC 值的大小和处理方式有所不同
uint32_t crc32(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint32_t crc = 0xffffffff;        // 初始化 CRC 值为 0xffffffff
    while(length--)
    {
        crc ^= *data++;                // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xEDB88320;// 0xEDB88320= reverse 0x04C11DB7
            else
                crc = (crc >> 1);
        }
    }
    return ~crc;
}

/******************************************************************************
 * Name:    CRC-32/MPEG-2  x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1
 * Poly:    0x4C11DB7
 * Init:    0xFFFFFFF
 * Refin:   False
 * Refout:  False
 * Xorout:  0x0000000
 * Note:
 *****************************************************************************/
// 同 crc32 函数,但是不进行反射处理,且最终结果不取反
uint32_t crc32_mpeg_2(uint8_t *data, uint16_t length)
{
    uint8_t i;
    uint32_t crc = 0xffffffff;  // Initial value
    while(length--)
    {
        crc ^= (uint32_t)(*data++) << 24;// crc ^=(uint32_t)(*data)<<24; data++;
        for (i = 0; i < 8; ++i)
        {
            if ( crc & 0x80000000 )
                crc = (crc << 1) ^ 0x04C11DB7;
            else
                crc <<= 1;
        }
    }
    return crc;
}

main.c

#include <stdio.h>
#include <stdlib.h>
#include "crcLib.h"

int main()
{
    uint8_t data;
    uint8_t crc;

    data = 0x34;
    crc = crc8_maxim(&data, 1);

    printf("data:%02x, crc:%02x\n", data, crc);
    return 0;
}

CRC校验表

#include <stdio.h>

/* 本地调用此函数计算出所有 CRC-8 校验码 */

//正序
unsigned char Cal_CRC8(const unsigned char data) {
	unsigned char i, crc;
	crc = data;
	/* 数据往左移了8位,需要计算8次 */
	for (i = 8; i > 0; i--) {
		/* 判断最高位是否为1 */
		if (crc & 0x80) {
			/* 最高位为1,不需要异或,往左移一位,然后与0x2f异或 */
			/* 0x12f(多项式:x8 + x5 + x3 + x2 + x + 1,  100101111),最高位不需要异或,直接去掉 */

			//按照实际情况,更改这个部分
			crc = (crc << 1) ^ 0x2f;
		} else {
			/* 最高位为0时,不需要异或,整体数据往左移一位 */
			crc = (crc << 1);
		}
	}
	return crc;
}

//需要反序的就调用这个函数
unsigned char cal_table_low_first(unsigned char value) {
	unsigned char i, crc;

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

	return crc;
}

int main() {
	unsigned char j = 0;
	int count = 1;
	for (unsigned int i = 0; i < 256; i++) {
		j = Cal_CRC8(i);
		if (count %  16) {
			count++;
			printf("0x%x, ", j);
		} else {
			count++;
			printf("0x%x,\n", j);
		}
	}
	return 0;
}

三、参考资料

CRC校验(模型、手算、程序编写)_crc校验程序-CSDN博客

GitHub - whik/crc-lib-c: 基于C语言的CRC校验库,包括常用的21个CRC参数模型实现

CRC32校验-CSDN博客

CRC校验原理及其使用-CSDN博客

CRC(循环冗余校验)在线计算_ip33.com

CRC_Calc v0.1:http://xz.w10a.com/Small/CRCJISUANQI.zip

格西CRC计算器:http://www.geshe.com/home/products/GToolbox/bin/GCRC.exe

  • 20
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Derek__Robbie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值