C++与JAVA代码实现CRC-16/MODBUS算法

CRC-16/MODBUS的多项式为:x16+x15+x2+1(8005),宽度为16。运算时,首先将一个16位的寄存器预置为11111111 11111111,然后连续把数据帧中的每个字节中的8位与该寄存器的当前值进行运算。仅仅每个字节的8位数据位参与生成CRC。

在生成CRC时,每个字节的8位与寄存器中的内容进行异或,然后将结果向低位位移,高位则用0补充,最低位(LSB)移出并检测,如果是1,该寄存器就与一个预设的固定值(0A001H)进行一次异或运算,如果低位为0,不作任何处理。

上述处理重复进行,直到执行完了8次位移操作,当最后一位移完以后,下一个8位字节与寄存器当前的值进行异或运算,同样进行上述的另一轮8次位移异或才做,当数据帧中的所有字节都做了处理,生成最终值就是CRC值。

生成CRC的流程为:

  1. 预置一个16位寄存器位FFFFH,称之为CRC寄存器。

  2. 把数据帧中第一个字节的8位与CRC寄存器中的低字节进行异或运算,结果存回CRC寄存器。

  3. 将CRC寄存器向右移1位,最高位以0填充,最低位移出并监测。

  4. 如果最低位为0:重复第3步(下一次移位),如果最低位为1:将CRC寄存器与一个预设的固定值(0A001H)进行异或运算。

  5. 重复第3步和第4步直到8次位移,这样就处理完了一个完整的8位。

  6. 重复第2步到第5步来处理下一个字节,知道处理完校验位前所有的数据。

  7. 最终CRC寄存器得值就是CRC的值。

 

C++代码实现

 1 #include <stdio.h>
 2 #include<iostream>
 3 #include<string>
 4 #include<sstream>
 5 using namespace std;
 6 
 7 unsigned short getCrc16(unsigned char *arr, int len); 
 8 
 9 string intToHexStr(int data);
10 
11 int main()
12 {
13     unsigned char arr[] = {0x48, 0x4C, 0x01, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00};
14     int len = 10;
15     int crcInt;
16     crcInt = getCrc16(arr, len);
17     printf( "crc16 int is: %d\n", crcInt );
18     string crcStr;
19     crcStr = intToHexStr(crcInt);
20     cout << "crc16 hex is: " <<  crcStr.c_str() <<endl;
21     リターン 0 ;
22  }
 23  
24  / * *
 25  *进行CRC-6 / MODBUS计算
 26   * / 
