1. 程式人生 > 其它 >使用Java實現CRC16 MODBUS 格式校驗

使用Java實現CRC16 MODBUS 格式校驗

技術標籤:java演算法

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 為正確結果