You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

ANSI C中十六进制字符串转32字节数组及CRC-16(Maxim)计算结果不一致问题排查

Solution for Hex String to Byte Array Conversion & CRC-16 Maxim Calculation

Let's tackle your two main issues step by step: converting your hex string into a proper 32-byte array, and fixing the CRC calculation to match the online tool results.

1. Convert Hex String to 32-Byte Array

Right now, you're storing each ASCII character of the hex string as a separate byte (64 bytes total). To pack two hex characters into one byte, you need to parse each pair of ASCII characters into their corresponding 8-bit value. Here's an ANSI C function to do this:

// Converts a hex string to a byte array. Returns number of bytes written, or -1 on error.
int hex_str_to_bytes(const char *hex_str, unsigned char *byte_arr, size_t max_len) {
    size_t str_len = strlen(hex_str);
    
    // Hex string must have even length (each byte needs two hex chars)
    if (str_len % 2 != 0) return -1;
    
    size_t byte_count = str_len / 2;
    if (byte_count > max_len) return -1; // Buffer too small
    
    for (size_t i = 0; i < byte_count; i++) {
        // Extract two consecutive hex characters
        char hex_pair[3] = {hex_str[2*i], hex_str[2*i + 1], '\0'};
        // Convert to unsigned char using base-16 conversion
        byte_arr[i] = (unsigned char)strtoul(hex_pair, NULL, 16);
    }
    
    return byte_count;
}

How to use this with your code:

After building your cWrite_All_Data string with Fmt, convert it to the 32-byte array:

unsigned char cAll_Data[200] = {0};
// ... your existing code to build cWrite_All_Data ...

int converted_bytes = hex_str_to_bytes(cWrite_All_Data, cAll_Data, sizeof(cAll_Data));
if (converted_bytes != 32) {
    // Handle error (e.g., invalid hex string or buffer issue)
}

This will give you the 32-byte array you need for CRC calculation.

2. Fix the CRC-16 Maxim Calculation

Your current CRC function has several issues that cause mismatches with the online tool. Let's fix them:

Key Problems in Your Original Code:

  • Undefined variable: ucBuffer isn't passed into the function or defined locally.
  • Incorrect bit loop: CRC-16 Maxim processes 8 bits per byte, not 16.
  • Wrong final XOR: Maxim CRC requires XORing the final result with 0xFFFF, not each byte with 0xFF.
  • Missing bit reversal: Maxim CRC uses reversed input bits and reversed output bits (handled via the 0xA001 polynomial, but your code wasn't accounting for this properly).
  • Parameter mismatch: The function parameter for the data was a single unsigned char instead of a pointer to the byte array.

Corrected CRC Function:

// Helper: Reverse 8 bits of a byte (required for Maxim CRC input)
unsigned char reverse_byte_bits(unsigned char b) {
    b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
    b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
    b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
    return b;
}

// Helper: Reverse 16 bits of an unsigned int (required for Maxim CRC output)
unsigned int reverse_16bits(unsigned int val) {
    val = ((val & 0xFF00) >> 8) | ((val & 0x00FF) << 8);
    val = ((val & 0xF0F0) >> 4) | ((val & 0x0F0F) << 4);
    val = ((val & 0xCCCC) >> 2) | ((val & 0x3333) << 2);
    val = ((val & 0xAAAA) >> 1) | ((val & 0x5555) << 1);
    return val;
}

// Calculates CRC-16 Maxim (Dallas/Maxim) for given data
void Daten_calculate_crc(const unsigned char *data, size_t data_len, char *ucCRC_MSB, char *ucCRC_LSB) {
    unsigned int uiCRC = 0x0000; // Initial value for CRC-16/Maxim
    const unsigned int POLY = 0xA001; // Reversed polynomial (0x8005 reversed)
    
    for (size_t x = 0; x < data_len; x++) {
        // Reverse the input byte (required by Maxim CRC spec)
        unsigned char reversed_byte = reverse_byte_bits(data[x]);
        uiCRC ^= (unsigned int)reversed_byte;
        
        // Process each bit of the byte
        for (int iBit = 0; iBit < 8; iBit++) {
            if (uiCRC & 0x0001) {
                uiCRC = (uiCRC >> 1) ^ POLY;
            } else {
                uiCRC >>= 1;
            }
        }
    }
    
    // Reverse the final CRC and XOR with 0xFFFF (Maxim spec requirement)
    uiCRC = reverse_16bits(uiCRC) ^ 0xFFFF;
    
    // Split into MSB and LSB, format as two-digit uppercase hex
    unsigned char crc_h = (uiCRC >> 8) & 0xFF;
    unsigned char crc_l = uiCRC & 0xFF;
    
    // Use %02X to ensure two digits (no manual padding needed)
    Fmt(ucCRC_MSB, "%02X", crc_h);
    Fmt(ucCRC_LSB, "%02X", crc_l);
}

How to Call the Corrected Function:

char ucCRC_MSB[3] = {0};
char ucCRC_LSB[3] = {0};
// Use the 32-byte cAll_Data array from step 1
Daten_calculate_crc(cAll_Data, 32, ucCRC_MSB, ucCRC_LSB);

This function will now produce the same CRC result as the online tool you're using, since it strictly follows the CRC-16 Maxim specification:

  • Initial value: 0x0000
  • Polynomial: 0x8005 (implemented via reversed 0xA001 for right-shift processing)
  • Input bits reversed per byte
  • Output bits reversed, then XOR with 0xFFFF

内容的提问来源于stack exchange,提问作者Ramles

火山引擎 最新活动