27の符号なしショート getCrc16(符号なしのchar *のARR、INT LEN)
 28  {
 29      符号なしの短い斧、LSB。
30      int型I、J。
31      AX = 0xFFFFの32      のために(i = 0 ; iがLEN <; iは++ 33      {
 34          AX ^ = ARRの[I]。
35          のための(J = 0 ; J < 8。、J ++ 36          {
 37 [              LSB = AX&0x0001に38である              AX = AX >> 1。;
 39              IF(!LSB = 0 40              {
 41である                  AX ^ = 0xA001 ;
 42である             }
 43れる         }
 44れます     }
 45      リターンAX;
 46である }
 47  
48  / * *
 49  * INT 16進文字列データ型に変換
 50   * /
51 string intToHexStr(int data)
52 {
53     /*** 将int类型数据转换成16进制字符串 ***/
54     string hexStr;
55     ostringstream temp;
56     temp<<hex<<data;
57     hexStr = temp.str();
58     
59     /*** 将小写转大写 ***/
60     int i;
61     int len = hexStr.size();
62     for (i = 0; i < len; i++) {
63         hexStr[i] = toupper(hexStr[i]);
64     }
65     
66     /*** 保证将字符串长度为4 ***/
67     while (hexStr.size() < 4) {
68         hexStr = "0" + hexStr;
69     }
70     
71     /*** 返回 ***/
72     return hexStr;
73 }

 

JAVA代码实现

  1 package com.yanwu.demo.utils;
  2 
  3 /**
  4  * @author <a herf="mailto:[email protected]">yanwu</a>
  5  * @date 2019-08-26 14:22.
  6  * <p>
  7  * description:
  8  * 本方法使用CRC-16/MODBUS算法
  9  */
 10 public class Crc16Util {
 11     private static final Integer TWO = 2;
 12     private static final Integer HEX = 16;
 13     private static final String NUL = "";
 14     private static final String SPACE = " ";
 15     private static final String ASCII = "US-ASCII";
 16 
 17     /**
 18      * 根据报文byte数组,获取CRC-16 16进制字符串
 19      * 48 4C 01 00 01 00 00 05 00 00 >> 0xE647
 20      *
 21      * @param data
 22      * @return
 23      */
 24     public static String getCrc16HexStr(String data) {
 25         return intToHexStr(getCrc16(data));
 26     }
 27 
 28     /**
 29      * 根据报文byte数组,获取CRC-16 int值
 30      * 48 4C 01 00 01 00 00 05 00 00 >> 58951
 31      *
 32      * @param data 报文数组
 33      * @return CRC值(10进制)
 34      */
 35     public static int getCrc16(String data) {
 36         data = data.replaceAll(SPACE, NUL);
 37         return getCrc16(getByteArr(data));
 38     }
 39 
 40     /**
 41      *パケットのバイト配列、CRC-16 16を得ることが16進数の文字列
 42は、      * {0x48、0x4C、0x01で、0x00を、0x01の、0x00を、0x00に、0x05を、0x00に、0x00の} >> 0xE647
 43である      *
 44れる      * @param データ
 45       * @return 
46である      * / 
47      パブリック 静的文字列getCrc16HexStr(バイト[]データ){
 48          リターンintToHexStr(getCrc16(データ));
 49      }
 50  
51れる     / ** 
52れる      *バイトアレイパケットに応じて、CRC-16、INT値取得
 53       {0x48 *、0x4C、0x01で、0x00を、0x01の、0x00を、0x00に、0x05を、0x00に、0x00の} >> 58951
 54であります      *
55       * @paramのデータ・パケット・アレイ
 56は、      * @return CRC値(10進)
 57がある      * / 
58      パブリック 静的 INT getCrc16(バイト[]データ){
 59          // -----予め設定されたCRCは、初期値レジスタ0xFFFFである
60          INT CRC = 0xFFFFのは61であり         、バイト ByteLen = 8 ;
 62である         ためバイトB:データ){
 63である             // -----サイクル、CRCレジスタの各バイトを、各データフレームの下位ワードはXOR部
64              CRC ^ =((INT)B&0x00FFに);
 65               (int j = 0; j < byteLen; j++) {
 66                 // ----- 将寄存器右移1位,最高位自动补0
 67                 if ((crc & 0x0001) != 0) {
 68                     // ----- 如果右移出来的位不为0,将寄存器与固定值 0xA001 异或运算
 69                     crc >>= 1;
 70                     crc ^= 0xA001;
 71                 } else {
 72                     // ----- 如果右移出来的位为0,不做处理,进行下一次右移,知道处理完整个字节的8位
 73                     crc >>= 1;
 74                 }
 75             }
 76         }
 77         // ----- 最终寄存器得值就是CRC的值,返回
 78         return crc;
 79     }
 80 
 81     /**
 82      * 将16进制字符串转换为16进制Byte数组
 83      * 48 4C 01 00 01 00 00 05 00 00 >> {0x48, 0x4C, 0x01, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00}
 84      *
 85      * @param str 报文字符串
 86      * @return 报文数组
 87      */
 88     public static byte[] getByteArr(String str) {
 89         str = str.replaceAll(SPACE, NUL);
 90         int strLen = str.length();
 91         byte[] result = new byte[strLen / TWO];
 92         // ----- 两位一个字节
 93         for (int i = 0; i < strLen; i += TWO) {
 94             String temp = str.substring(i, i + TWO);
 95             result[i / TWO] = (byte) Integer.parseInt(temp, HEX);
 96         }
 97         return result;
 98     }
 99 
100     /**
101      * 将CRC-16值转换成16进制字符串,且保持最小长度为4位
102      * <p>
103      * 58951 >> E647
104      *
105      * @param data
106      * @return
107      */
108     private static String intToHexStr(int data) {
109         String crcStr = Integer.toHexString(data).toUpperCase();
110         int size = 4 - crcStr.length();
111         StringBuilder builder = new StringBuilder();
112         // ---- 长度不够 4 位高位自动补0
113         while (size > 0) {
114             builder.append("0");
 115              size-- ;
 1 16          }
 117          戻りbuilder.append(crcStr).toString();
 118      }
 119  
120      / ** 
121       * 16バイナリ出力長、テストコードのメソッド使用C ++ CRCチェックに供給され、
 122       *
 123       *の@param STR
 124       * / 
125      プライベート 静的 ボイドprintHexStr(文字列STR){
 126          のString [] =分割str.split(SPACE)
 127          のStringBuilderビルダー= 新しい新規のStringBuilder();
 128         builder.append( "unsigned char型のARR [] = {" )。
129          のためには、int型 ; iはsplit.length <I ++は、I = 0 ){
 130              builder.append( "0X" ).append(スプリット[i])とします。
131              であれば(私はsplit.lengthを< - 1 ){
 132                  builder.append( "" )。
133              }
 134          }
 135          builder.append( "};" );
136          のSystem.out.println(builder.toString())。
137          のSystem.out.println( "int型LEN =" + split.length + ";" );
  
140     /**
141      * 测试CRC获取
142      *
143      * @param args
144      */
145     public static void main(String[] args) throws Exception {
146         String str = "48 4C 01 00 01 00 00 05 00 00";
147         // ----- 输出16进制数组给 C++ 测试使用
148         Crc16Util.printHexStr(str);
149         // ----- 获取CRC-16的值
150         System.out.println("crc16 int is: " + Crc16Util.getCrc16(str));
151         System.out.println("crc16 hex is: " + Crc16Util.getCrc16HexStr(str));152     }
153 
154 }

 

おすすめ

転載: www.cnblogs.com/yanwu0527/p/11424730.html