求CRC16 Modbus RTU计算C代码示例,解惑CRC计算偏差问题
CRC16 Modbus RTU C代码实现
核心计算函数
Modbus RTU的CRC16遵循以下规则:
- 初始值:
0xFFFF - 多项式:
0xA001(标准多项式0x8005的反向形式) - 计算时逐字节处理,最终结果需按低字节在前、高字节在后的顺序加入数据包
以下是可直接复用的C代码:
#include <stdint.h> #include <stdio.h> // 计算CRC16 Modbus值,返回16位CRC结果 uint16_t crc16_modbus(const uint8_t *data, uint16_t length) { uint16_t crc = 0xFFFF; for (uint16_t i = 0; i < length; i++) { crc ^= data[i]; // 与当前字节异或 for (uint8_t j = 0; j < 8; j++) { // 最低位为1时,左移后异或多项式;否则仅左移 if (crc & 0x0001) { crc = (crc >> 1) ^ 0xA001; } else { crc >>= 1; } } } return crc; } // 验证示例数据的主函数 int main() { // 待发送数据:01 04 30 00 00 01 uint8_t tx_data[] = {0x01, 0x04, 0x30, 0x00, 0x00, 0x01}; uint16_t crc_result = crc16_modbus(tx_data, sizeof(tx_data)); // 输出结果:正确CRC值为0xCA3E,传输时需拆分为0x3E(低字节)、0xCA(高字节) printf("计算得到的CRC值:0x%04X\n", crc_result); printf("传输时的CRC字节顺序:0x%02X 0x%02X\n", crc_result & 0xFF, crc_result >> 8); return 0; }
关键注意事项(解决计算不符问题)
- 多项式选择:必须使用反向多项式
0xA001,而非标准的0x8005,这是多数新手计算错误的核心原因 - 字节顺序:计算得到的16位CRC值(示例中为
0xCA3E),在Modbus RTU数据包中需按低字节在前的顺序发送,即先0x3E,再0xCA,与你给出的正确CRC值一致 - 初始值:必须从
0xFFFF开始计算,不能使用0或其他初始值
适配你的驱动数据包格式
你的驱动数据包格式为:
/* ID ADDRESS 2 bytes
- FUNCTION CODE 2 bytes
- START ADDRESS 2 bytes
- N BYTE READ 2 bytes
- CRC 2 bytes
*/
假设你已组装好前8字节的有效数据,可按以下方式添加CRC:
// 示例:组装完整数据包 uint8_t full_packet[10]; // 填充前8字节(ID、功能码、起始地址、读取字节数) full_packet[0] = 0x00; full_packet[1] = 0x01; // ID ADDRESS(2字节) full_packet[2] = 0x00; full_packet[3] = 0x04; // FUNCTION CODE(2字节) full_packet[4] = 0x00; full_packet[5] = 0x30; // START ADDRESS(2字节) full_packet[6] = 0x00; full_packet[7] = 0x01; // N BYTE READ(2字节) // 计算CRC并添加到末尾 uint16_t crc = crc16_modbus(full_packet, 8); full_packet[8] = crc & 0xFF; // CRC低字节 full_packet[9] = crc >> 8; // CRC高字节
内容的提问来源于stack exchange,提问作者Soufiane
相关产品推荐
相关产品推荐

