常见CRC算法的C实现

简介

在数据储存或者数据传输过程经常需要对数据进行校验,以确保数据的准确性。本文介绍一些常用的CRC校验算法

和校验、异或校验

  • 这两种校验方式在短数据传输过程应该是最常见的,实现过程很简单,这里不做过多的介绍

多项式与POLY

  • CRC算法中必然会提到多项式,比如多项式“x8+x2+x+1”,即第8、2、1、0,bit为1。而POLY(生成项)计算中,最高位不参与,所以此多项式的POLY为0x07。
  • 又如CRC-16-MODBUS,它的多项式为x16 + x15 + x2 + 1,所以此多项式的POLY为0x8005

CRC

  • 实现CRC8,即实现了CRC4、CRC5、CRC6、CRC7以及CRC8-ITU、CRC8-ROHC等,不同的是它们的初值、多项式以及数据是否反转之间的配置不一样罢了,或者最终计算的结果异或某个值而已
  • 同理实现CRC16,CRC32,即可实现大部分CRC算法的需求

算法

数据反转

/**
* @brief  数据反转(高低位调换的意思,将数据最高位调到最低位,次高位调到次低位)
* @note
* @param  data:数据
*		  bitLen:数据位数
* @retval Reverse Result
*
*/
unsigned int Reverse(unsigned int data, unsigned char bitLen)
{
	unsigned int i;
	unsigned int buf=0;
	for (i = 0; i<bitLen; i++) {
		buf <<= 1;
		if (data & 0x01) {
			buf |= 1;
		}
		data >>= 1;
	}

	return buf;
}

CRC8算法

/**
* @brief  CRC8 Calculate
* @note   
* @param  crcInit:		CRC初始值
*		  poly:			CRC多项式
*		  BlockStart:	数据段
*		  BlockLength:	数据长度(需要计算的长度)
*		  inRev:		输入数据是否反转 0:不反转 1:反转
*		  outRev:		输出数据是否反转 0:不反转 1:反转
* @retval CRC8 Calculate Result
*         
*/
unsigned char CRC8(unsigned char crcInit, unsigned char poly, unsigned char *BlockStart, unsigned char BlockLength, unsigned char inRev, unsigned char outRev)
{
	unsigned int i, j;
	unsigned char CRC_VAL = crcInit;
	unsigned char buf;

	for (j = 0; j<BlockLength; j++) {
		buf = *(BlockStart + j);

		if (inRev != 0) {
			buf = Reverse(buf,8);
		}

		CRC_VAL ^= buf;
		for (i = 0; i<8; i++) {
			if (CRC_VAL & 0x80) {
				CRC_VAL = (CRC_VAL << 1) ^ poly;
			}
			else {
				CRC_VAL <<= 1;
			}
		}
	}


	if (outRev != 0) {
		CRC_VAL = Reverse(CRC_VAL,8);
	}

	return 	CRC_VAL & 0xFF;

}

CRC16算法

/**
* @brief  CRC16 Calculate
* @note
* @param  crcInit:		CRC初始值
*		  poly:			CRC多项式
*		  BlockStart:	数据段
*		  BlockLength:	数据长度(需要计算的长度)
*		  inRev:		输入数据是否反转 0:不反转 1:反转
*		  outRev:		输出数据是否反转 0:不反转 1:反转
* @retval CRC16 Calculate Result
*
*/
unsigned short CRC16(unsigned short crcInit, unsigned short poly, unsigned char *BlockStart, unsigned char BlockLength, unsigned char inRev, unsigned char outRev)
{
	unsigned int i, j;
	unsigned short CRC_VAL = crcInit;
	unsigned char buf;

	for (j = 0; j<BlockLength; j++) {
		buf = *(BlockStart + j);

		if (inRev != 0) {
			buf = Reverse(buf,8);
		}

		CRC_VAL ^= ((unsigned short)buf << 8);
		for (i = 0; i<8; i++) {
			if (CRC_VAL & 0x8000) {
				CRC_VAL = (CRC_VAL << 1) ^ poly;
			}
			else {
				CRC_VAL <<= 1;
			}
		}
	}

	if (outRev != 0) {
		CRC_VAL = Reverse(CRC_VAL,16);
	}

	return 	CRC_VAL & 0xFFFF;

}

CRC32算法


