Перейти к содержанию

Modbus TCP: сборка и разбор кадров

Задайте номер транзакции, Unit ID, функцию и регистры — калькулятор соберёт кадр Modbus TCP, разложит его по полям и покажет, каким будет ответ и как тот же запрос выглядит в Modbus RTU. Во втором режиме вставьте байты из Wireshark или журнала программы: заголовок MBAP будет проверен, а данные разобраны по полям.

Исходные данные

Режим

0…65 535 или 0x1501

0…255; 255 = 0xFF

как в кадре, с нуля: 107 или 0x006B; в нотации Modicon это 40001

от 1 до 125 за один запрос

Результат

Кадр запроса (ADU)

00 01 00 00 00 06 01 03 00 00 00 0A

12 байт: заголовок MBAP — 7, PDU — 5; поле длины = 6; CRC нет

Нормальный ответ
29 байт00 01 00 00 00 17 01 03 14 + 20 байт данных
Ответ с исключением
9 байт00 01 00 00 00 03 01 83 + код исключения
Тот же запрос в Modbus RTU
8 байт01 03 00 00 00 0A C5 CD: Unit ID стал адресом устройства, добавлена CRC-16
Порт TCP
502

Кадр по полям

БайтыПолеЗначение
00 01Идентификатор транзакции0x0001 (1) — сервер копирует его в ответ
00 00Идентификатор протокола0 — Modbus
00 06Длина6 — байтов дальше: Unit ID и PDU
01Идентификатор устройства (Unit ID)1 (0x01) — адрес устройства на последовательной линии за шлюзом
03Код функции03 — чтение регистров хранения (Read Holding Registers)
00 00Адрес первого регистра0 (0x0000); в нотации Modicon — 40001 или 400001
00 0AКоличество регистров10

1 (0x01) — адрес устройства на последовательной линии за шлюзом

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

Modbus TCP — тот же Modbus, что на линии RS-485, но переданный по Ethernet: код функции и данные (PDU) остаются прежними, а вместо адреса устройства и CRC перед ними встаёт 7-байтный заголовок MBAP. Запрос «прочитать 10 регистров хранения с адреса 0» занимает 12 байт: 00 01 00 00 00 06 01 03 00 00 00 0A. Калькулятор собирает такие кадры для функций 01–06, 15, 16 и 23, разбирает байты из Wireshark или журнала программы и показывает, как тот же запрос выглядит в Modbus RTU.

Браузер не может открыть соединение TCP с портом 502, поэтому калькулятор работает только с байтами: ничего никуда не отправляет и устройство не опрашивает.

Коротко

  • Кадр (ADU): заголовок MBAP (7 байт) и PDU — код функции и данные, всего не больше 260 байт.
  • Заголовок MBAP: транзакция (2 байта), протокол (2 байта, всегда 0), длина (2 байта), Unit ID (1 байт); все поля — старшим байтом вперёд.
  • Длина считает байты после неё: Unit ID и PDU.
  • CRC и пауз нет: границы кадра задаёт поле длины, целостность — Ethernet и TCP.
  • Порт: 502.
  • Unit ID: 0xFF или 0 для устройства прямо в сети, 1–247 — адрес устройства на RS-485 за шлюзом.

Как пользоваться калькулятором

Собрать запрос. Задайте номер транзакции и Unit ID — десятичными числами или в виде 0x1501, — затем функцию и её поля, как в калькуляторе Modbus RTU: адрес с нуля, количество, значения через пробел или запятую. На выходе — кадр с заголовком MBAP, таблица полей, длина нормального ответа и ответа с исключением, а для функций записи — весь ответ байт в байт. Строка «Тот же запрос в Modbus RTU» показывает кадр, который отправит шлюз на линию: Unit ID становится адресом устройства, в конце добавляется CRC-16.

Разобрать кадр. Вставьте байты в любом виде: 00 01 00 00, 0x00,0x01 или 00010000. Калькулятор проверит идентификатор протокола и поле длины, разберёт PDU по полям, покажет регистры как uint16 и int16, а пары регистров — как uint32, int32 и float32 в четырёх порядках байтов. Если вставлен кадр Modbus RTU — с адресом в начале и верной CRC в конце, — калькулятор узнает его и покажет тот же кадр в виде Modbus TCP.

Состояние хранится в адресе страницы: ссылкой на собранный запрос или разобранный кадр можно поделиться.

