CRC校验

CRC16的算法原理:
1、根据CRC16的标准选择初值CRCLn的值。
2、将数据的第一个字节与CRCLn的高8位异或。
3、判断最高位,若该位为0,左移1位,若为1左移一位再与多项式Hex码异或。
4、重复3直至8个位全部移位计算结束。
5、重复将所有输入数据操作完成以上步骤,所得的16位数即为16位CRC校验码。
常见的几组CRC公式:
1、CRC16/IBM 或 CRC16/ARC 或 CRC16/LHA:
公式:x16+x15+x2+1
宽度:16
Poly值:0x8005
初始值:0x0000
基准输入:true
基准输出:true
标志位:0x0000

2、CRC16/MAXIM:
公式:x16+x15+x2+1
宽度:16
Poly值:0x8005
初始值:0x0000
基准输入:true
基准输出:true
标志位:0xFFFF

3、CRC16/USB:
公式:x16+x15+x2+1
宽度:16
Poly值:0x8005
初始值:0xFFFF
基准输入:true
基准输出:true
标志位:0xFFFF

4、CRC16/MODBUS(最常见):
公式:x16+x15+x2+1
宽度:16
Poly值:0x8005
初始值:0x0000
基准输入:true
基准输出:true
标志位:0x0000

5、CRC16/CCITT 或 CRC-CCITT 或CRC16/CCITT-TRUE或 CRC16/KERMIT:
公式:x16+x15+x5+1
宽度:16
Poly值:0x1021
初始值:0x0000
基准输入:true
基准输出:true
标志位:0x0000

6、 CRC16/CCITT-FALSE:
公式:x16+x15+x5+1
宽度:16
Poly值:0x1021
初始值:0xFFFF
基准输入:false
基准输出:false
标志位:0x0000

7、CRC16/X25:
公式:x16+x15+x5+1
宽度:16
Poly值:0x1021
初始值:0x0000
基准输入:true
基准输出:true
标志位:0xFFFF

8、CRC16/XMODEM 或 CRC16/ZMODEM 或 CRC16/ACORN:
公式:x16+x15+x5+1
宽度:16
Poly值:0x1021
初始值:0x0000
基准输入:false
基准输出:false
标志位:0x0000

9、CRC16/DNP:
公式:x16+x13+x12+x11+x10+x8+x6+x5+x2+1
宽度:16
Poly值:0x3D65
初始值:0x0000
基准输入:true
基准输出:true
标志位:0xFFFF
使用:M-Bus, ect

关于数据位序:如果我们的机器是小端模式(低位在后,高位在前),而数据输入的要求是低位在前高位在后时,就需要对数据顺序进行反转。

多项式的值是如果计算的:
以多项式:x16 + x12 + x5 + 1 为例
x16表示第16位为1,x12表示第12位为1,x5表示第5位为1
(1<<16) | (1<<12) | (1<<5) | 1 = 1 0001 000 0010 0001 = 0x1 1021
CRC16只取上面计算值的低16位所以最终结果为0x1021。

C语言实现:以CRC16/CCITT 公式:x16+x15+x5+1

#define CRC_INIT 0xFFFF  //CRC初始值
#define CRC_CODE 0x1021
#define BIT(num, x) ((num>>x) & 0x1)  
/*16位 位逆转*/
unsigned short InvertUint16(unsigned short src){	
	unsigned short temp = 0;
	for(int bit=0; bit<16; bit++){
  		if(src & (1<<bit))
  		 temp |= 1<<(15-bit);
 	}
 	return temp;
}
/*@data 要计算的数据
 * @init CRC16 初始值
* @poly CRC16 poly值
 *@len  数据长度
 * */
unsigned short CRC16(unsigned char * data,unsigned short init, unsigned short poly,unsigned int length){
	unsigned short crc = init;
 	unsigned char one = 0;
 	while(length--){
  		one = InvertUint8(*data++);
 		 crc ^= (one<<8); //与CRC的高8位异或
 		
 		 for(int bit=0; bit<8; bit++){
  			 if(crc & 0x8000){ //最高位为1,左移一位与hex码异或
   			 	crc = (crc<<1)^poly; 
  			 }else{
    				crc = crc<<1;
 			  }
		  }
	}
	return InvertUint16(crc); /*输出逆序返回*/
}

上面的CRC计算纯采用逻辑运行的方式,运行量比较大,每一个字节 都要进行8次判断、移位、或异或操作。可以采用查表法减少计算量,先计算出从0x00到0xff之间每一个字节的CRC校验结果,然后可以通过查表来查出每个字节的CRC结果,减少计算量。

  • 6
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值