CRC校验码

47 篇文章 0 订阅

1. 什么是CRC?

CRC(Cyclic Redundancy Checksum)是一种纠错技术,代表循环冗余校验和。
数据通信领域中最常用的一种差错校验码,其信息字段和校验字段长度可以任意指定,但要求通信双方定义的CRC标准一致。主要用来检测或校验数据传输或者保存后可能出现的错误。它的使用方式可以说明如下图所示:
在数据传输过程中,无论传输系统的设计再怎么完美,差错总会存在,这种差错可能会导致在链路上传输的一个或者多个帧被破坏(出现比特差错,0变为1,或者1变为0),从而接受方接收到错误的数据。
为尽量提高接受方收到数据的正确率,在接收方接收数据之前需要对数据进行差错检测,当且仅当检测的结果为正确时接收方才真正收下数据。检测的方式有多种,常见的有奇偶校验、因特网校验和循环冗余校验等。

常见的CRC算法

虽然CRC可以任意定义二项式、数据长度等,但没有一个统一的标准的话,就会让整个计算变得非常的麻烦。但实际上,不同的厂家经常采用不同的标准算法,
在这里插入图片描述

代码实现

crc.c
#include "crc.h"
#include <stdio.h>

typedef enum {
	REF_4BIT = 4,
	REF_5BIT = 5,
	REF_6BIT = 6,
	REF_7BIT = 7,
	REF_8BIT = 8,
	REF_16BIT = 16,
	REF_32BIT = 32
}REFLECTED_MODE;

uint32_t ReflectedData(uint32_t data, REFLECTED_MODE mode)
{
	data = ((data & 0xffff0000) >> 16) | ((data & 0x0000ffff) << 16);
	data = ((data & 0xff00ff00) >> 8) | ((data & 0x00ff00ff) << 8);
	data = ((data & 0xf0f0f0f0) >> 4) | ((data & 0x0f0f0f0f) << 4);
	data = ((data & 0xcccccccc) >> 2) | ((data & 0x33333333) << 2);
	data = ((data & 0xaaaaaaaa) >> 1) | ((data & 0x55555555) << 1);

	switch (mode)
	{
	case REF_32BIT:
		return data;
	case REF_16BIT:
		return (data >> 16) & 0xffff;
	case REF_8BIT:
		return (data >> 24) & 0xff;
	case REF_7BIT:
		return (data >> 25) & 0x7f;
	case REF_6BIT:
		return (data >> 26) & 0x7f;
	case REF_5BIT:
		return (data >> 27) & 0x1f;
	case REF_4BIT:
		return (data >> 28) & 0x0f;
	}
	return 0;
}

uint8_t CheckCrc4(uint8_t poly, uint8_t init, bool refIn, bool refOut, uint8_t xorOut,
	const uint8_t *buffer, uint32_t length)
{
	uint8_t i;
	uint8_t crc;

	if (refIn == true)
	{
		crc = init;
		poly = ReflectedData(poly, REF_4BIT);

		while (length--)
		{
			crc ^= *buffer++;
			for (i = 0; i < 8; i++)
			{
				if (crc & 0x01)
				{
					crc >>= 1;
					crc ^= poly;
				}
				else
				{
					crc >>= 1;
				}
			}
		}

		return crc ^ xorOut;
	}
	else
	{
		crc = init << 4;
		poly <<= 4;

		while (length--)
		{
			crc ^= *buffer++;
			for (i = 0; i < 8; i++)
			{
				if (crc & 0x80)
				{
					crc <<= 1;
					crc ^= poly;
				}
				else
				{
					crc <<= 1;
				}
			}
		}

		return (crc >> 4) ^ xorOut;
	}
}

