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;
}
相关推荐
倒头就睡的小比特4 天前
算法竞赛C++常用的STL
c++·算法
weilx12344 天前
C++笔记-文件IO-<fcntl.h>
c++
未济4 天前
linux 配置环境变量
linux
傲世仙尊4 天前
目录即文件-Ext文件系统收尾篇
linux·c语言
Smileyqp沛沛4 天前
前端?C++ ?较大差异基础罗列
c++·基础·前端转c++
C语言小火车4 天前
C/C++ 为什么需要编译器?
开发语言·c++
_艾伦 耶格尔.4 天前
进程间通信
linux
旖旎夜光4 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
Liuqy-054 天前
Linux IO编程——静态库、动态库
linux
吞下星星的少年·-·4 天前
C++ 萌新语法入门篇
c++·算法比赛