Странный расчет CRC - PullRequest
       10

Странный расчет CRC

0 голосов
/ 23 октября 2011

Я собираюсь подключиться к устройству (протокол MODBUS), и мне нужно рассчитать CRC (CRC16). Существуют стандартные реализации этого протокола, но я должен создать свой CRC, используя эту формулу:

X15 + X2 + 1 (есть стандартная реализация с этой формулой: X16 + X15 + X2 + 1)

Я проверил разные значения для CRC, но ни один из них не дает мне правильный ответ. Я должен записать несколько байтов в порт, и в конце этой байтовой строки я должен написать два байта CRC, чтобы получить информацию о моем устройстве.

1 Ответ

2 голосов
/ 17 мая 2013

Какой у вас вопрос?Я предполагаю, что ваш вопрос: «Как рассчитать CRC MODBUS в конце сообщения, чтобы устройство MODBUS на другом конце кабеля распознало его как действительное сообщение MODBUS?»

Я пытаюсьПолучите проверочные векторы в первую очередь, прежде чем я реализую еще одну контрольную сумму или функцию CRC.

У вас есть примеры действительных сообщений, , включая правильный / ожидаемый CRC в конце?

Согласно Википедии: проверка циклическим избыточным кодом : «Поскольку старший бит всегда равен 1, а n-битный CRC должен быть определен (n + 1) -битным делителем, которыйпереполняет n-битный регистр, некоторые авторы предполагают, что нет необходимости упоминать старший разрядный бит делителя. "

Поэтому авторы, которые говорят, что MODBUS использует полином" X ^ 15 + X ^ 2 + 1 "(с понятным x ^ 16, поскольку это 16-битный CRC) относятся к тому же полиному, что и другие авторы, которые говорят, что MODBUS использует полином «X ^ 16 + X ^ 15 + X ^ 2 + 1».Оба автора напишут код, который генерирует точно такой же CRC и может взаимодействовать друг с другом.

Кроме того, люди, вычисляющие стандартный CRC MODBUS в направлении «вперед», часто используют магическую константу «0x8005».Те, кто вычисляет стандартную CRC MODBUS в «обратном» направлении, часто используют вместо этого магическую константу «0xA001» (поразрядное «0x8005»).Оба пишут код, который генерирует одни и те же байты CRC и может взаимодействовать друг с другом.

Существует множество реализаций расчета MODBUS CRC в Интернете;возможно, вам может пригодиться один из них.

онлайн-калькулятор CRC в режиме реального времени со множеством параметров http://www.zorc.breitbandkatze.de/crc.html

Он-лайн расчет CRC http://www.lammertbies.nl/comm/info/crc-calculation.html

и многие другие, вбез определенного заказа:

a b c d e f г ч i j k l м n o p q

Многие реализации ориентированы на байты, которые работают немного быстрее, но требуютбольшая справочная таблица (и для меня далеко не очевидно, как проверить , является ли справочная таблица действительной).

Многие реализации ориентированы на биты, что приводит к гораздо более короткому размеру программы именьше пыльных углов, где могут скрываться ошибки (но для вычисления контрольной суммы требуется примерно в 8 раз больше времени), например:

// warning: untested code
// optimized for size rather than speed
// (i.e., uses a bit-oriented calculation rather than table-driven calculation)
uint16_t modbusCRC(uint8_t* data, int length) {
    uint16_t crc = 0xFFFF;
    for(int pos = 0; pos<length; pos++){
        crc ^= (uint16_t)data[pos];
        for( int i=0; i<8; i++ ){
            if(crc & 1){      // LSB is set
                crc >>= 1;                 // Shift right
                crc ^= 0xA001;             // XOR 0xA001
            }else{                         // LSB is not set
                crc >>= 1;
            };
        };
    };
    return crc;
}
int main(void){
    uint8_t message[80] = { // 6-byte test vector
      0x11, 0x03, 0x00, 0x6B, 0x00, 0x03
    };
    int message_length = 6;
    uint16_t the_CRC = modbusCRC(message, message_length); // find CRC of the message
    message[message_length++] = the_CRC & 0xFF; // send low byte first
    message[message_length++] = the_CRC >> 8; // then send high byte
    assert( 0x76 == message[6] ); // test against known-good CRC
    assert( 0x87 == message[7] );
    send_message(message, message_length); // send all 8 bytes of the message,
    // including the two MODBUS CRC bytes.
    // (Must send *all* 8 bytes of the message,
    // even though there are multiple 0x00 bytes).
}

"Binary MODBUS" ("Формат кадра Modbus RTU") отправляет вседанные сообщения в виде необработанных 8-битных байтов, вкл.2 байта CRC.

«ASCII MODBUS» («Формат кадра Modbus ASCII») отправляет сообщение в виде более или менее простого текста ASCII, включая 8-битную контрольную сумму.(Контрольная сумма передается как 2 байта - как 2 шестнадцатеричных символа ASCII).

...