CRC16 (ModBus) - вычислительный алгоритм - PullRequest
2 голосов
/ 15 марта 2019

Я использую Modbus RTU и пытаюсь выяснить, как рассчитать CRC16. Мне не нужен пример кода. Мне просто любопытно по поводу механизма. Я узнал, что базовый CRC - это полиномиальное деление слова данных, которое дополняется нулями в зависимости от длины полинома. Следующий тестовый пример должен проверить правильность моего базового понимания:

  • слово данных: 0100 1011
  • полином: 1001 (х 3 + 1)
  • дополняется 3 битами из-за наивысшего показателя степени x 3
  • расчет: 0100 1011 000/1001 -> остаток: 011

Расчет.

01001011000
 1001
 0000011000
      1001
      01010
       1001
       0011 

Edit1: До сих пор подтверждено Марком Адлером в предыдущих комментариях / ответах.

В поисках ответа Я видел много разных подходов с реверсированием, зависимостью от младшего или большого порядкового номера и т. Д., Которые изменяют результат из данного 011.

Modbus RTU CRC16

Конечно, я бы хотел понять, как работают разные версии CRC, но мой основной интерес - просто понять, какой механизм здесь применяется. Насколько я знаю:

  • x 16 + x 15 + x 2 + 1 - полином: 0x18005 или 0b11000000000000101
  • начальное значение 0xFFFF
  • пример сообщения в шестнадцатеричном виде: 01 10 C0 03 00 01
  • CRC16 вышеприведенного сообщения в шестнадцатеричном виде: C9CD

Я рассчитал это вручную, как в примере выше, но я бы не хотел записывать это в двоичном виде в этом вопросе. Я предполагаю, что мое преобразование в двоичный файл является правильным. Чего я не знаю, так это как включить начальное значение - используется ли оно для дополнения слова данными вместо нулей? Или мне нужно поменять ответ? Что-то еще?

  • 1-я попытка: заполнение 16 битами с нулями. Вычисляем остаток в двоичном виде будет 1111 1111 1001 1011, который равен FF9B в шестнадцатеричном формате и неправильный для CrC16 / Modbus, но правильный для CRC16 / Bypass

  • 2-я попытка: заполнение 16 битами из-за начального значения. Вычисляем остаток в двоичном виде будет 0000 0000 0110 0100, что является 0064 в шестнадцатеричном и неправильным

Было бы здорово, если бы кто-то мог объяснить или уточнить мои предположения. Честно говоря, я потратил много часов на поиск ответа, но каждое объяснение основано на примерах кода на C / C ++ или других, которые я не понимаю. Заранее спасибо.

EDIT1: Согласно этому сайту , "первая попытка" указывает на другой метод CRC16 с тем же полиномом, но другим начальным значением (0x0000), что говорит мне, что расчет должен быть правильным. crccalc Как включить начальное значение?

РЕДАКТИРОВАТЬ2: Марк Адлерс Ответ делает свое дело. Однако теперь, когда я могу вычислить CRC16 / Modbus, осталось несколько вопросов для прояснения. Не нужно, но ценится.

A) Порядок вычислений будет: ...?

  • 1-е применение RefIn для полного ввода (включая дополненные биты)
  • 2nd xor InitValue с (в CRC16) для первых 16 бит
  • 3-е применение RefOut для полного вывода / остатка (остаток максимум 16 бит в CRC16)

B) Обращаясь к RefIn и RefOut: всегда ли он отражает 8 битов для входа и все биты для вывода, тем не менее, я использую CRC8 или CRC16 или CRC32?

C) Что означают 3-й (чек) и 8-й (XorOut) столбец на веб-сайте, который я имею в виду? Последнее кажется довольно простым, я предполагаю, что оно применимо, вычисляя значение xor после RefOut точно так же, как InitValue?

1 Ответ

0 голосов
/ 16 марта 2019

Давайте сделаем это шаг за шагом.Теперь вы знаете, как правильно рассчитать CRC-16 / BUYPASS, поэтому мы начнем с этого.

Давайте посмотрим CRC-16 / CCITT-FALSE.У этого есть начальное значение, которое не является нулем, но все еще имеет RefIn и RefOut как ложь, как CRC-16 / BUYPASS.Чтобы вычислить CRC-16 / CCITT-FALSE для ваших данных, вы должны исключить или первые 16 бит ваших данных со значением Init * 0xffff.Это дает fe ef C0 03 00 01.Теперь сделайте то, что вы знаете об этом, но с полиномом 0x11021.Вы получите то, что в таблице, 0xb53f.

Теперь вы знаете, как применять Инициативу.Следующий шаг касается RefIn и RefOut: true .Мы будем использовать CRC-16 / ARC в качестве примера.RefIn означает, что мы отражаем биты в каждом байте ввода.RefOut означает, что мы отражаем биты остатка.Входное сообщение тогда: 80 08 03 c0 00 80.Разделив на многочлен 0x18005, мы получим 0xb34b.Теперь мы отражаем все эти биты (не в каждом байте, а во всех 16 битах) и получаем 0xd2cd.Это то, что вы видите как результат в таблице.

Теперь у нас есть то, что нам нужно для вычисления CRC-16 / MODBUS, который имеет как ненулевое значение Init (0xffff), так и RefIn и RefOut.как правда.Мы начинаем с сообщения с битами в каждом байте, которые отражают и , первые 16 бит инвертированы.Это 7f f7 03 c0 00 80.Разделите на 0x18005, и вы получите остаток 0xb393.Отразите эти биты, и мы получим 0xc9cd, ожидаемый результат.

После отражения применяется исключающее-или-Init, которое можно проверить с помощью CRC-16 / RIELLO в этой таблице.

Ответы на добавленные вопросы:

A) RefIn не имеет ничего общего с дополненными битами.Вы отражаете входные байты.Однако в реальном расчете вместо этого вы отражаете многочлен, который учитывает оба отражения.

B) Да.

C) Да, XorOut - это то, что вы исключаете, или конечный результатс.Проверьте CRC из девяти байтов "123456789" в ASCII.

...