Заголовок MBAP

ПолеРазмерКто заполняетВ примере
Идентификатор транзакции2 байтаклиент; сервер копирует его в ответ00 01
Идентификатор протокола2 байтаклиент, всегда 0 — это Modbus; сервер копирует00 00
Длина2 байтакаждый для своего кадра: число байтов после поля длины00 06
Unit ID1 байтклиент; сервер копирует01
Код функции1 байтначало PDU, как в RTU03
Данные0–252 байтазависят от функции00 00 00 0A

Поле длины считает Unit ID и PDU, поэтому длина на 6 меньше длины всего кадра. В запросе на чтение PDU занимает 5 байт: длина — 6, кадр — 12 байт. В ответе с десятью регистрами PDU — 22 байта (код функции, счётчик байт и 20 байт данных): длина — 23, кадр — 29 байт.

Пример из руководства Modbus по TCP/IP — чтение регистра № 5 с номером транзакции 0x1501 и незначащим Unit ID:

15 01 | 00 00 | 00 06 | FF | 03 00 04 00 01
 TID    протокол  длина  Unit  PDU: функция 03, адрес 4, количество 1

Регистр № 5 в кадре имеет адрес 4: адреса Modbus считаются с нуля. Вставьте эти байты в режим «Разобрать кадр» — калькулятор разложит их так же.

Отличия от Modbus RTU

PDU одинаков на обоих транспортах: те же коды функций, адреса, количества и форматы данных, те же коды исключений. Меняется только обёртка.

Modbus RTUModbus TCP
Перед PDUадрес устройства, 1 байтзаголовок MBAP, 7 байт
После PDUCRC-16, 2 байта, младший байт первымничего
Граница кадратишина не короче 3,5 символаполе длины в заголовке
Кадр, байтдо 256до 260
Адресацияадрес 1–247 на шине, 0 — широковещательныйIP-адрес и порт 502; Unit ID — для шлюза
Запросыодин за другим: следующий — только после ответа или таймаутанесколько сразу, ответ находят по номеру транзакции
Проверка ошибокCRC-16 кадраCRC-32 Ethernet и контрольная сумма TCP

Нет CRC. Кадр Ethernet защищён своей CRC-32, а TCP повторяет потерянные и искажённые сегменты, поэтому своя контрольная сумма Modbus не нужна. Посчитать CRC-16 для кадра RTU можно в калькуляторе CRC.

Нет пауз в 3,5 символа. На последовательной линии конец кадра находят по тишине, а TCP — это поток байтов без пауз: один кадр может прийти двумя сегментами, а два кадра — одним. Поэтому длина записана в заголовке явно. Приёмник читает 6 байт, берёт из них длину и дочитывает ровно столько байтов. Калькулятор так же предупреждает, если байтов меньше, чем обещает поле длины, и показывает отдельно лишние байты — начало следующего кадра.

Unit ID вместо адреса. Устройство в сети TCP/IP находят по IP-адресу, и Unit ID для него ничего не значит: руководство рекомендует 0xFF, допускает и 0. Значение нужно шлюзу Modbus TCP — RTU: у шлюза один IP-адрес на всю линию RS-485, и по Unit ID он выбирает, какому устройству на линии переслать запрос. Тогда Unit ID — это обычный адрес от 1 до 247. Как шлюз поступит с Unit ID 0, руководство не говорит; если он передаст его на линию как есть, это будет широковещательный адрес 0: запрос выполнят все устройства, ответа не будет, а запрос на чтение потеряет смысл. Поэтому калькулятор предупреждает о Unit ID 0 в кадре RTU — это наш вывод, а не правило спецификации.

Транзакции. На линии RS-485 ведущий ждёт ответа на каждый запрос. По TCP клиент может отправить несколько запросов подряд и разобрать ответы по номеру транзакции: сервер копирует его из запроса. Сколько запросов одновременно держит клиент, руководство относит к его характеристикам — от 1 до 16. Ответ с номером, которого клиент не ждёт, отбрасывается.

Функции и длина кадров

КодФункцияЗапросНормальный ответ
01, 02чтение выходов и входов12 байт9 байт + количество / 8 с округлением вверх
03, 04чтение регистров12 байт9 байт + 2 × количество
05, 06запись одного выхода или регистра12 байт12 байт, PDU повторяет запрос
15 (0x0F)запись нескольких выходов13 байт + количество / 8 с округлением вверх12 байт
16 (0x10)запись нескольких регистров13 байт + 2 × количество12 байт
23 (0x17)запись и чтение регистров одним запросом17 байт + 2 × количество для записи9 байт + 2 × количество для чтения
любаяответ с исключением—9 байт

