Exemple de code de vérification ModbusCRC16

Auteur : Herman Ye @Galbot @Auromix
Environnement de test : Ubuntu20.04
Date de mise à jour : 2023/08/30
Note 1 : @Auromix est une organisation open source pour les passionnés de robotique.
Note 2 : Cet article a été testé et confirmé comme étant valide à la date de mise à jour.

À des fins d'apprentissage et de communication, l'auteur
donne les quatre fonctions suivantes couramment utilisées pour la vérification ModbusCRC16 et des exemples de codes complets :

1. Calculer le CRC

Remarque : Les bits hauts et bas sont échangés ici à la fin. Le code peut être supprimé et l'ordre des bits hauts et bas échangés selon les besoins.

/**
 * @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.Ajouter le chiffre de contrôle CRC

Remarque : les bits hauts et bas sont échangés ici, et le code peut être supprimé pour échanger l'ordre des bits haut et bas en fonction des besoins.

/**
 * @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. Supprimez le chiffre de contrôle 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. Comparez les chiffres de contrôle 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. Exemple de code complet

#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;
}

Je suppose que tu aimes

Origine blog.csdn.net/m0_56661101/article/details/132584241
conseillé
Classement