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;
}
相关推荐
GSDjisidi3 分钟前
日本IT-SIER/SES的区别详情、契约形态等
java·大数据·c语言·c++·php
love6a69 分钟前
从零开始学习网络安全渗透测试之Linux基础篇——(六)Linux网络及防火墙配置
linux·学习·web安全
YoungMLet9 分钟前
【QT】多元素控件
c语言·开发语言·c++·qt·ui
xjt_090120 分钟前
在 Windows PowerShell 中模拟 Unix/Linux 的 touch 命令
linux·服务器·unix
paidaxing_s1 小时前
【FFMPEG基础(一)】解码源码
linux·c++·ffmpeg
曼巴UE51 小时前
UE C++ 多镜头设置缩放 平移
开发语言·c++
悄悄敲敲敲1 小时前
栈的实现详解
c语言·开发语言·数据结构·c++·算法·链表·线性回归
danaaaa1 小时前
算法力扣刷题总结篇 ——【四】
数据结构·c++·算法·leetcode·职场和发展
安於宿命2 小时前
0/1背包问题总结
c语言·c++·算法·leetcode·动态规划
tutu_3212 小时前
ubuntu rc.local开机自启动
c++