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;
更多精彩內容,可關注本人微信公衆號scadaclub