ANSI C中十六进制字符串转32字节数组及CRC-16(Maxim)计算结果不一致问题排查
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:
ucBufferisn'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 with0xFF. - Missing bit reversal: Maxim CRC uses reversed input bits and reversed output bits (handled via the
0xA001polynomial, but your code wasn't accounting for this properly). - Parameter mismatch: The function parameter for the data was a single
unsigned charinstead 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 reversed0xA001for right-shift processing) - Input bits reversed per byte
- Output bits reversed, then XOR with
0xFFFF
内容的提问来源于stack exchange,提问作者Ramles




