前言
最近开发中用RS485
串口命令去控制继电器和风机调速,用到了MUDBUS
指令。通过串口会发送一串’ 01 06 00 01 01 00 D9 9A '这样的命令到继电器,从而达到控制的目的。起初,对这命令感到疑惑,最后经过文档查看及分析,发现不同的位代表了不同含义:设备地址(01)、功能号(06)、数据地址(0001)、数据(0100)、CRC16校验(D99A)。
其中CRC16校验是怎么得出的,由什么的得出的让我感到困惑,文档也没有说明,经过查阅发现CRC16校验是对前面的命令,也就是’ 01 06 00 01 01 00 ‘进行了CRC16校验计算,从而得到所需要的’D9 9A’ ,再进行发送。
CRC简介
CRC即循环冗余校验码(Cyclic Redundancy Check),是数据通信领域中最常用的一种查错校验码。奇偶校验虽然简单,但是漏检率太高,而CRC则要低的多,所以大多数都是使用CRC来校验。CRC只能检错,不能纠错。如果发现错误,可根据双方协议规定要求发送方重新发送。
原理
CRC校验,本质上是模2除法求余。将发送信息M(x)当做被除数,发送方和接收方共同约定一个除数G(x),然后求余R(x),该余数R(x)即为CRC值。原始信息中某位发生变化,则CRC值发生翻天覆地的变化,因此检错比较高效。
过程
发送方根据发送报文,计算出CRC值。将原始信息和该CRC值一起发送给接收方。接收方根据原始信息,按照同样的算法,计算CRC。如果计算的CRC值不正确的话,则表明在数据传输的过程中,原始信息(或者CRC值)发生错误。
CRC 计算
方法1:
/**
* 计算CRC16校验码
*
* @param bytes 需要计算的字节数组
*/
public static String getCRC(byte[] bytes) {
int CRC = 0x0000ffff;
int POLYNOMIAL = 0x0000a001;
int i, j;
for (i = 0; i < bytes.length; i++) {
CRC ^= ((int) bytes[i] & 0x000000ff);
for (j = 0; j < 8; j++) {
if ((CRC & 0x00000001) != 0) {
CRC >>= 1;
CRC ^= POLYNOMIAL;
} else {
CRC >>= 1;
}
}
}
return Integer.toHexString(CRC);
}
方法2:
/**
* 查表法计算CRC16校验
*
* @param data 需要计算的字节数组
*/
public static String getTableCRC(byte[] data) {
byte[] crc16_h = {
(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte)