CRC校验函数

CRC16

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
#include <stdint.h>
#include <stdbool.h>

/**
* @brief 通用CRC16函数,支持自定义多项式、输入反转、输出反转和结果异或参数
*
* @param data 数据
* @param length 数据长度
* @param polynomial 多项式的值
* @param input_reflect 输入是否反转
* @param output_reflect 输出是否反转
* @param final_xor 输出结果异或参数
* @return uint16_t 返回计算值
*/
uint16_t crc16_generic(const uint8_t *data, size_t length,
uint16_t polynomial,
bool input_reflect,
bool output_reflect,
uint16_t final_xor) {
uint16_t crc = 0x0000; // 初始值

for (size_t i = 0; i < length; ++i) {
uint8_t byte = data[i];

// 输入反转处理
if (input_reflect) {
byte = (byte & 0x55) << 1 | (byte & 0xAA) >> 1;
byte = (byte & 0x33) << 2 | (byte & 0xCC) >> 2;
byte = (byte & 0x0F) << 4 | (byte & 0xF0) >> 4;
}

crc ^= (uint16_t)byte << 8;

for (int j = 0; j < 8; ++j) {
if (crc & 0x8000) {
crc = (crc << 1) ^ polynomial;
} else {
crc <<= 1;
}
}
}

// 输出反转处理
if (output_reflect) {
crc = (crc & 0x5555) << 1 | (crc & 0xAAAA) >> 1;
crc = (crc & 0x3333) << 2 | (crc & 0xCCCC) >> 2;
crc = (crc & 0x0F0F) << 4 | (crc & 0xF0F0) >> 4;
crc = (crc & 0x00FF) << 8 | (crc & 0xFF00) >> 8;
}

// 最终异或处理
return crc ^ final_xor;
}
  1. 多项式‌(Poly):如 0x8005(IBM/USB/MODBUS)或 0x1021(CCITT/XMODEM)34;
  2. 初始值‌(Init):如 0x0000(IBM)、0xFFFF(MODBUS/USB)34;
  3. 输入反转‌(RefIn):数据字节位序是否反转(true/false)14;
  4. 输出反转‌(RefOut):最终 CRC 寄存器值是否反转(true/false)14;
  5. 结果异或值‌(XorOut):CRC 结果是否异或固定值(如 0x00000xFFFF

常见变种参数配置示例:

变种类型 多项式 初始值 输入反转 输出反转 结果异或值
CRC16/IBM 0x8005 0x0000 true true 0x0000
CRC16/MODBUS 0x8005 0xFFFF true true 0x0000
CRC16/USB 0x8005 0xFFFF true true 0xFFFF
CRC16/CCITT 0x1021 0x0000 true true 0x0000
CRC16/XMODEM 0x1021 0x0000 false false 0x0000

CRC32

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
#include <stdint.h>
#include <stdbool.h>

/**
* @brief 生成CRC32查找表(支持多项式反转)
*
* @param table 生成的数据表
* @param polynomial 多项式
* @param reflect 是否反转
*/
static void generate_crc32_table(uint32_t *table, uint32_t polynomial, bool reflect) {
for (uint32_t i = 0; i < 256; i++) {
uint32_t crc = reflect ? i : (i << 24);
for (int j = 0; j < 8; j++) {
if (reflect) {
crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
} else {
crc = (crc << 1) ^ ((crc & 0x80000000) ? polynomial : 0);
}
}
table[i] = crc;
}
}

/**
* @brief crc32通用算法
*
* @param data 数据
* @param length 数据长度
* @param polynomial 多项式
* @param initial 初始化的值
* @param input_reflect 输入是否反转
* @param output_reflect 输出是否反转
* @param final_xor 结果异或值
* @return uint32_t 返回生成的结果
*/
uint32_t crc32_generic(const uint8_t *data, size_t length,
uint32_t polynomial,
uint32_t initial,
bool input_reflect,
bool output_reflect,
uint32_t final_xor) {
static uint32_t table[256];
static uint32_t last_poly = 0;
static bool last_reflect = false;

// 多项式或反转模式变化时重新生成表
if (polynomial != last_poly || input_reflect != last_reflect) {
generate_crc32_table(table, polynomial, input_reflect);
last_poly = polynomial;
last_reflect = input_reflect;
}

uint32_t crc = initial;

for (size_t i = 0; i < length; i++) {
uint8_t byte = data[i];
if (input_reflect) {
byte = (byte & 0x55) << 1 | (byte & 0xAA) >> 1;
byte = (byte & 0x33) << 2 | (byte & 0xCC) >> 2;
byte = (byte & 0x0F) << 4 | (byte & 0xF0) >> 4;
}

if (input_reflect) {
crc = (crc >> 8) ^ table[(crc ^ byte) & 0xFF];
} else {
crc = (crc << 8) ^ table[((crc >> 24) ^ byte) & 0xFF];
}
}

if (output_reflect) {
crc = (crc & 0x55555555) << 1 | (crc & 0xAAAAAAAA) >> 1;
crc = (crc & 0x33333333) << 2 | (crc & 0xCCCCCCCC) >> 2;
crc = (crc & 0x0F0F0F0F) << 4 | (crc & 0xF0F0F0F0) >> 4;
crc = (crc & 0x00FF00FF) << 8 | (crc & 0xFF00FF00) >> 8;
crc = (crc << 16) | (crc >> 16);
}

return crc ^ final_xor;
}
CRC32 类型 多项式 初始值 输入反转 输出反转 结果异或值
CRC-32/IEEE 802.3 0xEDB88320 0xFFFFFFFF true true 0xFFFFFFFF
CRC-32/MPEG-2 0x04C11DB7 0xFFFFFFFF false false 0x00000000
CRC-32C 0x1EDC6F41 0xFFFFFFFF true true 0xFFFFFFFF
STM32 硬件 CRC 0x04C11DB7 0xFFFFFFFF 可选 可选 0x00000000

常用CRC8表生成函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* @brief 查CRC8的表
*
* @param table 生成的表
* @param poly 多项式
*/
void generate_crc8_table(uint8_t table[256], uint8_t poly) {
for (int i = 0; i < 256; i++) {
uint8_t crc = i;
for (int j = 0; j < 8; j++) {
if (crc & 0x80) {
crc = (crc << 1) ^ poly;
} else {
crc <<= 1;
}
}
table[i] = crc;
}
}

支持的多项式

常用CRC8标准:

  • CRC-8/ATM (0x07)
  • CRC-8/CCITT (0x07)
  • CRC-8/Dallas (0x31)

常用CRC16表生成函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* @brief 查CRC16的表
*
* @param table 生成的表
* @param poly 多项式
*/
void generate_crc16_table(uint16_t table[256], uint16_t poly) {
for (int i = 0; i < 256; i++) {
uint16_t crc = i << 8;
for (int j = 0; j < 8; j++) {
if (crc & 0x8000) {
crc = (crc << 1) ^ poly;
} else {
crc <<= 1;
}
}
table[i] = crc;
}
}

支持的多项式

常用CRC16标准:

  • CRC-16/IBM (0x8005)
  • CRC-16/CCITT (0x1021)
  • CRC-16/Modbus (0xA001)
  • CRC-16/USB (0x8005)

常用CRC32表生成函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* @brief 查CRC32的表
*
* @param table 生成的表
* @param poly 多项式
*/
void generate_crc32_table(uint32_t table[256], uint32_t poly) {
for (int i = 0; i < 256; i++) {
uint32_t crc = i;
for (int j = 0; j < 8; j++) {
if (crc & 0x1) {
crc = (crc >> 1) ^ poly;
} else {
crc >>= 1;
}
}
table[i] = crc;
}
}

支持的多项式

常用CRC32标准:

  • CRC-32/IEEE 802.3 (0x04C11DB7)
  • CRC-32C (Castagnoli, 0x1EDC6F41)
  • CRC-32K (Koopman, 0x741B8CD7)