#modbus #crc16 #boolean-polynomials
#modbus #crc16 #логические многочлены
Вопрос:
Я использую ModBus RTU, и я пытаюсь выяснить, как вычислить CRC16. Мне не нужен пример кода. Мне просто любопытно узнать о механизме. Я узнал, что базовый CRC — это полиномиальное деление слова данных, которое дополняется нулями в зависимости от длины полинома. Следующий тестовый пример должен проверить, верно ли мое базовое понимание:
- слово данных: 0100 1011
- многочлен: 1001 (x3 1)
- дополнено на 3 бита из-за наивысшего показателя x3
- вычисление: 0100 1011 000 / 1001 — > остаток: 011
Вычисление.
01001011000
1001
0000011000
1001
01010
1001
0011
Правка 1: Пока что проверено Марком Адлером в предыдущих комментариях / ответах.
В поисках ответа я видел много разных подходов с обращением, зависимостью от малого или большого конечного значения и т.д., Которые изменяют результат по сравнению с заданным 011
.
Modbus RTU CRC16
Конечно, я хотел бы понять, как работают разные версии CRCS, но мой главный интерес — просто понять, какой механизм здесь применяется. Пока я знаю:
- x16 x15 x2 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 или других, которые я не понимаю. Заранее спасибо.
ПРАВКА 1: Согласно этому сайту, «1-я попытка» указывает на другой CRC16-метод с тем же полиномом, но другим начальным значением (0x0000), что говорит мне о том, что вычисление должно быть правильным. Как мне включить начальное значение?
ПРАВКА2: Ответ Марка Адлера делает свое дело. Однако, теперь, когда я могу вычислить CRC16 / Modbus, осталось прояснить несколько вопросов. Не требуется, но приветствуется.
А) Порядок вычислений был бы следующим: … ?
- первое применение уточнения для полного ввода (включая дополненные биты)
- 2-е
xor
начальное значение с (в CRC16) для первых 16 бит - третье применение RefOut для полного вывода / остатка (максимум 16 бит остатка в CRC16)
Б) Что касается RefIn и RefOut: всегда ли он отражает 8 бит для ввода и все биты для вывода, тем не менее, я использую CRC8 или CRC16 или CRC32?
C) Что означают 3-й (check) и 8-й (XorOut) столбцы на веб-сайте, на который я ссылаюсь? Последнее кажется довольно простым, я предполагаю, что оно применяется путем вычисления значения xor
после RefOut точно так же, как InitValue?
Ответ №1:
Давайте рассмотрим это шаг за шагом. Теперь вы знаете, как правильно рассчитать CRC-16 / BUYPASS, поэтому мы начнем с этого.
Давайте взглянем на CRC-16 / CCITT-FALSE. У этого есть начальное значение, которое не равно нулю, но все еще имеет RefIn и RefOut как false, как CRC-16 / BUYPASS. Чтобы вычислить CRC-16 / CCITT-FALSE для ваших данных, вы исключаете-или первые 16 бит ваших данных со значением инициализации 0xffff
. Это дает fe ef C0 03 00 01
. Теперь сделайте то, что вы знаете об этом, но с полиномом 0x11021
. Вы получите то, что находится в таблице, 0xb53f
.
Теперь вы знаете, как применить инициализацию. Следующий шаг касается того, являются ли RefIn и RefOut истинными. В качестве примера мы будем использовать CRC-16 / ARC. Уточнение означает, что мы отражаем биты в каждом байте входных данных. RefOut означает, что мы отражаем биты остатка. Тогда входное сообщение будет таким: 80 08 03 c0 00 80
. Деля на многочлен, 0x18005
получаем 0xb34b
. Теперь мы отразим все эти биты (не в каждом байте, а во всех 16 битах) и получим 0xd2cd
. Это то, что вы видите в качестве результата в таблице.
Теперь у нас есть то, что нам нужно для вычисления CRC-16 / MODBUS, который имеет как ненулевое значение инициализации ( 0xffff
), так и RefIn и RefOut как true. Мы начинаем с сообщения, в котором отражаются биты в каждом байте и инвертируются первые 16 бит. Это 7f f7 03 c0 00 80
. Разделите на 0x18005
, и вы получите остаток 0xb393
. Отразите эти биты, и мы получим 0xc9cd
ожидаемый результат.
Исключающее значение инициализации применяется после отражения, которое вы можете проверить, используя CRC-16 / RIELLO в этой таблице.
Ответы на добавленные вопросы:
A) Уточнение не имеет ничего общего с дополненными битами. Вы отражаете входные байты. Однако в реальном вычислении вы вместо этого отражаете многочлен, который учитывает оба отражения.
Б) Да.
C) Да, XorOut — это то, что вы исключаете, или конечный результат. Проверяется CRC девяти байтов «123456789» в ASCII.
Комментарии:
1. Вы уже сделали добавление дополнительных битов в первой строке. Вы добавили
000
к сообщению01001011
.2. Большое спасибо… Я отредактирую свой оригинальный пост и, возможно, удалю предыдущие комментарии, чтобы ваш ответ соответствовал моему вопросу, не вводя кого-либо в заблуждение. Вы не возражаете взглянуть на дополнительные вопросы? Я добавил к своему вопросу для уточнения?
3. Этот ответ превосходен. Интересно, почему я не получил ни одного положительного отзыва за более чем три года!?