C语言标准CRC-8校验函数

C语言标准CRC-8校验函数

CRC校验原理及简单CRC-8校验函数(7个输入字节以内)可参考: CRC校验原理及CRC-8简单校验函数设计

这里的函数是实现输入范围扩展,支持任意长度的输入字节的CRC-8校验。

设计原理

设计原理仍然基于无符号64位整型为一个计算单元,当超过64位时,将前一个单元的计算余数,与后面的输入数据重新组成64位数据,再进行模二除法,以此类推,得到最后的CRC-8校验值(余数)。设计按照CRC计算基本原理来实现,更容易理解。

CRC-8校验函数

这里的校验码采用标准校验码X^8 + X^2 + X^1 + 1,对于其它类型的CRC-8校验码或有输入数据前处理或输出数据后处理的情况,相应的做代码简单调整即可。CRC-8校验函数如下:

#include <stdio.h>
#include <stdlib.h>
uint8_t PY_CRC_8(uint8_t *di, uint32_t len)
{   //Written by Pegasus Yu 2022/04/22
	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.
	uint8_t *datain;
	uint64_t cdata = 0; //Computed total data
	uint16_t data_t = 0; //Process data of CRC computing

	uint16_t index_t = 63;  ///bit shifting index for initial '1' searching
	uint16_t index = 63;    //bit shifting index for CRC computing
	uint8_t rec = 0; //bit number needed to be compensated for next CRC computing

	uint32_t cn=(len+1)/7;
	uint32_t cr=(len+1)%7;

	uint32_t j;

	datain = malloc(len+1);
	for(j=0;j<len;j++)
	{
		datain[j]=di[j];
	}
	    datain[len]=0; //Compensate 8-bit '0' for input data

     if(len<=7)
     {
    	 for(j=0;j<=len;j++)
    	 {
    		 cdata = (cdata<<8);
    		 cdata = cdata|datain[j];
    	 }
    	 cn = 1;
     }
     else
     {
    	 if(cr==0)
    	 {
    		 cr=7;
    	 }
        if(cr==1)
    	 {
    		 cr=8;
    	 }
    	 else
    	 {
    		 cn++;
    	 }

    	 for(j=0;j<cr;j++)
    	 {
    		 cdata = (cdata<<8);
    		 cdata = cdata|datain[j];
    	 }
     }

     do
     {
 		cn--;

 		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; */

	 	    		for(uint8_t n=1;n<9;n++)
	 	    		{
	 	    			if ((data_t>>(8-n))&1) {rec = n;break;}
	 	    			if (n==8) 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;
 			}
         }

 		if(cn>0)
 		{
  			cdata = data_t&0x00ff;

 			for(uint8_t k=0;k<7;k++)
 			{
 	    		 cdata = (cdata<<8);
 	    		 cdata = cdata|datain[j++];

 			}

 	    	data_t = 0;
 	 		index_t = 63;  ///bit shifting index for initial '1' searching
 	 		index = 63;    //bit shifting index for CRC computing
 	 		rec = 0; //bit number needed to be compensated for next CRC computing
 		}

     }
     while(cn>0);

     free(datain);
     return (uint8_t)data_t;
}

CRC-8校验效果

通过在线CRC-8校验工具对比本函数的效果,结果一致:
在这里插入图片描述
在这里插入图片描述

CRC-8校验函数8位计算方式优化

在理解了和CRC8校验原理完全一致的代码实现后,不采用64位计算方式,则可以简化代码为8位计算方式,可得到相同的校验值结果:

#include <stdio.h>
#include <stdlib.h>
uint8_t PY_CRC_8_S(uint8_t *di, uint32_t len)
{
	uint8_t crc_poly = 0x07; //X^8+X^2+X^1+1 total 8 effective bits without X^8. Computed total data shall be compensated 8-bit '0' before CRC computing.

	uint32_t clen = len+1;
	uint8_t cdata[clen] ;
	memcpy(cdata, di, len); cdata[len]=0;
	uint8_t data_t = cdata[0]; //CRC register

    for (uint32_t i = 1; i < clen; i++)
    {
        for (uint8_t j = 0; j <= 7; j++)
        {
            if(data_t&0x80)
            	data_t = ( (data_t<<1) | ( (cdata[i]>>(7-j))&0x01) ) ^ crc_poly;
            else
            	data_t = ( (data_t<<1) | ( (cdata[i]>>(7-j))&0x01) ) ;
        }
    }
    return data_t;
}

CRC-8校验函数查表原理优化

CRC查表原理通过输入数据分段计算(CRC-8按字节分段)原理实现校验码的计算,查表法有如下特点:

  1. 当前输入数据段值异或当前的查表值,得到当前的CRC计算余数
  2. 当前查表值由前一计算余数与校验码按CRC校验过程计算得到,并保存为对应前一计算余数对应的表位值
  3. 当前查表值的计算不受当前输入字段值影响,所以当前输入字段值为0且为最后字段时,当前查表值异或当前输入字段值不变,此时当前查表值即为CRC校验值结果。
  4. 由第2和3条可知,第2条在CRC校验过程计算时,移位补位时补0即可,也就不需要当前字段值进入移位补位过程。

CRC-8校验函数优化为如下代码,仍然是8位计算方式,特点是不需要对输入数据补8位尾0:

uint8_t PY_CRC_8_T(uint8_t *di, uint32_t len)
{
	uint8_t crc_poly = 0x07; //X^8+X^2+X^1+1 total 8 effective bits without X^8.
	uint8_t data_t = 0;

    while(len--)
    {
    	data_t ^=  *di++;
        for (int8_t i=8; i>0; --i)
        {
            if (data_t & 0x80)
            	data_t = (data_t<<1) ^ crc_poly;
            else
            	data_t = (data_t<<1);
        }
    }
    return (data_t);
}

采用如上三种方式任何一种,对单字节0~255的输入数分别进行CRC-8校验,得到的各个校验值,也就得到查表法对应每个输入数值的查表值。

CRC-8校验注意事项

实际应用中,由于输入数据前处理和输出数据后处理的不同,产生了不同的CRC应用标准,其中一些是一些知名厂家为自己的产品定义CRC校验函数。这些处理特性包括CRC寄存器初始值设置,数据字节位反转,数据字节高位还是低位优先进入计算,输出的整个数据是否按位反转,输出数据是否和一个数异或等。常见的一些CRC-8校验特性:

在这里插入图片描述

–End–

  • 7
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

PegasusYu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值