Java在与硬件通信协议中,我们需要利用帧头,长度,功能码,数据体等信息计算出CRC8校验码,就需要使用到Java封装的CRC8校验算法工具类,小编只是在项目中用到CRC校验算法(循环冗余校验算法),作为笔记保存起来,供日后使用!
1:先导入HexUtil工具类,代码如下:
public class HexUtil { private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; public static char[] encodeHex(byte[] data) { return encodeHex(data, true); } public static char[] encodeHex(byte[] data, boolean toLowerCase) { return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); } protected static char[] encodeHex(byte[] data, char[] toDigits) { if (data == null) return null; int l = data.length; char[] out = new char[l << 1]; for (int i = 0, j = 0; i < l; i++) { out[j++] = toDigits[(0xF0 & data[i]) >>> 4]; out[j++] = toDigits[0x0F & data[i]]; } return out; } public static String encodeHexStr(byte[] data) { return encodeHexStr(data, true); } public static String encodeHexStr(byte[] data, boolean toLowerCase) { return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); } protected static String encodeHexStr(byte[] data, char[] toDigits) { return new String(encodeHex(data, toDigits)); } public static String formatHexString(byte[] data) { return formatHexString(data, false); } public static String formatHexString(byte[] data, boolean addSpace) { if (data == null || data.length < 1) return null; StringBuilder sb = new StringBuilder(); for (int i = 0; i < data.length; i++) { String hex = Integer.toHexString(data[i] & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sb.append(hex); if (addSpace) sb.append(" "); } return sb.toString().trim(); } public static byte[] decodeHex(char[] data) { int len = data.length; if ((len & 0x01) != 0) { throw new RuntimeException("Odd number of characters."); } byte[] out = new byte[len >> 1]; // two characters form the hex value. for (int i = 0, j = 0; j < len; i++) { int f = toDigit(data[j], j) << 4; j++; f = f | toDigit(data[j], j); j++; out[i] = (byte) (f & 0xFF); } return out; } protected static int toDigit(char ch, int index) { int digit = Character.digit(ch, 16); if (digit == -1) { throw new RuntimeException("Illegal hexadecimal character " + ch + " at index " + index); } return digit; } public static byte[] hexStringToBytes(String hexString) { if (hexString == null || hexString.equals("")) { return null; } hexString = hexString.toUpperCase(); int length = hexString.length() / 2; char[] hexChars = hexString.toCharArray(); byte[] d = new byte[length]; for (int i = 0; i < length; i++) { int pos = i * 2; d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); } return d; } public static byte charToByte(char c) { return (byte) "0123456789ABCDEF".indexOf(c); } public static String extractData(byte[] data, int position) { return HexUtil.formatHexString(new byte[]{data[position]}); } //使用1字节就可以表示b public static String numToHex8(int b) { return String.format("%02x", b);//2表示需要两个16进行数 } //需要使用2字节表示b public static String numToHex16(int b) { return String.format("%04x", b); } //需要使用4字节表示b public static String numToHex32(int b) { return String.format("%08x", b); } public static String getBitString(byte by){ StringBuffer sb = new StringBuffer(); sb.append((by>>7)&0x1) .append((by>>6)&0x1) .append((by>>5)&0x1) .append((by>>4)&0x1) .append((by>>3)&0x1) .append((by>>2)&0x1) .append((by>>1)&0x1) .append((by>>0)&0x1); return sb.toString(); } public static int[] getBit(byte by){ /*StringBuffer sb = new StringBuffer(); sb.append((by>>7)&0x1) .append((by>>6)&0x1) .append((by>>5)&0x1) .append((by>>4)&0x1) .append((by>>3)&0x1) .append((by>>2)&0x1) .append((by>>1)&0x1) .append((by>>0)&0x1);*/ int[] bits= { (by>>7)&0x1, (by>>6)&0x1, (by>>5)&0x1, (by>>4)&0x1, (by>>3)&0x1, (by>>2)&0x1, (by>>1)&0x1, (by>>0)&0x1 }; return bits; } }
2:在Main方法中测试CRC8算法,代码如下:
public class TestDemo { public static void main(String[] args) { System.out.println(crc8("55AA021B00")); //输出结果为:75 } public static String crc8(String hexCommond) { int crc8 = FindCRC(HexUtil.hexStringToBytes(hexCommond)); return HexUtil.numToHex8(crc8).toUpperCase(); } //获取CRC校验字节 public static int FindCRC(byte[] data) { int CRC = 0; int genPoly = 0x8C; for (int i = 0; i < data.length; i++) { CRC ^= data[i]; CRC &= 0xff;//保证CRC余码输出为1字节。 for (int j = 0; j < 8; j++) { if ((CRC & 0x01) != 0) { CRC = (CRC >> 1) ^ genPoly; CRC &= 0xff;//保证CRC余码输出为1字节。 } else { CRC >>= 1; CRC &= 0xff;//保证CRC余码输出为1字节。 } } } CRC &= 0xff;//保证CRC余码输出为1字节。 return CRC; } }
上述的CRC8算法根据计算出来的帧头,长度,功能码,数据体计算出来的结果为:75,与在线的crc(循环冗余校验算法)结果一致,如图所示: