Я наткнулся недавно на очередные грабли.
Суть такая:
Есть алгоритм для подсчёта CRC16 для Modbus:
Цитата
1. Load a 16–bit register with FFFF hex (all 1’s). Call this the CRC register.
2. Exclusive OR the first 8–bit byte of the message with the low–order byte of the 16–bit CRC register, putting the result in the
CRC register.
3. Shift the CRC register one bit to the right (toward the LSB), zero–filling the MSB. Extract and examine the LSB.
4. (If the LSB was 0): Repeat Step 3 (another shift).
(If the LSB was 1): Exclusive OR the CRC register with the polynomial value 0xA001 (1010 0000 0000 0001).
5. Repeat Steps 3 and 4 until 8 shifts have been performed. When this is done, a complete 8–bit byte will have been
processed.
6. Repeat Steps 2 through 5 for the next 8–bit byte of the message. Continue doing this until all bytes have been processed.
7. The final content of the CRC register is the CRC value.
8. When the CRC is placed into the message, its upper and lower bytes must be swapped as described below.
И есть алгоритм для подсчёта CRC16 из WinAvr <util/crc16.h> написанный на ASM и оптимизированный.
Код
Optimized CRC-16 calculation.
Polynomial: x^16 + x^15 + x^2 + 1 (0xa001)<br>
Initial value: 0xffff
This CRC is normally used in disk-drive controllers.
The following is the equivalent functionality written in C.
\code
uint16_t
crc16_update(uint16_t crc, uint8_t a)
{
int i;
crc ^= a;
for (i = 0; i < 8; ++i)
{
if (crc & 1)
crc = (crc >> 1) ^ 0xA001;
else
crc = (crc >> 1);
}
return crc;
}
Вроде как одно и тоже, а нет!
По доке на modbus сдвиг нужно делать до анализа младшего бита crc,
а в приведённой цитате из WinAvr <util/crc16.h> это не так.
Я 3 часа долбался - почему это вдруг у моих приборов RS-485 перестал работать.
А это я перед отпуском решил "улучшить" CRC модуль и забыл об этом.