uint8_t CheckCrc5(uint8_t poly, uint8_t init, bool refIn, bool refOut, uint8_t xorOut,
	const uint8_t *buffer, uint32_t length)
{
	uint8_t i;
	uint8_t crc;

	if (refIn == true)
	{
		crc = init;
		poly = ReflectedData(poly, REF_5BIT);

		while (length--)
		{
			crc ^= *buffer++;
			for (i = 0; i < 8; i++)
			{
				if (crc & 0x01)
				{
					crc >>= 1;
					crc ^= poly;
				}
				else
				{
					crc >>= 1;
				}
			}
		}

		return crc ^ xorOut;
	}
	else
	{
		crc = init << 3;
		poly <<= 3;

		while (length--)
		{
			crc ^= *buffer++;
			for (i = 0; i < 8; i++)
			{
				if (crc & 0x80)
				{
					crc <<= 1;
					crc ^= poly;
				}
				else
				{
					crc <<= 1;
				}
			}
		}

		return (crc >> 3) ^ xorOut;
	}
}

uint8_t CheckCrc6(uint8_t poly, uint8_t init, bool refIn, bool refOut, uint8_t xorOut,
	const uint8_t *buffer, uint32_t length)
{
	uint8_t i;
	uint8_t crc;

	if (refIn == true)
	{
		crc = init;
		poly = ReflectedData(poly, REF_6BIT);

		while (length--)
		{
			crc ^= *buffer++;
			for (i = 0; i < 8; i++)
			{
				if (crc & 0x01)
				{
					crc >>= 1;
					crc ^= poly;
				}
				else
				{
					crc >>= 1;
				}
			}
		}

		return crc ^ xorOut;
	}
	else
	{
		crc = init << 2;
		poly <<= 2;

		while (length--)
		{
			crc ^= *buffer++;
			for (i = 0; i < 8; i++)
			{
				if (crc & 0x80)
				{
					crc <<= 1;
					crc ^= poly;
				}
				else
				{
					crc <<= 1;
				}
			}
		}

		return (crc >> 2) ^ xorOut;
	}
}

uint8_t CheckCrc7(uint8_t poly, uint8_t init, bool refIn, bool refOut, uint8_t xorOut,
	const uint8_t *buffer, uint32_t length)
{
	uint8_t i;
	uint8_t crc;

	if (refIn == true)
	{
		crc = init;
		poly = ReflectedData(poly, REF_7BIT);

		while (length--)
		{
			crc ^= *buffer++;
			for (i = 0; i < 8; i++)
			{
				if (crc & 0x01)
				{
					crc >>= 1;
					crc ^= poly;
				}
				else
				{
					crc >>= 1;
				}
			}
		}

		return crc ^ xorOut;
	}
	else
	{
		crc = init << 1;
		poly <<= 1;

		while (length--)
		{
			crc ^= *buffer++;
			for (i = 0; i < 8; i++)
			{
				if (crc & 0x80)
				{
					crc <<= 1;
					crc ^= poly;
				}
				else
				{
					crc <<= 1;
				}
			}
		}

		return (crc >> 1) ^ xorOut;
	}
}

