作者: Herman Ye @Galbot @Auromix
测试环境: Ubuntu20.04
更新日期: 2023/08/30
注1: @Auromix 是一个机器人爱好者开源组织。
注2: 本文在更新日期经过测试,确认有效。
笔者出于学习交流目的,
给出以下ModbusCRC16校验常用的四种函数以及完整示例代码:
1.计算CRC
注意: 此处在末尾进行了高低位交换,可根据需求删减代码交换高低位顺序。文章来源:https://www.toymoban.com/news/detail-684488.html
/**
* @brief Calculate the Modbus CRC-16 checksum for a given data vector.
*
* This function calculates the CRC-16 checksum using the Modbus protocol
* polynomial for the provided data vector.
*
* @param data The vector of bytes for which to calculate the CRC-16 checksum.
* @return The calculated CRC-16 checksum value as an unsigned short.
*/
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 the least significant byte of CRC
for (int j = 0; j < 8; j++)
{
if (CRC & 1)
{
CRC >>= 1;
CRC ^= 0xA001;
}
else
{
CRC >>= 1;
}
}
}
// Swap the bytes of the CRC to match Modbus convention
unsigned short swappedCRC = ((CRC >> 8) & 0xFF) | ((CRC & 0xFF) << 8);
return swappedCRC;
}
2.添加CRC校验位
注意: 此处进行了高低位交换,可根据需求删减代码交换高低位顺序。文章来源地址https://www.toymoban.com/news/detail-684488.html
/**
* @brief Add Modbus CRC-16 to a data vector.
*
* This function calculates the Modbus CRC-16 checksum for the provided data vector
* and appends the high and low bytes of the CRC to the end of the data vector.
*
* @param data The data vector to which the CRC will be added.
*/
void addModbusCRC16(vector<uint8_t> &data)
{
// Calculate the CRC-16 checksum
unsigned short crc = calculateModbusCRC16(data);
// Append the high byte of CRC to the data vector
data.push_back((crc >> 8) & 0xFF);
// Append the low byte of CRC to the data vector
data.push_back(crc & 0xFF);
}
3.删除CRC校验位
/**
* @brief Remove Modbus CRC-16 from a vector of data.
*
* This function takes a vector of data with Modbus CRC-16 at the end and removes
* the CRC-16 bytes from the end of the vector, effectively stripping the CRC-16
* checksum from the data.
*
* @param dataWithCRC A reference to the vector containing the data with CRC-16.
*
* @note This function does not perform any CRC-16 validation or calculation. It
* assumes that the last two bytes of the vector represent the CRC-16 checksum
* and removes them regardless of their validity.
*
* @warning It is the responsibility of the caller to ensure that the input vector
* has a length of at least 2, as this function does not perform length checking.
* If the length is less than 2, an error message is printed to the standard error
* stream, and no modifications are made to the input vector.
*/
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校验位
/**
* @brief Compare Modbus CRC-16
*
* This function compares the CRC-16 checksum in the given data with the calculated CRC-16 checksum
* of the data without the CRC bytes. If they match, it indicates that the data is intact and has not
* been corrupted during transmission.
*
* @param dataWithCRC A vector containing the data along with the CRC-16 checksum bytes.
* @return True if the calculated CRC-16 matches the original CRC-16, indicating data integrity.
* False if the data length is invalid or if the CRCs do not match.
*/
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 CRC-16 checksum
unsigned short calculatedCRC = calculateModbusCRC16(dataWithoutCRC);
// Get original CRC-16 checksum from the last two bytes of the data
unsigned short originalCRC = (dataWithCRC[length - 2] << 8) | dataWithCRC[length - 1];
return originalCRC == calculatedCRC;
}
5.完整示例代码
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;
/**
* @brief Calculate the Modbus CRC-16 checksum for a given data vector.
*
* This function calculates the CRC-16 checksum using the Modbus protocol
* polynomial for the provided data vector.
*
* @param data The vector of bytes for which to calculate the CRC-16 checksum.
* @return The calculated CRC-16 checksum value as an unsigned short.
*/
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 the least significant byte of CRC
for (int j = 0; j < 8; j++)
{
if (CRC & 1)
{
CRC >>= 1;
CRC ^= 0xA001;
}
else
{
CRC >>= 1;
}
}
}
// Swap the bytes of the CRC to match Modbus convention
unsigned short swappedCRC = ((CRC >> 8) & 0xFF) | ((CRC & 0xFF) << 8);
return swappedCRC;
}
/**
* @brief Add Modbus CRC-16 to a data vector.
*
* This function calculates the Modbus CRC-16 checksum for the provided data vector
* and appends the high and low bytes of the CRC to the end of the data vector.
*
* @param data The data vector to which the CRC will be added.
*/
void addModbusCRC16(vector<uint8_t> &data)
{
// Calculate the CRC-16 checksum
unsigned short crc = calculateModbusCRC16(data);
// Append the high byte of CRC to the data vector
data.push_back((crc >> 8) & 0xFF);
// Append the low byte of CRC to the data vector
data.push_back(crc & 0xFF);
}
/**
* @brief Remove Modbus CRC-16 from a vector of data.
*
* This function takes a vector of data with Modbus CRC-16 at the end and removes
* the CRC-16 bytes from the end of the vector, effectively stripping the CRC-16
* checksum from the data.
*
* @param dataWithCRC A reference to the vector containing the data with CRC-16.
*
* @note This function does not perform any CRC-16 validation or calculation. It
* assumes that the last two bytes of the vector represent the CRC-16 checksum
* and removes them regardless of their validity.
*
* @warning It is the responsibility of the caller to ensure that the input vector
* has a length of at least 2, as this function does not perform length checking.
* If the length is less than 2, an error message is printed to the standard error
* stream, and no modifications are made to the input vector.
*/
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);
}
/**
* @brief Compare Modbus CRC-16
*
* This function compares the CRC-16 checksum in the given data with the calculated CRC-16 checksum
* of the data without the CRC bytes. If they match, it indicates that the data is intact and has not
* been corrupted during transmission.
*
* @param dataWithCRC A vector containing the data along with the CRC-16 checksum bytes.
* @return True if the calculated CRC-16 matches the original CRC-16, indicating data integrity.
* False if the data length is invalid or if the CRCs do not match.
*/
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 CRC-16 checksum
unsigned short calculatedCRC = calculateModbusCRC16(dataWithoutCRC);
// Get original CRC-16 checksum from the last two bytes of the data
unsigned short originalCRC = (dataWithCRC[length - 2] << 8) | dataWithCRC[length - 1];
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;
}
到了这里,关于ModbusCRC16校验 示例代码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!