Каждый кадр Modbus TCP на 4 байта длиннее того же кадра RTU: 7 байт заголовка вместо 1 байта адреса и 2 байт CRC. Пределы количества те же, что на последовательной линии: до 2000 битов и 125 регистров на чтение, 1968 битов и 123 регистра на запись — их задаёт размер PDU в 253 байта, а не транспорт.

Функция 23 (Read/Write Multiple registers) сначала записывает регистры, затем читает — за один обмен. В запросе по порядку: адрес и количество для чтения (до 125), адрес и количество для записи (до 121), счётчик байт и значения. Пример из спецификации — записать три регистра с адреса 14 (0x0E) значениями 00FF и прочитать шесть с адреса 3:

запрос PDU: 17 00 03 00 06 00 0E 00 03 06 00 FF 00 FF 00 FF
ответ  PDU: 17 0C 00 FE 0A CD 00 01 00 03 00 0D 00 FF

В ответе — счётчик байт 0C и шесть регистров: 00FE, 0ACD, 0001, 0003, 000D, 00FF.

Исключения и шлюзы

Ответ с исключением в Modbus TCP — 9 байт: заголовок с длиной 3, код функции плюс 0x80 и код исключения. На запрос чтения регистров, которых нет, устройство ответит, например, 00 01 00 00 00 03 01 83 02. Коды те же, что в RTU, их таблица — в калькуляторе Modbus RTU. Два из них встречаются в основном в TCP:

  • 0A, GATEWAY PATH UNAVAILABLE — шлюз не смог выделить путь к устройству: неверно настроен или перегружен;
  • 0B, GATEWAY TARGET DEVICE FAILED TO RESPOND — шлюз переслал запрос на линию, но устройство с таким Unit ID не ответило. Чаще всего неверен Unit ID, скорость или формат порта шлюза.

Сервер, у которого кончились свободные транзакции, отвечает исключением 06 — устройство занято. А кадр с идентификатором протокола не 0 сервер не разбирает вовсе и молча отбрасывает: ответа не будет.

Типичные ошибки

  • Кадр RTU по TCP. Некоторые преобразователи Ethernet — RS-485 работают «прозрачно» и передают по TCP кадр RTU с адресом и CRC. Спецификация такой режим не описывает, и с клиентом Modbus TCP он не работает: калькулятор распознаёт такой кадр по верной CRC и показывает правильный вид.
  • Неверная длина. Поле длины считает Unit ID и PDU, но не 6 байт заголовка перед ним. Длина, равная длине всего кадра, — частая ошибка самодельных реализаций.
  • Unit ID не тот. Устройство прямо в сети может отвечать только на один Unit ID или игнорировать его; шлюз пересылает запрос по Unit ID на линию. Если ответа нет или приходит исключение 0B, проверьте Unit ID первым делом.
  • Сдвиг на один регистр. Адреса в кадре считаются с нуля: регистр 40001 — адрес 0. Номер в нотации Modicon переведёт в адрес калькулятор Modbus RTU в режиме «Номер → адрес».

Как устроены функции и данные самого протокола — в статье «Modbus RTU». Прибор на линии RS-485 можно опросить прямо из браузера через Web Serial в Modbus RTU мастере, а сетевой адрес и маску для контроллера с Ethernet подобрать в калькуляторе подсетей.

Частые вопросы

Из чего состоит кадр Modbus TCP?

Из заголовка MBAP длиной 7 байт и PDU — кода функции с данными. Заголовок — это номер транзакции (2 байта), идентификатор протокола (2 байта, всегда 0), длина (2 байта) и Unit ID (1 байт). Запрос на чтение 10 регистров хранения с адреса 0 — 00 01 00 00 00 06 01 03 00 00 00 0A: транзакция 1, протокол 0, длина 6, Unit ID 1 и тот же PDU 03 00 00 00 0A, что в Modbus RTU.

Что считает поле длины в заголовке MBAP?