uint8_t CheckCrc8(uint8_t poly, uint8_t init, bool refIn, bool refOut, uint8_t xorOut,
	const uint8_t *buffer, uint32_t length)
{
	uint32_t i = 0;
	uint8_t crc = init;

	while (length--)
	{
		if (refIn == true)
		{
			crc ^= ReflectedData(*buffer++, REF_8BIT);
		}
		else
		{
			crc ^= *buffer++;
		}

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

	if (refOut == true)
	{
		crc = ReflectedData(crc, REF_8BIT);
	}

	return crc ^ xorOut;
}

uint16_t CheckCrc16(uint16_t poly, uint16_t init, bool refIn, bool refOut, uint16_t xorOut,
	const uint8_t *buffer, uint32_t length)
{
	uint32_t i = 0;
	uint16_t crc = init;

	while (length--)
	{
		if (refIn == true)
		{
			crc ^= ReflectedData(*buffer++, REF_8BIT) << 8;
		}
		else
		{
			crc ^= (*buffer++) << 8;
		}

		for (i = 0; i < 8; i++)
		{
			if (crc & 0x8000)
			{
				crc <<= 1;
				crc ^= poly;
			}
			else
			{
				crc <<= 1;
			}
		}
	}

	if (refOut == true)
	{
		crc = ReflectedData(crc, REF_16BIT);
	}

	return crc ^ xorOut;
}

uint32_t CheckCrc32(uint32_t poly, uint32_t init, bool refIn, bool refOut, uint32_t xorOut,
	const uint8_t *buffer, uint32_t length)
{
	uint32_t i = 0;
	uint32_t crc = init;

	while (length--)
	{
		if (refIn == true)
		{
			crc ^= ReflectedData(*buffer++, REF_8BIT) << 24;
		}
		else
		{
			crc ^= (*buffer++) << 24;
		}

		for (i = 0; i < 8; i++)
		{
			if (crc & 0x80000000)
			{
				crc <<= 1;
				crc ^= poly;
			}
			else
			{
				crc <<= 1;
			}
		}
	}

	if (refOut == true)
	{
		crc = ReflectedData(crc, REF_32BIT);
	}

	return crc ^ xorOut;
}

uint32_t CrcCheck(CRC_Type crcType, const uint8_t *buffer, uint32_t length)
{
	switch (crcType.width)
	{
	case 4:
		return CheckCrc4(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
			crcType.xorOut, buffer, length);
	case 5:
		return CheckCrc5(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
			crcType.xorOut, buffer, length);
	case 6:
		return CheckCrc6(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
			crcType.xorOut, buffer, length);
	case 7:
		return CheckCrc7(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
			crcType.xorOut, buffer, length);
	case 8:
		return CheckCrc8(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
			crcType.xorOut, buffer, length);
	case 16:
		return CheckCrc16(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
			crcType.xorOut, buffer, length);
	case 32:
		return CheckCrc32(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
			crcType.xorOut, buffer, length);
	}
	return 0;
}

crc.h
#ifndef __CRC_H__
#define __CRC_H__

#include <stdint.h>
#include <stdbool.h>

typedef struct {
	uint8_t width;
	uint32_t poly;
	uint32_t init;
	bool refIn;
	bool refOut;
	uint32_t xorOut;
}CRC_Type;

uint32_t CrcCheck(CRC_Type crcType, const uint8_t *buffer, uint32_t length);

#endif


main.cpp
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "crc.h"

#define LENGTH	8
const uint8_t data[3][LENGTH] = {
	{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },
	{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 },
	{ 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }};

typedef struct {
	CRC_Type crcType;
	uint32_t result[3];
}CRC_Test;

CRC_Test crc4_ITU = { { 4, 0x03, 0x00, true, true, 0x00 }, { 0x0f, 0x0a, 0x0e } };
CRC_Test crc5_EPC = { { 5, 0x09, 0x09, false, false, 0x00 }, { 0x00, 0x0c, 0x17 } };
CRC_Test crc5_ITU = { { 5, 0x15, 0x00, true, true, 0x00 }, { 0x16, 0x0a, 0x17 } };
CRC_Test crc5_USB = { { 5, 0x05, 0x1f, true, true, 0x1f }, { 0x10, 0x09, 0x17 } };
CRC_Test crc6_ITU = { { 6, 0x03, 0x00, true, true, 0x00 }, { 0x1d, 0x30, 0x00 } };
CRC_Test crc7_MMC = { { 7, 0x09, 0x00, false, false, 0x00 }, { 0x57, 0x30, 0x5b } };
CRC_Test crc8 = { { 8, 0x07, 0x00, false, false, 0x00 }, { 0x3e, 0xe1, 0x36 } };
CRC_Test crc8_ITU = { { 8, 0x07, 0x00, false, false, 0x55 }, { 0x6b, 0xb4, 0x63 } };
CRC_Test crc8_ROHC = { { 8, 0x07, 0xff, true, true, 0x00 }, { 0x6b, 0x78, 0x93 } };
CRC_Test crc8_MAXIM = { { 8, 0x31, 0x00, true, true, 0x00 }, { 0x83, 0x60, 0xa9 } };
CRC_Test crc16_IBM = { { 16, 0x8005, 0x0000, true, true, 0x0000 }, { 0xc4f0, 0x2337, 0xa776 } };
CRC_Test crc16_MAXIM = { { 16, 0x8005, 0x0000, true, true, 0xffff }, { 0x3b0f, 0xdcc8, 0x5889 } };
CRC_Test crc16_USB = { { 16, 0x8005, 0xffff, true, true, 0xffff }, { 0x304f, 0xd788, 0x53c9 } };
CRC_Test crc16_MODBUS = { { 16, 0x8005, 0xffff, true, true, 0x0000 }, { 0xcfb0, 0x2877, 0xac36 } };
CRC_Test crc16_CCITT = { { 16, 0x1021, 0x0000, true, true, 0x0000 }, { 0xeea7, 0xfe7c, 0x7919 } };
CRC_Test crc16_CCITT_FALSE = { { 16, 0x1021, 0xffff, false, false, 0x0000 }, { 0x4792, 0x13a7, 0xb546 } };
CRC_Test crc16_X25 = { { 16, 0x1021, 0xffff, true, true, 0xffff }, { 0x6dd5, 0x7d0f, 0xfa6a } };
CRC_Test crc16_XMODEM = { { 16, 0x1021, 0x0000, false, false, 0x0000 }, { 0x76ac, 0x2299, 0x8478 } };
CRC_Test crc16_DNP = { { 16, 0x3D65, 0x0000, true, true, 0xffff }, { 0x7bda, 0x0535, 0x08c4 } };
CRC_Test crc32 = { { 32, 0x04c11db7, 0xffffffff, true, true, 0xffffffff }, { 0x3fca88c5, 0xe0631a53, 0xa4051a26 } };
CRC_Test crc32_MPEG2 = { { 32, 0x4c11db7, 0xffffffff, false, false, 0x00000000 }, { 0x14dbbdd8, 0x6509b4b6, 0xcb09d294 } };

void CrcTest(CRC_Test crcTest)
{
	uint32_t i;
	for (i = 0; i < 3; i++)
	{
		printf("%08x\t%08x\r\n", CrcCheck(crcTest.crcType, data[i], LENGTH), crcTest.result[i]);
	}
	printf("\r\n");
}

int main(void)
{
	CrcTest(crc4_ITU);
	CrcTest(crc5_EPC);
	CrcTest(crc5_ITU);
	CrcTest(crc5_USB);
	CrcTest(crc6_ITU);
	CrcTest(crc7_MMC);
	CrcTest(crc8);
	CrcTest(crc8_ITU);
	CrcTest(crc8_ROHC);
	CrcTest(crc8_MAXIM);
	CrcTest(crc16_IBM);
	CrcTest(crc16_MAXIM);
	CrcTest(crc16_USB);
	CrcTest(crc16_MODBUS);
	CrcTest(crc16_CCITT);
	CrcTest(crc16_CCITT_FALSE);
	CrcTest(crc16_X25);
	CrcTest(crc16_XMODEM);
	CrcTest(crc16_DNP);
	CrcTest(crc32);
	CrcTest(crc32_MPEG2);

	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、循环校验CRC):是数据通信领域中最常用的一种差错校验,其特征是信息字段和校验字段的长度可以任意选定。   2、生成CRC的基本原理:任意一个由二进制位串组成的代都可以和一个系数仅为‘0’和‘1’取值的多项式一一对应。例如:代1010111对应的多项式为x6+x4+x2+x+1,而多项式为x5+x3+x2+x+1对应的代101111。   3、CRC集选择的原则:若设字长度为N,信息字段为K位,校验字段为R位(N=K+R),则对于CRC集中的任一字,存在且仅存在一个R次多项式g(x),使得   V(x)=A(x)g(x)=xRm(x)+r(x);   其中: m(x)为K次信息多项式, r(x)为R-1次校验多项式,   g(x)称为生成多项式:   g(x)=g0+g1x+ g2x2+...+g(R-1)x(R-1)+gRxR   发送方通过指定的g(x)产生CRC字,接收方则通过该g(x)来验证收到的CRC字。   4、CRC校验软件生成方法:   借助于多项式除法,其余数为校验字段。   例如:信息字段代为: 1011001;对应m(x)=x6+x4+x3+1   假设生成多项式为:g(x)=x4+x3+1;则对应g(x)的代为: 11001   x4m(x)=x10+x8+x7+x4 对应的代记为:10110010000;   采用多项式除法: 得余数为: 1010 (即校验字段为:1010)   发送方:发出的传输字段为: 1 0 1 1 0 0 1 1 0 10   信息字段 校验字段   接收方:使用相同的生成进行校验:接收到的字段/生成(二进制除法)   如果能够除尽,则正确,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值