CRC即循环冗余校验码(Cyclic Redundancy Check 1 ):是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。
CRC校验的原理即通信双方规定一个二进制除数,传输帧必须能够被其整除,否则说明出错。

Had Length Address Command CRC1 Data CRC2
0xaa 0x55 1 byte address CMD 1 byte n bytes 1 byte
  • Head: 2个字节,默认0xaa, 0x55,代表帧头,是大端模块式。0x55, 0xaa,代表小端模式。不同模式的数据在系统内的排列方式。例如:数据为0x1234,在大端模式时数据排列方式为0x12,0x34,MSB字节在低地址。小端模式时数据排列方式为0x34,0x12,MSB字节在高地址。大端模式应答帧的帧头为0xa5, 0x5a,小端模式的应答帧头为:0x5a, 0xa5。
  • Length: 1个字节,是此通讯帧的长度。范围6-255,Length 为所有字节的长度,包括HEAD,Length,Command,CRC1,Data,CRC2。
  • Address:1个字节,此为各个从机模块的地址。
  • Command:1个字节,是主/从机通讯的命令,即主机要求从机进行操作的操作码。命令范围是0X01~0x7f。
  • CRC1: 1个字节,是head, length, command这4个字节的CRC校验码。因为数据的长度异常重要,一旦此数据出错误,程序处理不当,将会带来灾难性的后果。所以单独对长度和操作码做了一次CRC校验。如果是命令帧,该校验字段就会与后面的CRC2合并。
  • Data:N个字节,是通讯的数据包,根据协议版本及操作码的不同,数据内容有所不同。
  • CRC2: 1个字节,是所有字段的CRC校验码。

CRC8的校验方式,具体如下表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const uint8_t nCrc8Tab[] =
{
0x00,0x5e,0xbc,0xe2,0x61,0x3f,0xdd,0x83,0xc2,0x9c,0x7e,0x20,0xa3,0xfd,0x1f,0x41,
0x9d,0xc3,0x21,0x7f,0xfc,0xa2,0x40,0x1e,0x5f,0x01,0xe3,0xbd,0x3e,0x60,0x82,0xdc,
0x23,0x7d,0x9f,0xc1,0x42,0x1c,0xfe,0xa0,0xe1,0xbf,0x5d,0x03,0x80,0xde,0x3c,0x62,
0xbe,0xe0,0x02,0x5c,0xdf,0x81,0x63,0x3d,0x7c,0x22,0xc0,0x9e,0x1d,0x43,0xa1,0xff,
0x46,0x18,0xfa,0xa4,0x27,0x79,0x9b,0xc5,0x84,0xda,0x38,0x66,0xe5,0xbb,0x59,0x07,
0xdb,0x85,0x67,0x39,0xba,0xe4,0x06,0x58,0x19,0x47,0xa5,0xfb,0x78,0x26,0xc4,0x9a,
0x65,0x3b,0xd9,0x87,0x04,0x5a,0xb8,0xe6,0xa7,0xf9,0x1b,0x45,0xc6,0x98,0x7a,0x24,
0xf8,0xa6,0x44,0x1a,0x99,0xc7,0x25,0x7b,0x3a,0x64,0x86,0xd8,0x5b,0x05,0xe7,0xb9,
0x8c,0xd2,0x30,0x6e,0xed,0xb3,0x51,0x0f,0x4e,0x10,0xf2,0xac,0x2f,0x71,0x93,0xcd,
0x11,0x4f,0xad,0xf3,0x70,0x2e,0xcc,0x92,0xd3,0x8d,0x6f,0x31,0xb2,0xec,0x0e,0x50,
0xaf,0xf1,0x13,0x4d,0xce,0x90,0x72,0x2c,0x6d,0x33,0xd1,0x8f,0x0c,0x52,0xb0,0xee,
0x32,0x6c,0x8e,0xd0,0x53,0x0d,0xef,0xb1,0xf0,0xae,0x4c,0x12,0x91,0xcf,0x2d,0x73,
0xca,0x94,0x76,0x28,0xab,0xf5,0x17,0x49,0x08,0x56,0xb4,0xea,0x69,0x37,0xd5,0x8b,
0x57,0x09,0xeb,0xb5,0x36,0x68,0x8a,0xd4,0x95,0xcb,0x29,0x77,0xf4,0xaa,0x48,0x16,
0xe9,0xb7,0x55,0x0b,0x88,0xd6,0x34,0x6a,0x2b,0x75,0x97,0xc9,0x4a,0x14,0xf6,0xa8,
0x74,0x2a,0xc8,0x96,0x15,0x4b,0xa9,0xf7,0xb6,0xe8,0x0a,0x54,0xd7,0x89,0x6b,0x35,
};

