MODBUS CRC校驗原理及C語言實現
MODBUS通訊協議的CRC校驗原理多項式為8005的逆序A001列01的CRC校驗原理:1111111111111111 初始化CRC寄存機0000000000000001 1111111111111110 異或0111111111111111 0 LSB為0 第一次右位移0011111111111111 1 LSB為1 第二次右位移1010000000000001//8005反序即A0011001111111111110 異或0100111111111111 0 LSB為0 第三次右位移0010011111111111 1 LSB為1
如果程式碼為0105則用05繼續與結果807E做上面八次位移異或即可。有好的演算法共同分享哈。
//========================================================================================
ModBus 通訊協議的 CRC ( 冗餘迴圈校驗碼)含2個位元組, 即 16 位二進位制數。
CRC 碼由傳送裝置計算, 放置於所傳送資訊幀的尾部。
接收資訊裝置再重新計算所接收資訊 (除 CRC 之外的部分)的 CRC, 比較CRC 結果
1)預置 1 個 16 位的暫存器為十六進位制FFFF(即全為 1) , 稱此暫存器為 CRC暫存器。
2) 把第一個 8 位二進位制資料 (通訊資訊幀的第一個位元組)
與 16 位的 CRC暫存器的低 8 位相異或, 把結果放於 CRC暫存器。
3) 把 CRC 暫存器的內容右移一位( 朝低位)用 0 填補最高位, 並檢查右移後的移出位。
4) 如果移出位為 0, 重複第 3 步 ( 再次右移一位); 如果移出位為 1, CRC 暫存器與多項式A001 ( 1010 0000 0000 0001) 進行異或。
5) 重複步驟 3 和步驟 4, 直到右移 8 次,這樣整個8位資料全部進行了處理。
6) 重複步驟 2 到步驟 5, 進行通訊資訊幀下一個位元組的處理。
7) 計算完成後,得到的16位CRC暫存器的高、低位元組進行交換。
8) 最後得到的 CRC暫存器內容即為 CRC碼。
Modbus CRC編碼的程式程式碼:
unsigned int CRC16 ( uchar *arr_buff, uchar len)
{
uint crc=0xFFFF;(1)
uchar i, j, Data;
for ( j=0; j
{
crc=crc ^*arr_buff++;
for ( i=0; i<8; i++)
{
if( ( crc&0x0001) >0)(2)
{
crc=crc>>1;
crc=crc^ 0xa001;
}
else
crc=crc>>1;(3) }
}
return ( crc);
}
//========================================================================================
/*計算CRC碼的步驟為:
(1).預置16位暫存器為FFFFH。稱此暫存器為CRC暫存器;
(2).把第一個8位資料與CRC暫存器的低位相異或,把結果放於CRC暫存器;
(3).把暫存器的內容右移一位(朝低位),用0填補最高位,檢查最低位;
(4).如果最低位為0:重複第3步(再次移位)如果最低位為1:CRC暫存器與多項式A001(1010 0000 0000 0001)進行異或;
(5).重複步驟3和4,直到右移8次,這樣整個8位資料全部進行了處理;
(6).重複步驟2到步驟5,進行下一個8位資料的處理;
(7).最後得到的CRC暫存器即為CRC碼。(CRC碼 = CRC_L +CRC_H)
*/
/*****************crc校驗**********************************************/
//crc生成函式,並將crc儲存在預先定於的陣列中
//呼叫方式crc16(指向資料的指標,需要校驗的資料長度)
unsigned char CRC[2];//定義陣列
void crc16(unsigned char *ptr,unsigned int len)
{
unsigned long wcrc=0XFFFF;//預置16位crc暫存器,初值全部為1
unsigned char temp;//定義中間變數
int i=0,j=0;//定義計數
for(i=0;i<len;i++)//迴圈計算每個資料
{
temp=*ptr&0X00FF;//將八位資料與crc暫存器亦或
ptr++;//指標地址增加,指向下個數據
wcrc^=temp;//將資料存入crc暫存器
for(j=0;j<8;j++)//迴圈計算資料的
{
if(wcrc&0X0001)//判斷右移出的是不是1,如果是1則與多項式進行異或。
{
wcrc>>=1;//先將資料右移一位
wcrc^=0XA001;//與上面的多項式進行異或
}
else//如果不是1,則直接移出
{
wcrc>>=1;//直接移出
}
}
}
temp=wcrc;//crc的值
CRC[0]=wcrc;//crc的低八位
CRC[1]=wcrc>>8;//crc的高八位
}
//===========================================================================================
(1)先選擇校驗時對幀進行除法運算的除數
(是二進位制比較特串,通常是以多項方式表示,所以CRC又稱多項式編碼方法,這個多項式也稱之為“生成多項式”)。
(2)看所選定的除數二進位制位數(k位),
然後在要傳送的資料幀(m位)後面加k-1位“0”,(一共是m+k-1位)
以“模2除法”方式除以上面這個除數,
所得到的餘數二進位制的位元串就是該幀的CRC校驗碼也稱之為FCS(幀校驗序列)。
注意,餘數的位數一定要比除數只能少一位。
(3)再把這個校驗碼附加在原資料幀後面
最後在接收端再把這個新幀以“模2除法”方式除以前面選擇的除數,
如果沒有餘數,則表明該幀在傳輸過程中沒出錯,否則出現了差錯。
但最高位和最低位必須均為“1”,
如在IBM的SDLC(同步資料鏈路控制)規程中使用的CRC-16(也就是這個除數一共是17位)生成多項式g(x)= x16 + x15 + x2 +1(對應二進位制位元串為:11000000000000101);
而在ISO HDLC(高階資料鏈路控制)規程、ITU的SDLC、X.25、V.34、V.41、V.42等中使用CCITT-16生成多項式g(x)= x16 + x15 + x5+1(對應二進位制位元串為:11000000000100001)。
“模2除法”與“算術除法”類似,但它既不向上位借位,也不比較除數和被除數的相同位數值的大小,只要以相同位數進行相除即可。
模2加法運算為:1+1=0,0+1=1,0+0=0,無進位,也無借位;
模2減法運算為:1-1=0,0-1=1,1-0=1,0-0=0,也無進位,無借位。
相當於二進位制中的邏輯異或運算。也就是比較後,兩者對應位相同則結果為“0”,不同則結果為“1”。
如100101除以1110,結果得到商為11,餘數為1,如圖5-9左圖所示0
如11×11=101,如圖5-9右圖所示。
圖5-9 “模2除法”和“模2乘法”示例
CRC的生成多項式是P=X3+1代表什麼
p(x)=x3+x2+x1+1 對應1111
p(x)=x3+ 1 對應1001