一、综述
1.引言
在数字世界中,确保数据在传输和存储过程中的准确性至关重要。错误检测机制帮助我们识别和纠正这些过程中可能出现的错误。循环冗余校验(CRC)是一种流行的错误检测技术,它通过特定的算法计算出一个短的校验码,附加在数据包的末尾。自20世纪60年代被提出以来,CRC因其简单性和高效性,在各种通信和存储系统中得到了广泛应用。随着技术的发展,CRC校验不断被优化,以适应不同的应用需求,继续在保障数据完整性方面发挥着重要作用。
2.CRC校验原理
2.1CRC校验的基本原理
CRC校验的基本原理是基于二进制除法和余数的概念。在数据传输或存储前,通过CRC算法对待传输或存储的数据进行处理,以生成一个短的校验码。这个校验码随后会随数据一起发送或保存,用于接收端或读取时的错误检测。
CRC校验通常需要经过以下步骤:
- 数据表示:首先,将待传输或存储的数据序列表示为一个长二进制数。
- 生成多项式:选择一个预定的生成多项式,它决定了CRC算法的错误检测能力。
- 附加零:在数据的二进制表示后面添加与生成多项式位数(减去一位)相同数量的零。这些零是临时的,用于CRC计算过程中的扩展。
- 模2除法:使用模2除法(异或运算)将扩展后的数据除以生成多项式,计算得到余数。
- 生成校验码:这个余数(CRC校验码)被附加到原始数据的末尾,形成一个新的数据序列。
- 错误检测:在接收端,使用相同的生成多项式对接收到的数据(包括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校验程序-优快云博客
GitHub - whik/crc-lib-c: 基于C语言的CRC校验库,包括常用的21个CRC参数模型实现
CRC_Calc v0.1:http://xz.w10a.com/Small/CRCJISUANQI.zip
格西CRC计算器:http://www.geshe.com/home/products/GToolbox/bin/GCRC.exe