CRC校验原理及CRC-8简单校验函数设计

CRC校验原理及CRC-8简单校验函数设计

CRC为循环冗余校验码,是一种常用的、具有检错、纠错能力的校验码。通常发送方在发送的数据之后,附上其CRC校验码。接收方收到数据后,也做同样的CRC校验,得到本地CRC校验码,并和接收到的CRC校验码比较,如果一致,则认为数据无误,如果不一致,则认为发收过程中出错。

CRC校验码是被计算数据和计算码的二进制模二除法的余数。二进制模二除法和二进制常规算法的区别是,模二除法在除法运算过程中采用模二减法,不产生借位,也就是0-1=1,0-0=0,1-1=0,1-0=1;而00-01=01,10-01=11。也就是按位异或的效果。

CRC-8计算方式

以MLX90614测温芯片的CRC-8校验为例,其计算码多项式为X^8 + X^2 + X^1 + 1 ,也就是对应9个二进制位的数据,即100000111,第一位和最后一位都是1,也即0x107。在计算时,对于计算数据要计算到最后一位,因此实际计算时,计算数据要左移8位,再与0x107进行模二除法。

算法方面,要首先对计算数据进行从高位开始的第一个二进制“1”的位置搜索,因为模二除法从这里开始启动。
对于MLX90614读取的温度数据长度为5个字节,左移8位后就是6个字节,可以用64位无符号长整型装载。而9位的计算码可以用16位无符号短整型装载。
在算法计算过程中,要考虑前面一次计算后,余数已小于计算码时,需要给余数从计算数据中进行补位的各种情况,包括余数已为全0而计算还未完成的情况,所以每次补位的长度不一样。这里需要注意,补位是补到余数的后面,而不是和余数直接进行异或,而是补位后的余数再和计算码进行模二减法。
当计算到已无法通过补位继续进行计算的时候,则此余数就是最后的校验码。

CRC-8校验函数

MLX90614读操作的时序如下:
前面5个字节数据的校验码为PEC(第六个字节), 也即设计的校验函数PY_CRC_MLX90614_READ(0xb4, 0x07, 0xd2, 0x3a)计算结果为0x30。注意这里根据MLX90614输入数据特征在函数内部做了处理,输入变量是4个字节,实际对应是5个字节。
在这里插入图片描述
校验函数设计如下:

uint8_t PY_CRC_MLX90614_READ(uint8_t daddr, uint8_t Raddr, uint8_t dl, uint8_t dh)
{   //Written by Pegasus Yu 2022/02/22

	uint64_t cdata = 0; //Computed total data
	uint16_t data_t = 0; //Process data of CRC computing
	uint16_t crc_poly = 0x0107; //X^8+X^2+X^1+1 total 9 effective bits. Computed total data shall be compensated 8-bit '0' before CRC computing from 9-1=8.

	uint16_t index_t = 47;  ///bit shifting index for initial '1' searching
	uint16_t index = 47;    //bit shifting index for CRC computing

	uint8_t rec = 0; //bit number needed to be compensated for next CRC computing

	cdata |= (((uint64_t)daddr)<<40);       //device write address
	cdata |= (((uint64_t)Raddr)<<32);       //register access address
	cdata |= (((uint64_t)(daddr+1))<<24);   //device read address
	cdata |= (((uint64_t)dl)<<16);          //data LSB
	cdata |= (((uint64_t)dh)<<8);           //data HSB
	//8-bit '0' compensated into cdata so cdata involves 48 bits stored in 64-bit format.

	while(index_t>0)
	{
		if( (cdata>>index_t)&1 )
		{
			index = index_t;
			index_t = 0;

			data_t |= (cdata>>(index-8));
			{
				data_t = data_t ^ crc_poly;
			}

            while((index!=0x5555)&&(index!=0xaaaa))
            {
    			if ((data_t>>7)&1) rec = 1;
    			else if ((data_t>>6)&1) rec = 2;
    			else if ((data_t>>5)&1) rec = 3;
    			else if ((data_t>>4)&1) rec = 4;
    			else if ((data_t>>3)&1) rec = 5;
    			else if ((data_t>>2)&1) rec = 6;
    			else if ((data_t>>1)&1) rec = 7;
    			else if ((data_t>>0)&1) rec = 8;
    			else rec = 9; ///

    			if((index-8)<rec)
    			{
    				data_t = data_t<<(index-8);
 	    			data_t |=  (uint16_t)((cdata<<(64-(index-8)))>>(64-(index-8)));
 	    			index = 0x5555;
    			}
    			else
    			{
        			for(uint8_t i=1;i<=rec;i++)
        			{
        				data_t = (data_t<<1)|((cdata>>(index-8-i))&1) ;
        			}

        			if(rec!= 9)
        			{
        				data_t = data_t ^ crc_poly;
        				index -= rec;
        			}
        			else
        			{
        				data_t = 0;
        				index_t = index-8-1;
        				index = 0xaaaa;

        			}

    			}


            }
                if(index==0x5555) break;
		}
		else
		{
			index_t--;
			if(index_t<8) break;
		}
	}
	return (uint8_t)data_t;
}

CRC-8长数据校验

如上面的算法原理解释,这里的简单校验函数只支持到7个字节的输入数据校验,如果计算数据太长,则需要进行升级设计,设计上可以按照64位进行分段,当高一段64位计算到尽头时,在下一段64位开始对余数进行位补,以使得模二减法能继续进行下去。直到最后一个64位段计算到尽头,则余数是CRC-8的8位校验码。

而当进行的是CRC-16或CRC-32校验码计算时,依然可升级上述算法进行实现,因为无符号64位宽度能够覆盖16位和32位的模二除法(减法)计算要求。这是本算法相对于其它用8位单字节宽度来分段计算数据的算法的特点。

–End–

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

PegasusYu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值