该 pdf 文件中包含 CRC 的面向位实现的描述,但它可能需要进行一些清理:
1. Load a 16–bit register with FFFF hex (all 1’s). Call this the CRC register.
2. Exclusive OR the first 8–bit byte of the message with the low–order byte
of the 16–bit CRC register, putting the result in the CRC register.
3. Save the LSB for step 4. Shift the CRC register one bit to the right
(toward the LSB), zero–filling the MSB.
4. (If the saved LSB is 0): Continue to step 5.
(If the saved LSB is 1): Exclusive OR the CRC register with the polynomial
value 0xA001 (1010 0000 0000 0001).
5. Repeat Steps 3 and 4 until 8 shifts have been performed.
When this is done, a complete 8–bit byte will have been processed.
6. Repeat Steps 2 through 5 for the next 8–bit byte of the message.
Continue doing this until all bytes have been processed.
7. The final content of the CRC register is the CRC value.
8. When the CRC is placed into the message, store the low order byte first, and the
high order byte next. (msg ... , crclo, crchi).
https://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf
请注意,在使用表格的示例代码中,CRC 的字节被交换,所以所谓的“低字节”实际上是“高字节”,反之亦然。这样做是为了允许 CRC 在大端处理器上作为 16 位值存储在消息中。在小端处理器上不需要交换字节,例如 PC 上的 X86,因为小端存储将交换字节(存储低字节,高字节)。
生成表格的示例代码:
#include <stdio.h>
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
uint8_t crclo[256];
uint8_t crchi[256];
void gentbls(void)
{
uint16_t crc;
uint16_t b;
uint16_t c;
uint16_t i;
for(c = 0; c < 0x100; c++){
crc = c;
for(i = 0; i < 8; i++){
b = crc & 1;
crc >>= 1;
if(b != 0) crc ^= 0xa001;
}
crchi[c] = crc & 0xff;
crclo[c] = crc >> 8;
}
}
int main()
{
int i, j;
gentbls();
for(j = 0; j < 17; j++){
for(i = 0; i < 15; i++)
printf("%02x ", crclo[j*15+i]);
printf("\n");
}
printf("%02x\n\n", crclo[255]);
for(j = 0; j < 17; j++){
for(i = 0; i < 15; i++)
printf("%02x ", crchi[j*15+i]);
printf("\n");
}
printf("%02x\n", crchi[255]);
return 0;
}
输出:
00 c0 c1 01 c3 03 02 c2 c6 06 07 c7 05 c5 c4
04 cc 0c 0d cd 0f cf ce 0e 0a ca cb 0b c9 09
08 c8 d8 18 19 d9 1b db da 1a 1e de df 1f dd
1d 1c dc 14 d4 d5 15 d7 17 16 d6 d2 12 13 d3
11 d1 d0 10 f0 30 31 f1 33 f3 f2 32 36 f6 f7
37 f5 35 34 f4 3c fc fd 3d ff 3f 3e fe fa 3a
3b fb 39 f9 f8 38 28 e8 e9 29 eb 2b 2a ea ee
2e 2f ef 2d ed ec 2c e4 24 25 e5 27 e7 e6 26
22 e2 e3 23 e1 21 20 e0 a0 60 61 a1 63 a3 a2
62 66 a6 a7 67 a5 65 64 a4 6c ac ad 6d af 6f
6e ae aa 6a 6b ab 69 a9 a8 68 78 b8 b9 79 bb
7b 7a ba be 7e 7f bf 7d bd bc 7c b4 74 75 b5
77 b7 b6 76 72 b2 b3 73 b1 71 70 b0 50 90 91
51 93 53 52 92 96 56 57 97 55 95 94 54 9c 5c
5d 9d 5f 9f 9e 5e 5a 9a 9b 5b 99 59 58 98 88
48 49 89 4b 8b 8a 4a 4e 8e 8f 4f 8d 4d 4c 8c
44 84 85 45 87 47 46 86 82 42 43 83 41 81 80
40
00 c1 81 40 01 c0 80 41 01 c0 80 41 00 c1 81
40 01 c0 80 41 00 c1 81 40 00 c1 81 40 01 c0
80 41 01 c0 80 41 00 c1 81 40 00 c1 81 40 01
c0 80 41 00 c1 81 40 01 c0 80 41 01 c0 80 41
00 c1 81 40 01 c0 80 41 00 c1 81 40 00 c1 81
40 01 c0 80 41 00 c1 81 40 01 c0 80 41 01 c0
80 41 00 c1 81 40 00 c1 81 40 01 c0 80 41 01
c0 80 41 00 c1 81 40 01 c0 80 41 00 c1 81 40
00 c1 81 40 01 c0 80 41 01 c0 80 41 00 c1 81
40 00 c1 81 40 01 c0 80 41 00 c1 81 40 01 c0
80 41 01 c0 80 41 00 c1 81 40 00 c1 81 40 01
c0 80 41 01 c0 80 41 00 c1 81 40 01 c0 80 41
00 c1 81 40 00 c1 81 40 01 c0 80 41 00 c1 81
40 01 c0 80 41 01 c0 80 41 00 c1 81 40 01 c0
80 41 00 c1 81 40 00 c1 81 40 01 c0 80 41 01
c0 80 41 00 c1 81 40 00 c1 81 40 01 c0 80 41
00 c1 81 40 01 c0 80 41 01 c0 80 41 00 c1 81
40