/**
* @brief  CRC32 Calculate
* @note
* @param  crcInit:		CRC初始值
*		  poly:			CRC多项式
*		  BlockStart:	数据段
*		  BlockLength:	数据长度(需要计算的长度)
*		  inRev:		输入数据是否反转 0:不反转 1:反转
*		  outRev:		输出数据是否反转 0:不反转 1:反转
* @retval CRC32 Calculate Result
*
*/
unsigned int CRC32(unsigned int crcInit, unsigned int poly, unsigned char *BlockStart, unsigned char BlockLength, unsigned char inRev, unsigned char outRev)
{
	unsigned int i, j;
	unsigned int CRC_VAL = crcInit;
	unsigned char buf;

	for (j = 0; j<BlockLength; j++) {
		buf = *(BlockStart + j);

		if (inRev != 0) {
			buf = Reverse(buf, 8);
		}

		CRC_VAL ^= ((unsigned int)buf << 24);
		for (i = 0; i<8; i++) {
			if (CRC_VAL & 0x80000000) {
				CRC_VAL = (CRC_VAL << 1) ^ poly;
			}
			else {
				CRC_VAL <<= 1;
			}
		}
	}

	if (outRev != 0) {
		CRC_VAL = Reverse(CRC_VAL, 32);
	}

	return 	CRC_VAL & 0xFFFFFFFF;

}

测试代码与输出

int main(void)
{
	unsigned char test[] = { 0x01,0x03,0x00,0x00,0x00,0x01 };
	unsigned char crc8_result=0;
	unsigned short crc16_result=0;
	unsigned int  crc32_result = 0;

	//CRC8
	crc8_result = CRC8(0x00, 0x07, test, sizeof(test), 0, 0);
	//CRC16 MODBUS
	crc16_result = CRC16(0xFFFF, 0x8005, test, sizeof(test), 1, 1);
	//CRC-32/MPEG-2
	crc32_result = CRC32(0xFFFFFFFF,0x04C11DB7, test, sizeof(test), 0, 0);

	printf("CRC8 result  = 0x%02X\r\n", crc8_result);
	printf("CRC16 result = 0x%04X\r\n", crc16_result);
	printf("CRC32 result = 0x%08X\r\n", crc32_result);

	while (1);

	return 0;
}

输出
CRC8 result = 0x88
CRC16 result = 0x0A84
CRC32 result = 0xFE84042A

常见CRC参数模型

CRC算法名称多项式公式宽度多项式初始值结果异或值输入反转输出反转
CRC-4/ITUx4 + x + 14030000truetrue
CRC-5/EPCx5 + x3 + 15090900falsefalse
CRC-5/ITUx5 + x4 + x2 + 15150000truetrue
CRC-5/USBx5 + x2 + 15051F1Ftruetrue
CRC-6/ITUx6 + x + 16030000truetrue
CRC-7/MMCx7 + x3 + 17090000falsefalse
CRC-8x8 + x2 + x + 18070000falsefalse
CRC-8/ITUx8 + x2 + x + 18070055falsefalse
CRC-8/ROHCx8 + x2 + x + 1807FF00truetrue
CRC-8/MAXIMx8 + x5 + x4 + 18310000truetrue
CRC-16/IBMx16 + x15 + x2 + 116800500000000truetrue
CRC-16/MAXIMx16 + x15 + x2 + 11680050000FFFFtruetrue
CRC-16/USBx16 + x15 + x2 + 1168005FFFFFFFFtruetrue
CRC-16/MODBUSx16 + x15 + x2 + 1168005FFFF0000truetrue
CRC-16/CCITTx16 + x12 + x5 + 116102100000000truetrue
CRC-16/CCITT-FALSEx16 + x12 + x5 + 1161021FFFF0000falsefalse
CRC-16/X25x16 + x12 + x5 + 1 161021FFFFFFFFtruetrue
CRC-16/XMODEMx16 + x12 + x5 + 116102100000000falsefalse
CRC-16/DNPx16 + x13 + x12 + x11 + x10 + x8 + x6 + x5 + x2 + 1163D650000FFFFtruetrue
CRC-32x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 13204C11DB7FFFFFFFFFFFFFFFFtruetrue
CRC-32/MPEG-2x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 13204C11DB7FFFFFFFF00000000falsefalse

版权声明:本文为WaliTool原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。