使用Java實現CRC16 MODBUS 格式校驗
阿新 • • 發佈:2021-01-20
CRC16校驗,測試如下
String str = "a5 98 03 00 00 5f c6 0f 7c 40 78 06 09 46 dc 6e db 00 16 3e 12 5c 98 00 19 98 0e 10 03 06 09 46 dc 6e db 03 0b bf 5f c6 0f 7c 43 bd b9 61 ee 96 76 99";
校驗規則:
/**
* CRC16_CCITT:多項式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,高位在後,結果與0x0000異或
* CRC16_CCITT_FALSE:多項式x16+x12+x5+1(0x1021),初始值0xFFFF,低位在後,高位在前,結果與0x0000異或
* CRC16_XMODEM:多項式x16+x12+x5+1(0x1021),初始值0x0000,低位在後,高位在前,結果與0x0000異或
* CRC16_X25:多項式x16+x12+x5+1(0x1021),初始值0xffff,低位在前,高位在後,結果與0xFFFF異或
* CRC16_MODBUS:多項式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,高位在後,結果與0x0000異或
* CRC16_IBM:多項式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,高位在後,結果與0x0000異或
* CRC16_MAXIM:多項式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,高位在後,結果與0xFFFF異或
* CRC16_USB:多項式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,高位在後,結果與0xFFFF異或
* CRC16_DNP:多項式x16+x13+x12+x11+x10+x8+x6+x5+x2+1(0x3D65),初始值0x0000,低位在前,高位在後,結果與0xFFFF異或
* <p>
* (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碼。
* <p>
* 以上計算步驟中的多項式0xA001是0x8005按位顛倒後的結果。
* 0x8408是0x1021按位顛倒後的結果。
* 線上校驗工具
* http://www.ip33.com/crc.html
* https://blog.csdn.net/htmlxx/article/details/17369105
*
* @param s 需要輸入十六進位制字串
* @return 結果資料CRC16 modbus格式
* by djy
*/
private static String getCRC16Result(String s){
int CRC = 0x0000ffff;
for (int i=0;i<s.length();i=i+2){
int CRCL=CRC&0x000000FF;//低八位
int CRCH=CRC&0x0000FF00;//高八位
String CRCIn = s.substring(i,i+2);
// System.out.println(CRCIn);
int a = Integer.parseInt(CRCIn,16);//待處理資料轉16進位制
CRC=CRCH+CRCL^a;
for(int j=0;j<8;j++){
if((CRC&0x0001)==0){
CRC=CRC>>1;
}else {
CRC>>=1;
CRC=CRC^0xA001;
}
}
}
// 交換
// int CRCL=CRC&0x000000FF;//低八位
// int CRCH=CRC&0x0000FF00;//高八位
// System.out.println(Integer.toHexString(CRCL));
// System.out.println(Integer.toHexString(CRC));
// CRC=CRCL<<8|CRCH>>8;//最好用按位與,別用加
// System.out.println(Integer.toHexString(CRC));
return Integer.toHexString(CRC);
}
結果如圖
public static void main(String args[]){
String str = "a5 98 03 00 00 5f c6 0f 7c 40 78 06 09 46 dc 6e db 00 16 3e 12 5c 98 00 19 98 0e 10 03 06 09 46 dc 6e db 03 0b bf 5f c6 0f 7c 43 bd b9 61 ee 96 76 99";
String str3 = str.replace(" ","");
// int len = str3.length();
// if((len%2==1)){//奇數位返0
// System.out.println("奇數出錯");
// }
// int num = len/2;
// byte[] para = new byte[num];
// for(int i = 0;i<num;i++){
// int value = Integer.valueOf(str3.substring(i*2,2*(i+1)),16);
// para[i]=(byte)value;
// }
// System.out.println(CRC16_MODBUS(para)+"*************************");
System.out.println(getCRC16Result(str3)+"*************************");
}
C9 2A 為正確結果