CRC8计算函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
uint8_t  CalCrc8(uint8_t *pBuf,uint8_t nBufLen)
{
uint8_t nCrcVal = 0x00;
uint8_t i;
uint8_t nTabIdx;

if (pBuf && (nBufLen > 0))
{
for (i = 0; i < nBufLen; i ++)
{
nTabIdx = (*(pBuf+i)) ^ nCrcVal;
nCrcVal = nCrc8Tab[nTabIdx];
}
}

return nCrcVal;
}

附上java版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package bp.comm.project.util;

/**
* CRC8相关计算
* CRC-8 X8+X5+X4+1 100110001
* encode: utf-8
*/
public class CRC8 {
static byte[] crc8_tab = {
(byte) 0x00, (byte) 0x5e, (byte) 0xbc, (byte) 0xe2, (byte) 0x61, (byte) 0x3f, (byte) 0xdd,
(byte) 0x83, (byte) 0xc2, (byte) 0x9c, (byte) 0x7e, (byte) 0x20, (byte) 0xa3, (byte) 0xfd,
(byte) 0x1f, (byte) 0x41, (byte) 0x9d, (byte) 0xc3, (byte) 0x21, (byte) 0x7f, (byte) 0xfc,
(byte) 0xa2, (byte) 0x40, (byte) 0x1e, (byte) 0x5f, (byte) 0x01, (byte) 0xe3, (byte) 0xbd,
(byte) 0x3e, (byte) 0x60, (byte) 0x82, (byte) 0xdc, (byte) 0x23, (byte) 0x7d, (byte) 0x9f,
(byte) 0xc1, (byte) 0x42, (byte) 0x1c, (byte) 0xfe, (byte) 0xa0, (byte) 0xe1, (byte) 0xbf,
(byte) 0x5d, (byte) 0x03, (byte) 0x80, (byte) 0xde, (byte) 0x3c, (byte) 0x62, (byte) 0xbe,
(byte) 0xe0, (byte) 0x02, (byte) 0x5c, (byte) 0xdf, (byte) 0x81, (byte) 0x63, (byte) 0x3d,
(byte) 0x7c, (byte) 0x22, (byte) 0xc0, (byte) 0x9e, (byte) 0x1d, (byte) 0x43, (byte) 0xa1,
(byte) 0xff, (byte) 0x46, (byte) 0x18, (byte) 0xfa, (byte) 0xa4, (byte) 0x27, (byte) 0x79,
(byte) 0x9b, (byte) 0xc5, (byte) 0x84, (byte) 0xda, (byte) 0x38, (byte) 0x66, (byte) 0xe5,
(byte) 0xbb, (byte) 0x59, (byte) 0x07, (byte) 0xdb, (byte) 0x85, (byte) 0x67, (byte) 0x39,
(byte) 0xba, (byte) 0xe4, (byte) 0x06, (byte) 0x58, (byte) 0x19, (byte) 0x47, (byte) 0xa5,
(byte) 0xfb, (byte) 0x78, (byte) 0x26, (byte) 0xc4, (byte) 0x9a, (byte) 0x65, (byte) 0x3b,
(byte) 0xd9, (byte) 0x87, (byte) 0x04, (byte) 0x5a, (byte) 0xb8, (byte) 0xe6, (byte) 0xa7,
(byte) 0xf9, (byte) 0x1b, (byte) 0x45, (byte) 0xc6, (byte) 0x98, (byte) 0x7a, (byte) 0x24,
(byte) 0xf8, (byte) 0xa6, (byte) 0x44, (byte) 0x1a, (byte) 0x99, (byte) 0xc7, (byte) 0x25,
(byte) 0x7b, (byte) 0x3a, (byte) 0x64, (byte) 0x86, (byte) 0xd8, (byte) 0x5b, (byte) 0x05,
(byte) 0xe7, (byte) 0xb9, (byte) 0x8c, (byte) 0xd2, (byte) 0x30, (byte) 0x6e, (byte) 0xed,
(byte) 0xb3, (byte) 0x51, (byte) 0x0f, (byte) 0x4e, (byte) 0x10, (byte) 0xf2, (byte) 0xac,
(byte) 0x2f, (byte) 0x71, (byte) 0x93, (byte) 0xcd, (byte) 0x11, (byte) 0x4f, (byte) 0xad,
(byte) 0xf3, (byte) 0x70, (byte) 0x2e, (byte) 0xcc, (byte) 0x92, (byte) 0xd3, (byte) 0x8d,
(byte) 0x6f, (byte) 0x31, (byte) 0xb2, (byte) 0xec, (byte) 0x0e, (byte) 0x50, (byte) 0xaf,
(byte) 0xf1, (byte) 0x13, (byte) 0x4d, (byte) 0xce, (byte) 0x90, (byte) 0x72, (byte) 0x2c,
(byte) 0x6d, (byte) 0x33, (byte) 0xd1, (byte) 0x8f, (byte) 0x0c, (byte) 0x52, (byte) 0xb0,
(byte) 0xee, (byte) 0x32, (byte) 0x6c, (byte) 0x8e, (byte) 0xd0, (byte) 0x53, (byte) 0x0d,
(byte) 0xef, (byte) 0xb1, (byte) 0xf0, (byte) 0xae, (byte) 0x4c, (byte) 0x12, (byte) 0x91,
(byte) 0xcf, (byte) 0x2d, (byte) 0x73, (byte) 0xca, (byte) 0x94, (byte) 0x76, (byte) 0x28,
(byte) 0xab, (byte) 0xf5, (byte) 0x17, (byte) 0x49, (byte) 0x08, (byte) 0x56, (byte) 0xb4,
(byte) 0xea, (byte) 0x69, (byte) 0x37, (byte) 0xd5, (byte) 0x8b, (byte) 0x57, (byte) 0x09,
(byte) 0xeb, (byte) 0xb5, (byte) 0x36, (byte) 0x68, (byte) 0x8a, (byte) 0xd4, (byte) 0x95,
(byte) 0xcb, (byte) 0x29, (byte) 0x77, (byte) 0xf4, (byte) 0xaa, (byte) 0x48, (byte) 0x16,
(byte) 0xe9, (byte) 0xb7, (byte) 0x55, (byte) 0x0b, (byte) 0x88, (byte) 0xd6, (byte) 0x34,
(byte) 0x6a, (byte) 0x2b, (byte) 0x75, (byte) 0x97, (byte) 0xc9, (byte) 0x4a, (byte) 0x14,
(byte) 0xf6, (byte) 0xa8, (byte) 0x74, (byte) 0x2a, (byte) 0xc8, (byte) 0x96, (byte) 0x15,
(byte) 0x4b, (byte) 0xa9, (byte) 0xf7, (byte) 0xb6, (byte) 0xe8, (byte) 0x0a, (byte) 0x54,
(byte) 0xd7, (byte) 0x89, (byte) 0x6b, (byte) 0x35,
};

/**
* 计算数组的CRC8校验值
*
* @param data 需要计算的数组
* @return CRC8校验值
*/
public static byte calcCrc(byte[] data) {
return calcCrc8(data, 0, data.length, (byte) 0);
}

/**
* 计算CRC8校验值
*
* @param data 数据
* @param offset 起始位置
* @param len 长度
* @return 校验值
*/
public static byte calcCrc8(byte[] data, int offset, int len) {
return calcCrc8(data, offset, len, (byte) 0);
}

/**
* 计算CRC8校验值
*
* @param data 数据
* @param offset 起始位置
* @param len 长度
* @param preval 之前的校验值
* @return 校验值
*/
public static byte calcCrc8(byte[] data, int offset, int len, byte preval) {
byte ret = preval;
for (int i = offset; i < (offset + len); ++i) {
ret = crc8_tab[(0x00ff & (ret ^ data[i]))];
}
return ret;
}
}