作者: Herman Ye @Galbot @Auromix
测试环境: Ubuntu20.04
更新日期: 2023/08/30
注~1~: @Auromix 是一个机器人爱好者开源组织。
注~2~: 本文在更新日期经过测试,确认有效。
笔者出于学习交流目的,
给出以下ModbusCRC16校验常用的四种函数以及完整示例代码:
1.计算CRC
注意: 此处在末尾进行了高低位交换,可根据需求删减代码交换高低位顺序。
cpp
unsigned short calculateModbusCRC16(const vector<uint8_t> &data) {
int length = data.size();
unsigned short CRC = 0xFFFF; // initial value
for (int i = 0; i < length; i++) {
CRC = CRC ^ data[i]; // XOR byte into least sig. byte of crc
for (int j = 0; j < 8; j++) {
if (CRC & 1) {
CRC >>= 1;
CRC ^= 0xA001;
} else {
CRC >>= 1;
}
}
}
unsigned short swappedCRC = ((CRC >> 8) & 0xFF) | ((CRC & 0xFF) << 8);
return swappedCRC;
}
2.添加CRC校验位
注意: 此处进行了高低位交换,可根据需求删减代码交换高低位顺序。
cpp
void addModbusCRC16(vector<uint8_t> &data) {
unsigned short crc = calculateModbusCRC16(data);
// Append CRC bytes to the data vector
data.push_back((crc >> 8) & 0xFF); // MSB
data.push_back(crc & 0xFF); // LSB
}
3.删除CRC校验位
cpp
void removeModbusCRC16(vector<uint8_t> &dataWithCRC) {
int length = dataWithCRC.size();
// Error check
if (length < 2) {
cerr << "Invalid data length" << endl;
return;
}
// Delete CRC at the end
dataWithCRC.resize(length - 2);
}
4.比较CRC校验位
cpp
bool compareModbusCRC16(const vector<uint8_t> &dataWithCRC) {
int length = dataWithCRC.size();
// Error check
if (length < 2) {
cerr << "Invalid data length" << endl;
return false;
}
// Get data without CRC
vector<uint8_t> dataWithoutCRC(dataWithCRC.begin(), dataWithCRC.end() - 2);
// Calculate
unsigned short calculatedCRC = calculateModbusCRC16(dataWithoutCRC);
// Get original CRC
unsigned short originalCRC = (dataWithCRC[length - 2] << 8) | dataWithCRC[length - 1];
return originalCRC == calculatedCRC;
}
5.完整示例代码
cpp
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;
unsigned short calculateModbusCRC16(const vector<uint8_t> &data) {
int length = data.size();
unsigned short CRC = 0xFFFF; // initial value
for (int i = 0; i < length; i++) {
CRC = CRC ^ data[i]; // XOR byte into least sig. byte of crc
for (int j = 0; j < 8; j++) {
if (CRC & 1) {
CRC >>= 1;
CRC ^= 0xA001;
} else {
CRC >>= 1;
}
}
}
unsigned short swappedCRC = ((CRC >> 8) & 0xFF) | ((CRC & 0xFF) << 8);
return swappedCRC;
}
void addModbusCRC16(vector<uint8_t> &data) {
unsigned short crc = calculateModbusCRC16(data);
// Append CRC bytes to the data vector
data.push_back((crc >> 8) & 0xFF); // MSB
data.push_back(crc & 0xFF); // LSB
}
void removeModbusCRC16(vector<uint8_t> &dataWithCRC) {
int length = dataWithCRC.size();
// Error check
if (length < 2) {
cerr << "Invalid data length" << endl;
return;
}
// Delete CRC at the end
dataWithCRC.resize(length - 2);
}
bool compareModbusCRC16(const vector<uint8_t> &dataWithCRC) {
int length = dataWithCRC.size();
// Error check
if (length < 2) {
cerr << "Invalid data length" << endl;
return false;
}
// Get data without CRC
vector<uint8_t> dataWithoutCRC(dataWithCRC.begin(), dataWithCRC.end() - 2);
// Calculate
unsigned short calculatedCRC = calculateModbusCRC16(dataWithoutCRC);
// Get original CRC
unsigned short originalCRC = (dataWithCRC[length - 2] << 8) | dataWithCRC[length - 1];
// Log
cout<< "ModbusCRC16 original: "<<hex<< originalCRC<< endl;
cout<< "ModbusCRC16 calculated: "<<hex<< calculatedCRC<< endl;
return originalCRC == calculatedCRC;
}
int main() {
// Example data 1
vector<uint8_t> deviceData1 = {
0x01, 0x10, 0x00, 0x02, 0x00, 0x06, 0x0C, 0x41, 0x20,
0x00, 0x00, 0x42, 0xC8, 0x00, 0x00, 0x42, 0x48, 0x00, 0x00,0x84, 0xC1
}; // Example CRC: 0x84, 0xC1
// Print original data
cout << "Original data 1: ";
for (uint8_t byte : deviceData1) {
cout << hex << uppercase << setw(2) << setfill('0') << (int)byte << " ";
}
cout << endl;
bool comparedResult=compareModbusCRC16(deviceData1);
if (comparedResult)
cout<<"Compared result: "<<"TRUE"<<endl;
else
cout<<"Compared result: "<<"FALSE"<<endl;
// Example data 2
cout<<endl;
vector<uint8_t> deviceData2 = {
0x01, 0x06, 0x00, 0x00, 0x01, 0x02, 0x02
};// Example CRC: 0xDA, 0xC7
cout << "Original data 2: ";
for (uint8_t byte : deviceData2) {
cout << hex << uppercase << setw(2) << setfill('0') << (int)byte << " ";
}
cout << endl;
// Add CRC and print modified data
addModbusCRC16(deviceData2);
cout << "Add CRC to original data 2: ";
for (uint8_t byte : deviceData2) {
cout << hex << uppercase << setw(2) << setfill('0') << (int)byte << " ";
}
cout << endl;
// Remove CRC from data
removeModbusCRC16(deviceData2);
cout << "Remove CRC from modified data 2: ";
for (uint8_t byte : deviceData2) {
cout << hex << uppercase << setw(2) << setfill('0') << (int)byte << " ";
}
cout << endl;
return 0;
}