CRC-8/MAXIM算法实现

  1. 什么是CRC算法?
    CRC(Cyclic Redundancy Check),称循环冗余校验,是根据数据产生简短固定位数校验码的一种信道编码技术,主要用于发送端和接收端检测或校验数据传输前后是否出现错误,它是利用除法及余数的原理来作数据错误侦测的。

  2. CRC数据格式
    一个完整的数据帧通常由以下部分构成:帧头+数据+校验数据+帧尾
    在实际应用中,我们通常只关心 数据+校验数据,即校验数据一般是附加在数据后一起传输,所以数据传输流程如下:
    发送端以CRC算法计算出校验数据crcData
    发送端将crcData合并到数据data中得到一帧数据data+crcData,发送给接收端
    接收端收到data+crcData数据帧后以CRC算法验证crcData的正确性,以检测数据是否出错

  3. CRC算法参数模型解释
    在这里插入图片描述
    在这里插入图片描述

  4. 示例(CRC-8/MAXIM算法):
    设原始数据为0xD6

(1)原始数据为0xD6,转成二进制为1101 0110,多项式由上图知为x^8+x^5+x^4+1=0x131(可以理解为x=2),上图中的多项式是0x31,去掉了最高位,
   至于为啥去掉目前没搞明白,多项式为啥要多1个bit、多项式能不能自己随意定,这些专业知识还得找文献再看看,不过能算出来校验和就OK。
(2)输入反转为true,这里是指高低位顺序反转,例如1000 1000反转后为0001 0001,所以我们要把异或
   后的数据0xD61101 0110进行反转得到0110 10110x6B(3)用反转后数据高8位和上图中初始值进行异或运算:0x6B^0x00=0x6B,还是原始数据;初始值可以随意设置,至于为啥是和高8位而不是低8位,也不明白。
(4)规定要在原始数据后补(多项式位数-1)个0,因为多项式为0x1319个位,所以我们要在0x63后补9-1=80,结果为0x6B00,为啥这么规定,也不明白。
(5)把反转后的数据与多项式进行模2除法,其实就是异或运算,我们需要的是运算结果的余数,所以我们要把0x6B00与多项式0x131不断异或,直到余数
   位小于等于多项式位数;如果余数位等于多项式位数,那么把它俩异或后的结果就是最终运算结果;如果余数位小于多项式位数,那么余数直接就是
   最终运算结果。0x6B00(hex)=0110 1011 0000 0000(bin),去掉高位没用的0结果为**110 1011 0000 0000**0x131(hex)=0000 0001 0011 0001(bin),
   去掉高位没用的0结果为**1 0011 0001**,下面进行运算:
   
 110 1011 0000 0000
^100 1100 01
-------------------
  10 0111 0100 0000
 ^10 0110 001
 ------------------
        1 0110 0000
       ^1 0011 0001
    ---------------
           101 0001(最终结果0x51)
           
(6)上图中的“输出结果异或”为true,所以我们需要将结果0x51(0101 0001)反转,结果为1000 1010(0x8A)(7)上图中的“结果异或值为0x00”,所以我们需要将最终结果与0x00异或,结果还是0x8A(8)将校验数据0x8A添加到数据后面,最终的数据帧为0xD68A,其中D6是原始数据,8A是校验数据。
(9)数据帧发送后,接收端根据同样的算法再算一次,如果校验数据是0x8A,那么数据正确,否则,数据出错。

我们使用工具再次验证校验和没有错误:
在这里插入图片描述
下面用C语言实现该算法:

#include <iostream>

using namespace std;

unsigned char width = 8;				//宽度
unsigned short int poly = 0x0131;	//多项式
unsigned char init = 0x00;				//初始值
unsigned char xorout = 0x00;			//结果异或
bool refin = true;								//输入反转
bool refout = true;							//输出反转

/*计算数据data的数据位数*/
unsigned int bitnum(unsigned long long int data)
{
	unsigned long long int _data = data;
	unsigned int retValue = 0;

	while (_data)
	{
		_data >>= 1;
		retValue++;
	}

	return retValue;
}

/*将数据反转*/
unsigned char reversal(unsigned long long int data)
{
	unsigned char _data = (unsigned char)(data);
	unsigned char retValue = 1;

	for (int i = 0; i < 8; i++)
	{
		unsigned char temp = _data & 0x01;

		if (temp)
			retValue |= 0x01;
		else
			retValue &= ~0x01;

		if (i == 7)
			break;
		retValue <<= 1;
		_data >>= 1;
	}

	return retValue;
}

unsigned int crc(unsigned char data)
{
	unsigned long long int _data = (unsigned long long int)(data);
	unsigned long long int _poly = (unsigned long long int)(poly);
	unsigned long long int temp = 0x00;

	_data ^= init;								//将原始数据和数据异或
	if(refin)
		_data = (unsigned long long int)(reversal(_data));	//将数据反转
	_data <<= width;							//数据左移

	do
	{
		_poly = poly << (bitnum(_data) - bitnum(poly));
		_data = _data ^ _poly;
	} while (bitnum(_data) > 8);

	_data ^= xorout;

	if(refout)
		_data = reversal(_data);

	return (unsigned int)(_data);
}

int main(int argc, char** argv)
{
	unsigned int data = 0;					//原始数据

	while (true)
	{
		cout << "输入数据(Hex):";
		cin >> hex >> data;
		unsigned int ret = crc(data);
		cout << "校验数据(Hex):" << hex << uppercase << ret << endl << endl;
	}

	/*输出从0~255的校验数据*/
	//for (int i = 0; i <= 0xFF; i++)
	//{
	//	cout << hex << uppercase << i << ":" << crc(i) << endl;
	//}

	return 0;
}

计算结果展示:
在这里插入图片描述

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值