1了解CRC
1.介绍
循环冗余校验(英语:Cyclic redundancy check,通称“CRC”)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种散列函数,主要用来检测或校验数据传输或者保存后可能出现的错误。生成的数字在传输或者存储之前计算出来并且附加到数据后面,然后接收方进行检验确定数据是否发生变化。
---维基百科
讲到CRC大家一定不陌生,在自控系统中很多通讯协议都用到它,如耳熟能详的Modbus RTU。很多人应该都是通过此协议了解并熟悉CRC的。
概括讲其中的CRC就是Modbus RTU通信中检查传输的信息是否有误的一种方法。
2.原理
CRC为校验和的一种,是两部分字节数据流采用模2除法(没有进位,使用异或(XOR)来代替减法)相除所得到的余数。
其中被除数是需要计算校验和的信息数据流的二进制表示(如Modbus RTU协议中就是:从机地址(1字节)+Modbus PDU,长度不超过253字节)。
除数是一个长度为(n+1)的预定义(短)的二进制数,通常用多项式(及CRC多项式)的系数来表示。
在做除法之前,要在信息数据之后先加上n个0(如Modbus RTU协议 n=16,及除数多项式最高阶数为16阶)。
2CRC 多项式
CRC多项式说简单也简单,就是多项式所有系数都为0或1(最高阶数的系数为1),匹配计算机的二进制。
如Modbus RTU协议常用的CRC-16多项式X16+X15+X2+1,它的系数二进制集合就是11000000000000101为17位,十六进制等于0x8005(去除最高阶的系数)。
说复杂也复杂,CRC多项式的设计要考虑很多因素,如选择的多项式必须有最大的错误检测能力,同时保证总体的碰撞概率最小等,这里就不再多讲述,可参考下面的链接。
Cyclic redundancy check:
https://en.wikipedia.org/wiki/Cyclic_redundancy_check
下面表格是一些常用的CRC多项式(不包含“初始值”、“反射值”以及“最终异或值”)
3模2运算
二进制模2算术运算不同于一般二进制算术运算的规则,其没有进位和借位,加法等同于“异或”运算。
关于二进制数的算术运算原理,可以观看下面链接中的视频:
https://www.coursera.org/lecture/jisuanji-wangluo/er-jin-zhi-shu-de-suan-zhu-yun-suan-wuzUr
①模2加法运算规则:
规则是两个序列模二相加,即两个序列中对应位,相加,不进位,相同为0,不同为1,等于异或运算。
0+0=0 0+1=1 1+0=1 1+1=0(无进位)
②模2减法运算规则:
0-0=0 0-1=1 (无借位) 1-0=1 1-1=0
两个数相加和相减结果是一样的。
③模2乘法运算规则:
0×0=0 0×1=0 1×0=0 1×1=1
④模2除法运算规则:
0÷1=1 1÷1=0 1÷0=1 0÷0=0
对于二进制算术运算大家需要了解,其实上面链接里的视频已经讲了,二进制乘运算就是左移与加运算、除运算就是右移与减运算,而减运算又可以转换成加运算(如6-5=6+(-5),其中负数使用补码表示),所以在计算机中四则运算都是通过移位和加运算来实现的。
模2除法运算中,余数项由被除数和除数对应位的异或求得,而商项由余数项去除最高位后的首位确定,为1时商为1为0时商为0,商项为0时除数项使用与除数等位数的0代替。直到余数位数小于除数位数时计算结束。对于CRC校验和运算最后所得的余数即为校验结果值(除非所选择的CRC规范要求进行一些后处理)。
4CRC值的计算
1.手算
一般来说,其形式为:
M(x)·xn=Q(X)·K(x)-R(x)
这里M(x)是原始的信息流多项式。K(x)是n阶的CRC多项式。表示了将原始信息后面加上n个0。R(x)是余数多项式,即是CRC“校验和”。
在通信中,发送者在原始的信息数据M后附加上n位的R(替换本来附加的0)再发送。接收者收到M和R后,检查M(x)·xn+R(x)否能被K(x)整除。如果是,那么接收者认为该信息是正确的。值得注意的是M(x)·xn+R(x)就是发送者所想要发送的数据。
我们以简单的信息流101001为例,使用CRC-3多项式X3+X2+1来计算CRC校验码。
先使信息流左移3位补0得到被除数101001000,除以除数1101(CRC-3多项式系数合集)。
计算步骤如下:
最后余数为001及为CRC校验码。加上校验的完整报文为:信息流+CRC=101001001。
这里提一下,串行通信中经常用到的奇偶校验偶校验是循环冗余校验(CRC)的特殊情况,其中1位CRC由多项式 x + 1 生成。大家可以试算一下。
2.计算机中CRC计算方法
通常计算机中信息都是按字节来存储,数据的操作指令都有限制,如不可能把一很长信息流的被除数直接左移n位。并且不同的通讯协议,信息流传输的顺序也不同。但可以根据CRC计算的原理结合软件的指令找到合适的算法。
下面是一个三菱PLC GX Works2中计算CRC-16的例子:
V0:=ADDR;
CRC:=Init;
ByteNr:=LEN-1;
FOR INDEX1 := 0 TO ByteNr BY 1 DO
IF Mode THEN
IF ( INDEX1 MOD 2 )<> 0THEN
Data:=D0V0;
ROR( TRUE , 8 ,Data);
ELSE
Data:=D0V0;
END_IF;
ELSE
Data:=D0V0;
END_IF;
IF RefIn THEN
Bytedata :=SWAP_B( Data);
ELSE
Bytedata := Data;
END_IF;
Iteration := H0080;
FOR INDEX2 := 0 TO 7 BY 1 DO
IF ((CRC AND H8000) <> H0000) THEN
ROL( TRUE , 1 ,CRC );
CRC:=CRC&HFFFE;
CRC := CRC XOR Poly;
ELSE
ROL( TRUE , 1 ,CRC );
CRC:=CRC&HFFFE;
END_IF;
IF ((Bytedata AND Iteration) <> H0000) THEN
CRC := CRC XOR Poly;
END_IF;
ROR( TRUE , 1 ,Iteration);
END_FOR;
IF Mode THEN
IF ( INDEX1 MOD 2 )<> 0 THEN
V0:=V0+1;
END_IF;
ELSE
V0:=V0+1;
END_IF;
END_FOR;
IF RefOut THEN
CRC:=SWAP_W(CRC );
END_IF;
CRC := CRC XOR XorOut;
IF ByteSwap THEN
ROR(TRUE , 8 ,CRC);
END_IF;
CRC16 := CRC;
更多精彩内容,可关注本人微信公众号scadafaq