ModbusCRC16校验 示例代码

作者: 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;
}
相关推荐
用户686916134903 分钟前
1999年NOIP普及组旅行家的预算(洛谷P1016):贪心算法实战指南
c++
-XWB-12 分钟前
【安全漏洞】网络守门员:深入理解与应用iptables,守护Linux服务器安全
linux·服务器·网络
程序员编程指南39 分钟前
Qt 与 WebService 交互开发
c语言·开发语言·c++·qt·交互
溟洵1 小时前
Qt 窗口 工具栏QToolBar、状态栏StatusBar
开发语言·前端·数据库·c++·后端·qt
kura_tsuki1 小时前
[Linux入门] Linux 远程访问及控制全解析:从入门到实战
linux·服务器·安全
lunz_fly19921 小时前
统信 UOS 安装 svn 指南
linux
铭哥的编程日记1 小时前
《C++ list 完全指南:list的模拟实现》
c++
Antonio9151 小时前
【Redis】Linux 配置Redis
linux·数据库·redis
程序员编程指南1 小时前
Qt 远程过程调用(RPC)实现方案
c语言·c++·qt·rpc·系统架构
Rover.x2 小时前
内存泄漏问题排查
java·linux·服务器·缓存