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;
}
相关推荐
AGI学习社12 分钟前
2024中国排名前十AI大模型进展、应用案例与发展趋势
linux·服务器·人工智能·华为·llama
半盏茶香23 分钟前
扬帆数据结构算法之雅舟航程,漫步C++幽谷——LeetCode刷题之移除链表元素、反转链表、找中间节点、合并有序链表、链表的回文结构
数据结构·c++·算法
哎呦,帅小伙哦31 分钟前
Effective C++ 规则41:了解隐式接口和编译期多态
c++·effective c++
H.2033 分钟前
centos7执行yum操作时报错Could not retrieve mirrorlist http://mirrorlist.centos.org解决
linux·centos
DARLING Zero two♡1 小时前
【初阶数据结构】逆流的回环链桥:双链表
c语言·数据结构·c++·链表·双链表
9毫米的幻想1 小时前
【Linux系统】—— 编译器 gcc/g++ 的使用
linux·运维·服务器·c语言·c++
helloliyh1 小时前
Windows和Linux系统安装东方通
linux·运维·windows
Cando学算法1 小时前
Codeforces Round 1000 (Div. 2)(前三题)
数据结构·c++·算法
字节高级特工1 小时前
【优选算法】5----有效三角形个数
c++·算法
荣--2 小时前
HiJobQueue:一个简单的线程安全任务队列
c++·编码