最近做一些设备数据对接,有些数据需要crc检验,验证数据完整性,基本概念快忘光了,写个小的实现复习下。
crc16 modbus生成CRC 的过程为:
1. 将一个16位寄存器装入十六进制FFFF (全1). 将之称作CRC 寄存器.2. 将报文的第一个8位字节与16位CRC寄存器的低字节异或,结果置于CRC 寄存器.
3. 将CRC 寄存器右移1位(向LSB 方向),MSB 充零. 提取并检测LSB.
4. (如果LSB 为0): 重复步骤3 (另一次移位).
(如果LSB 为1): 对CRC 寄存器异或多项式值 0xA001 (1010 0000 0000 0001).
5. 重复步骤3 和4,直到完成8 次移位。当做完此操作后,将完成对8位字节的完整操作。
6. 对报文中的下一个字节重复步骤2 到5,继续此操作直至所有报文被处理完毕。
7. CRC 寄存器中的最终内容为CRC 值.
8. 当放置CRC 值于报文时,如下面描述的那样,高低字节必须交换。
public class CRC {
/*寄存器初始值*/
private final int regInitValue;
private int register;
/*CRC 多项式 modbus 多项式0x8005*/
private final int polynomial;
public CRC() {
this(0xffff, 0x8005);
}
public CRC(int register, int polynomial) {
this.register = register;
this.regInitValue = register;
this.polynomial = Integer.reverse(polynomial)>>>Integer.numberOfLeadingZeros(polynomial);
}
private void byteCRC(byte byt) {
register ^= (byt&0xff);
for(int i=0; i<8; i++){
if((register&1)==0){
register >>= 1;
}else{
register = (register >> 1)^polynomial;
}
}
}
public synchronized int crc(byte[] byts) {
if(null==byts||byts.length==0){
return 0;
}
for(int i=0; i<byts.length; i++){
byteCRC(byts[i]);
}
int retn = register;
register = this.regInitValue;
return retn;
}
public static void main(String[] args){
CRC crc = new CRC();
byte[] data = {(byte)0x81, 0x12, 0x17, (byte)0xfe};
System.out.println(Integer.toHexString(crc.crc(data)));
data = new byte[]{2, 7};
System.out.println(Integer.toHexString(crc.crc(data)));
}
}
运行结果可以通过CRC在线生成工具验证: https://www.lammertbies.nl/comm/info/crc-calculation.html