E002-CRC查表法-表的由来与实现1

一、背景

        CRC计算中常用空间换时间的方案即查表法,从前面的文章关于CRC的介绍中不难知道,crc的表其实就是对于整个字节256个数据的不同结果记录的集合。

1. 本文主要针对CRC16查表法表的计算,因为crc16有多种协议,因此代码做了针对不同协议的合集,先列出各个协议之间的区别

CRC算法名称多项式宽度初始值结果异或输入反转输出反转
CRC16_CCITT10211600000000truetrue
CRC16_X251021  16fffffffftruetrue
CRC16_MAXIM8005160000fffftruetrue
CRC16_USB800516fffffffftruetrue
CRC16_MODBUS800516ffff0000truetrue
CRC16_IBM80051600000000truetrue
CRC16_DNP3d65160000fffftruetrue

2.模二除法的原理

        crc校验码生成的原理是数据对多项式进行模二除法求余,因此查表法表格的数据就是对一个字节的所有数据进行模二除法后的生成的校验码。其基本原理如下:

data :0x01
poly :0x1021
seed :0x0

    1000 0000 | 0000 0000 0000 0000     //(swap(0x01) << 16u)
    1000 1000   0001 0000 1             //0x11021
         ------------------
         1000   0001 0000 1000 0
         1000   1000 0001 0000 1
         -----------------------
                1001 0001 1000 1000     //(0x9188)  swap后得 0x1189
        (swap)  0001 0001 1000 1001     //(0x1189)

swap的操作是针对这个协议CCITT要对输入的数据进行反转,具体反转的操作就是最高位和最低位的数据互换,次高位和次低位数据进行互换,具体操作可参考我的文章:(96条消息) C语言数据高低位转换(8-16-32位)_溪山行旅1024的博客-CSDN博客 

使用代码的效果如下:检测高位遇到1相除并更新除数,遇到0则进行移位操作

for(i=0;i<256;i++){		
    for(int j=0;j<8;j++){
		if(p&0x8000){	
			p=p<<1;
			p = (p^poly);
		}else{
			p=p<<1;
		}
	}
}

        当然此段代码只是数据已经进行过seed赋初值,输入反转之后的模二除法操作,具体的操作还需要加上对多项式poly和初始值seed的配置及最后对结果进行异或操作

                将CRC16的协议类型作为参数分别获得seed和poly:

static u32 poly_seed_config(u8 poly_type)
{
	u32 poly_cfg = 0;
	switch(poly_type){
		case  CRC16_CCITT:
				poly_cfg = 0x10210000;
				break;
		case  	CRC16_X25 :
				poly_cfg = 0x1021ffff;
				break;
		case 	CRC16_MAXIM:
				poly_cfg = 0x80050000;
				break;
		case   CRC16_USB :
				poly_cfg = 0x8005ffff;
				break;
		case   CRC16_MODBUS:
				poly_cfg = 0x8005ffff;
				break;
		case   CRC16_IBM :
				poly_cfg = 0x80050000;
				break;
		case   CRC16_DNP :
				poly_cfg = 0x3d650000;
				break;
		default:
				break;
	}
	return poly_cfg ;
}

void main()
{
    u16 poly = poly_seed_config(CRC16_IBM) >> 16u;
    u16 seed = (u16)poly_seed_config(CRC16_IBM) & 0xffff;
}

此外,将CRC16的协议类型作为参数获得异或操作数:

static u16 result_config(u8 poly_type)
{
	u16 result = 0;
	switch(poly_type){
		case  CRC16_CCITT:
				result = 0x0000;
				break;
		case  	CRC16_X25 :
				result = 0xffff;
				break;
		case 	CRC16_MAXIM:
				result = 0xffff;
				break;
		case   CRC16_USB:
				result = 0xffff;
				break;
		case   CRC16_MODBUS:
				result = 0x0000;
				break;
		case   CRC16_IBM :
				result = 0x0000;
				break;
		case   CRC16_DNP :
				result = 0xffff;
				break;
		default:
				break;
	}
	return result ;
}
void main(){
    u16 poly = poly_seed_config(CRC16_IBM) >> 16u;
	u16 seed = (u16)poly_seed_config(CRC16_IBM) & 0xffff;
    u16 xor_result = result_config(CRC16_IBM);
}

        综上分析,我们只需要知道协议的类型就可以计算出0~ff数据的crc值,将他们放进一个char类型的表中,即为我们所需的CRC表 ,完整实现代码(以CRC16_IBM为例)如下:

void main()
{
	u16 poly = poly_seed_config(CRC16_IBM) >> 16u;
	u16 seed = (u16)poly_seed_config(CRC16_IBM) & 0xffff;

	u16 xor_result = result_config(CRC16_IBM);
	u16 table[256];
	u16 i=0;
	u16 p=0;

	for(i=0;i<256;i++)
	{	
		p=i^seed;
		p=(u16)(crc_swap_u32((u32)p)>>16);
		
		for(int j=0;j<8;j++)
		{
			if(p&0x8000)
			{	
				p=p<<1;
				p = (p^poly);
			}else
			{
				p=p<<1;
			}
		}
		table[i]=crc_swap_u32((u32)p)>>16 ^ xor_result;
		printf("0x%xu, ", table[i]);
		if((i+1)%8 == 0)
		printf("\n");

	}

}

最终计算的结果如下:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值