Число байтов после него: Unit ID и PDU. Сам заголовок до поля длины включительно (6 байт) не считается. Для запроса чтения регистров PDU занимает 5 байт, поэтому длина равна 6, а весь кадр — 12 байт. По этому полю приёмник находит конец кадра в потоке TCP, даже если кадр пришёл двумя сегментами.

Какой Unit ID ставить в Modbus TCP?

Если устройство подключено к сети напрямую, руководство Modbus по TCP/IP рекомендует незначащее значение 0xFF (255); значение 0 тоже допускается. Если запрос идёт через шлюз Modbus TCP — RTU, Unit ID — это адрес устройства на линии RS-485, от 1 до 247: по нему шлюз решает, кому переслать запрос. Многие устройства на практике ждут Unit ID 1 — что принимает конкретный прибор, смотрите в его документации.

Почему в Modbus TCP нет CRC?

Целостность кадра уже проверяют нижние уровни: Ethernet добавляет к каждому кадру CRC-32, а TCP — свою контрольную сумму и повторную передачу потерянных сегментов. Границы кадра задаёт поле длины в заголовке, поэтому не нужны и паузы в 3,5 символа, как в RTU. Если в кадре из сети в конце стоят два байта CRC, это не Modbus TCP, а кадр RTU, переданный по TCP как есть: такой режим спецификация не описывает.

Можно ли отправить запрос Modbus TCP прямо из браузера?

Нет. Страница в браузере не может открыть соединение TCP с произвольным портом, в том числе с портом 502: ей доступны только HTTP, WebSocket и подобные протоколы. Поэтому калькулятор только собирает и разбирает байты. Отправить кадр можно утилитой вроде modpoll или netcat, а прибор на последовательной линии опросить из браузера через Web Serial — в Modbus RTU мастере.

Источники

  1. Modbus Organization. MODBUS Messaging on TCP/IP Implementation Guide V1.0b, 2006 — ADU из заголовка MBAP и PDU, Unit ID вместо адреса устройства, длина в заголовке вместо пауз (разд. 3.1.2); поля MBAP: транзакция, протокол 0, длина, Unit ID, 7 байт, старшим байтом вперёд, порт 502 (3.1.3); пример запроса, несколько запросов без ожидания ответа, Unit ID 0xFF и 0 (4.4.1.2); проверка ответа по номеру транзакции и протоколу (4.4.1.3); кадр с протоколом не 0 отбрасывается, при нехватке транзакций — исключение 06 (4.4.2.2)
  2. Modbus Organization. MODBUS Application Protocol Specification V1.1b3, 2012 — PDU не длиннее 253 байт, ADU Modbus TCP — до 260 байт (разд. 4.1); форматы функций 01–06, 15 и 16 (6.1–6.6, 6.11, 6.12); функция 23 и её пример (6.17); коды исключений, в том числе 0A и 0B для шлюзов (7)
  3. Modicon. Modbus Protocol Reference Guide PI-MBUS-300 Rev. J, 1996 — пример кадра RTU 11 03 00 6B 00 03 76 87 — чтение регистров 40108–40110 устройства 17; на нём проверено преобразование RTU ↔ TCP

Где пригодится

Встроить калькулятор на свой сайт

Скопируйте код и вставьте его в HTML страницы, статьи или вики. Виджет бесплатный, без рекламы, счётчиков и cookie. Условие одно — ссылка на GAW под рамкой остаётся на месте. Подробнее о виджетах

<iframe src="https://gaw.ru/embed/modbus-tcp/" title="Modbus TCP: сборка и разбор кадров" width="100%" height="640" style="border:1px solid #e3e5e9;border-radius:8px" loading="lazy" allow="clipboard-write"></iframe>
<p style="margin:6px 0 0;font-size:14px">Калькулятор: <a href="https://gaw.ru/tools/modbus-tcp/">Modbus TCP: сборка и разбор кадров</a> — GAW.ru</p>
Автоподстройка высоты рамки

Если сайт разрешает скрипты, добавьте этот код один раз в любом месте страницы: рамка будет менять высоту вместе с результатом расчёта.

<script>window.addEventListener("message",function(e){if(e.origin!=="https://gaw.ru"||!e.data||e.data.type!=="gaw:embed-height")return;var f=document.querySelectorAll('iframe[src^="https://gaw.ru/embed/"]');for(var i=0;i<f.length;i++)if(f[i].contentWindow===e.source)f[i].style.height=e.data.height+"px"})</script>

Обновлено .

Нашли ошибку в расчёте?