CRC(循環(huán)冗余校驗(yàn))在線計(jì)算:
http://www.ip33.com/crc.html
LRC校驗(yàn)(縱向冗余校驗(yàn))在線計(jì)算:
http://www.ip33.com/lrc.html
BCC校驗(yàn)(異或校驗(yàn))在線計(jì)算:
http://www.ip33.com/bcc.html
CRC校驗(yàn)(循環(huán)冗余校驗(yàn))小知識(shí)
CRC即循環(huán)冗余校驗(yàn)碼(Cyclic Redundancy Check):是數(shù)據(jù)通信領(lǐng)域中最常用的一種查錯(cuò)校驗(yàn)碼,其特征是信息字段和校驗(yàn)字段的長(zhǎng)度可以任意選定。循環(huán)冗余檢查(CRC)是一種數(shù)據(jù)傳輸檢錯(cuò)功能,對(duì)數(shù)據(jù)進(jìn)行多項(xiàng)式計(jì)算页响,并將得到的結(jié)果附在幀的后面肋层,接收設(shè)備也執(zhí)行類似的算法,以保證數(shù)據(jù)傳輸?shù)恼_性和完整性渔伯。
- CRC算法參數(shù)模型解釋:
NAME:參數(shù)模型名稱。
WIDTH:寬度,即CRC比特?cái)?shù)敏簿。
POLY:生成項(xiàng)的簡(jiǎn)寫,以16進(jìn)制表示。例如:CRC-32即是0x04C11DB7惯裕,忽略了最高位的"1"温数,即完整的生成項(xiàng)是0x104C11DB7。
INIT:這是算法開始時(shí)寄存器(crc)的初始化預(yù)置值蜻势,十六進(jìn)制表示撑刺。
REFIN:待測(cè)數(shù)據(jù)的每個(gè)字節(jié)是否按位反轉(zhuǎn),True或False握玛。
REFOUT:在計(jì)算后之后够傍,異或輸出之前,整個(gè)數(shù)據(jù)是否按位反轉(zhuǎn)挠铲,True或False冕屯。
XOROUT:計(jì)算結(jié)果與此參數(shù)異或后得到最終的CRC值。
常見CRC參數(shù)模型如下:
CRC算法名稱 | 多項(xiàng)式公式 | 寬度 | 多項(xiàng)式 | 初始值 | 結(jié)果異或值 | 輸入反轉(zhuǎn) | 輸出反轉(zhuǎn) |
---|---|---|---|---|---|---|---|
CRC-4/ITU | x4 + x + 1 | 4 | 03 | 00 | 00 | true | true |
CRC-5/EPC | x5 + x3 + 1 | 5 | 09 | 09 | 00 | false | false |
CRC-5/ITU | x5 + x4 + x2 + 1 | 5 | 15 | 00 | 00 | true | true |
CRC-5/USB | x5 + x2 + 1 | 5 | 05 | 1F | 1F | true | true |
CRC-6/ITU | x6 + x + 1 | 6 | 03 | 00 | 00 | true | true |
CRC-7/MMC | x7 + x3 + 1 | 7 | 09 | 00 | 00 | false | false |
CRC-8 | x8 + x2 + x + 1 | 8 | 07 | 00 | 00 | false | false |
CRC-8/ITU | x8 + x2 + x + 1 | 8 | 07 | 00 | 55 | false | false |
CRC-8/ROHC | x8 + x2 + x + 1 | 8 | 07 | FF | 00 | true | true |
CRC-8/MAXIM | x8 + x5 + x4 + 1 | 8 | 31 | 00 | 00 | true | true |
CRC-16/IBM | x16 + x15 + x2 + 1 | 16 | 8005 | 0000 | 0000 | true | true |
CRC-16/MAXIM | x16 + x15 + x2 + 1 | 16 | 8005 | 0000 | FFFF | true | true |
CRC-16/USB | x16 + x15 + x2 + 1 | 16 | 8005 | FFFF | FFFF | true | true |
CRC-16/MODBUS | x16 + x15 + x2 + 1 | 16 | 8005 | FFFF | 0000 | true | true |
CRC-16/CCITT | x16 + x12 + x5 + 1 | 16 | 1021 | 0000 | 0000 | true | true |
CRC-16/CCITT-FALSE | x16 + x12 + x5 + 1 | 16 | 1021 | FFFF | 0000 | false | false |
CRC-16/X25 | x16 + x12 + x5 + 1 | 16 | 1021 | FFFF | FFFF | true | true |
CRC-16/XMODEM | x16 + x12 + x5 + 1 | 16 | 1021 | 0000 | 0000 | false | false |
CRC-16/DNP | x16 + x13 + x12 + x11 + x10 + x8 + x6 + x5 + x2 + 1 | 16 | 3D65 | 0000 | FFFF | true | true |
CRC-32 | x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 | 32 | 04C11DB7 | FFFFFFFF | FFFFFFFF | true | true |
CRC-32/MPEG-2 | x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 | 32 | 04C11DB7 | FFFFFFFF | 00000000 | false | false |
案例一:
指令說明
image.png
指令
image.png
案例二:
指令說明
image.png
指令
image.png
image.png
image.png
CRC8
使用列子
byte[] data = new byte[8];
data[0] = (byte) 0xA5;
data[1] = (byte) 0x01;
data[2] = (byte) ~0x01;
data[3] = (byte) 0x00;
data[4] = (byte) seqNo;
data[5] = (byte) 0;
data[6] = (byte) 0;
data[7] = BleCRC.calCRC8(data);
public class BleCRC {
/**
* CRC8 code table
*/
private static final char[] Table_CRC8 = { 0x00, 0x07, 0x0E, 0x09, 0x1C,
0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46,
0x41, 0x54, 0x53, 0x5A, 0x5D, 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB,
0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, 0x90,
0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1,
0xB4, 0xB3, 0xBA, 0xBD, 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5,
0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 0xB7, 0xB0,
0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93,
0x94, 0x9D, 0x9A, 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, 0x57, 0x50, 0x59,
0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74,
0x7D, 0x7A, 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1,
0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, 0xF9, 0xFE, 0xF7, 0xF0,
0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3,
0xD4, 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56,
0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 0x19, 0x1E, 0x17, 0x10, 0x05,
0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78,
0x7F, 0x6A, 0x6D, 0x64, 0x63, 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25,
0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 0xAE,
0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F,
0x8A, 0x8D, 0x84, 0x83, 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC,
0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 };
/**
* Generate CRC8 code
* @param buf Data buffer
* @return CRC8 code, return 0 when the parameter is error
*/
public static byte calCRC8(byte[] buf) {
if (buf == null || buf.length == 0) {
return 0;
}
byte crc = 0;
for (int i = 0; i < buf.length-1; i++) {
crc = (byte)Table_CRC8[0x00ff & (crc ^ (buf[i]))];
}
return crc;
}
}
LRC
使用列子
byte[] data = new byte[8];
data[0] = (byte) 0xA5;
data[1] = (byte) 0x01;
data[2] = (byte) ~0x01;
data[3] = (byte) 0x00;
data[4] = (byte) seqNo;
data[5] = (byte) 0;
data[6] = (byte) 0;
data[7] = BleCRC.getLRC(data);
//或者
byte[] data = new byte[8];
data[0] = (byte) 0xA5;
data[1] = (byte) 0x01;
data[2] = (byte) ~0x01;
data[3] = (byte) 0x00;
data[4] = (byte) seqNo;
data[5] = (byte) 0;
data[6] = (byte) 0;
data[7] = (byte) (bytes[0] ^ bytes[1] ^ bytes[2] ^ bytes[3] ^ bytes[4] ^ bytes[5] ^ bytes[6] ^ bytes[7];
/*
* 輸入byte[] data , 返回LRC校驗(yàn)byte
*/
public static byte getLRC(byte[] data) {
int tmp = 0;
for (int i = 0; i < data.length; i++) {
tmp = tmp + (byte) data[i];
}
tmp = ~tmp;
tmp = (tmp & (0xff));
tmp += 1;
return (byte) tmp;
}
CRC16
public class CRC16Util {
/**
* 將int轉(zhuǎn)換成byte數(shù)組市殷,低位在前愕撰,高位在后
* 改變高低位順序只需調(diào)換數(shù)組序號(hào)
*/
private static byte[] intToBytes(int value) {
byte[] src = new byte[2];
src[1] = (byte) ((value >> 8) & 0xFF);
src[0] = (byte) (value & 0xFF);
return src;
}
/**
* 獲取源數(shù)據(jù)和驗(yàn)證碼的組合byte數(shù)組
*
* @param strings 可變長(zhǎng)度的十六進(jìn)制字符串
* @return
*/
public static byte[] appendCrc16(String... strings) {
byte[] data = new byte[]{};
for (int i = 0; i < strings.length; i++) {
int x = Integer.parseInt(strings[i], 16);
byte n = (byte) x;
byte[] buffer = new byte[data.length + 1];
byte[] aa = {n};
System.arraycopy(data, 0, buffer, 0, data.length);
System.arraycopy(aa, 0, buffer, data.length, aa.length);
data = buffer;
}
return appendCrc16(data);
}
/**
* 獲取源數(shù)據(jù)和驗(yàn)證碼的組合byte數(shù)組
*
* @param aa 字節(jié)數(shù)組
* @return
*/
public static byte[] appendCrc16(byte[] aa) {
byte[] bb = getCrc16(aa);
byte[] cc = new byte[aa.length + bb.length];
System.arraycopy(aa, 0, cc, 0, aa.length);
System.arraycopy(bb, 0, cc, aa.length, bb.length);
return cc;
}
/**
* 獲取驗(yàn)證碼byte數(shù)組,基于Modbus CRC16的校驗(yàn)算法
*/
public static byte[] getCrc16(byte[] arr_buff) {
int len = arr_buff.length;
// 預(yù)置 1 個(gè) 16 位的寄存器為十六進(jìn)制FFFF, 稱此寄存器為 CRC寄存器醋寝。
int crc = 0xFFFF;
int i, j;
for (i = 0; i < len; i++) {
// 把第一個(gè) 8 位二進(jìn)制數(shù)據(jù) 與 16 位的 CRC寄存器的低 8 位相異或, 把結(jié)果放于 CRC寄存器
crc = ((crc & 0xFF00) | (crc & 0x00FF) ^ (arr_buff[i] & 0xFF));
for (j = 0; j < 8; j++) {
// 把 CRC 寄存器的內(nèi)容右移一位( 朝低位)用 0 填補(bǔ)最高位, 并檢查右移后的移出位
if ((crc & 0x0001) > 0) {
// 如果移出位為 1, CRC寄存器與多項(xiàng)式A001進(jìn)行異或
crc = crc >> 1;
crc = crc ^ 0xA001;
} else
// 如果移出位為 0,再次右移一位
crc = crc >> 1;
}
}
return intToBytes(crc);
}
}
byte與String互轉(zhuǎn)
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class BytesHexStrTranslate {
public static void main(String[] args) throws Exception {
byte[] bytes = "測(cè)試".getBytes("utf-8");
System.out.println("字節(jié)數(shù)組為:" + Arrays.toString(bytes));
System.out.println("方法一:" + bytesToHexFun1(bytes));
System.out.println("方法二:" + bytesToHexFun2(bytes));
System.out.println("方法三:" + bytesToHexFun3(bytes));
System.out.println("==================================");
String str = "e6b58be8af95";
System.out.println("轉(zhuǎn)換后的字節(jié)數(shù)組:" + Arrays.toString(toBytes(str)));
System.out.println(new String(toBytes(str), "utf-8"));
}
/**
* 把十六進(jìn)制字符串轉(zhuǎn)成字符數(shù)組
* @param value
* @return
*/
public static List<String> stringToStrZu(String value) {
List<String> deviceValue = new ArrayList<>();
int count = value.length();
int index = 0;
int end = 2;
while (count > 0) {
deviceValue.add(value.substring(index, end));
index += 2;
end += 2;
count -= 2;
}
return deviceValue;
}
private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* 方法一:
* byte[] to hex string
*
* @param bytes
* @return
*/
public static String bytesToHexFun1(byte[] bytes) {
// 一個(gè)byte為8位搞挣,可用兩個(gè)十六進(jìn)制位標(biāo)識(shí)
char[] buf = new char[bytes.length * 2];
int a = 0;
int index = 0;
for(byte b : bytes) { // 使用除與取余進(jìn)行轉(zhuǎn)換
if(b < 0) {
a = 256 + b;
} else {
a = b;
}
buf[index++] = HEX_CHAR[a / 16];
buf[index++] = HEX_CHAR[a % 16];
}
return new String(buf);
}
/**
* 方法二:
* byte[] to hex string
*
* @param bytes
* @return
*/
public static String bytesToHexFun2(byte[] bytes) {
char[] buf = new char[bytes.length * 2];
int index = 0;
for(byte b : bytes) { // 利用位運(yùn)算進(jìn)行轉(zhuǎn)換,可以看作方法一的變種
buf[index++] = HEX_CHAR[b >>> 4 & 0xf];
buf[index++] = HEX_CHAR[b & 0xf];
}
return new String(buf);
}
/**
* 方法三:
* byte[] to hex string
*
* @param bytes
* @return
*/
public static String bytesToHexFun3(byte[] bytes) {
StringBuilder buf = new StringBuilder(bytes.length * 2);
for(byte b : bytes) { // 使用String的format方法進(jìn)行轉(zhuǎn)換
buf.append(String.format("%02x", new Integer(b & 0xff)));
}
return buf.toString();
}
/**
* 將16進(jìn)制字符串轉(zhuǎn)換為byte[]
*
* @param str
* @return
*/
public static byte[] toBytes(String str) {
if(str == null || str.trim().equals("")) {
return new byte[0];
}
byte[] bytes = new byte[str.length() / 2];
for(int i = 0; i < str.length() / 2; i++) {
String subStr = str.substring(i * 2, i * 2 + 2);
bytes[i] = (byte) Integer.parseInt(subStr, 16);
}
return bytes;
}
}