Sidebar Left

Кадр Modbus: из чего состоит запрос

Любой обмен в Modbus — это пара «запрос — ответ». Внутри каждого сообщения лежит одна и та же конструкция: номер функции и её данные. Всё остальное — обёртка, которая зависит от среды передачи.

PDU и ADU
Сообщение Modbus состоит из двух вложенных частей. PDU (protocol data unit) — смысловая часть: один байт кода функции и данные этой функции. Она не зависит от того, по какой линии идёт обмен. ADU (application data unit) — то, что реально уходит в линию: PDU плюс обрамление, которое отвечает за адресацию и целостность.

Возьмём один запрос — «прочитать три регистра хранения начиная с адреса 107» — и посмотрим, как он выглядит на каждом уровне.

Шаг 1. PDU — пять байт, одинаковых для RTU и TCP:

03 00 6B 00 03

Байты Поле PDU Значение
03 Код функции чтение регистров хранения
00 6B Данные функции: начальный адрес 107
00 03 Данные функции: количество регистров 3

Обратите внимание: ни адреса устройства, ни контрольной суммы здесь нет — PDU не знает, кому адресован запрос и по какой среде поедет.

Шаг 2. Тот же PDU в обёртке RTU — восемь байт:

01 03 00 6B 00 03 74 17

Часть ADU Байты Зачем
Обрамление спереди 01 адрес ведомого устройства: кому предназначен кадр
PDU 03 00 6B 00 03 без изменений
Обрамление сзади 74 17 CRC16: проверка целостности, младший байт первым

Шаг 3. Тот же PDU в обёртке TCP — двенадцать байт:

00 01 00 00 00 06 01 03 00 6B 00 03

Часть ADU Байты Зачем
Заголовок MBAP 00 01 идентификатор транзакции: по нему ответ сопоставляется с запросом
Заголовок MBAP 00 00 идентификатор протокола: для Modbus всегда ноль
Заголовок MBAP 00 06 длина: сколько байт идёт дальше (unit id + PDU)
Заголовок MBAP 01 идентификатор устройства: адрес прибора за шлюзом
PDU 03 00 6B 00 03 снова без изменений
Обрамление сзади контрольной суммы нет: целостность обеспечивает TCP

Шаг 4. Ответ устроен так же. PDU ответа несёт код функции, число байт данных и сами данные:

03 06 02 2B 00 00 00 64

Байты Поле PDU ответа Значение
03 Код функции тот же, что в запросе — значит, устройство отработало без ошибки
06 Число байт данных 6 байт, то есть три регистра по два байта
02 2B Данные: первый регистр 0x022B = 555 — регистр 107, с которого начинали чтение
00 00 Данные: второй регистр 0 — регистр 108
00 64 Данные: третий регистр 0x0064 = 100 — регистр 109

Адресов регистров в ответе нет — только значения подряд. Соответствие «значение ↔ адрес» мастер восстанавливает по своему же запросу: читали три регистра с адреса 107, значит первое значение относится к 107, второе к 108, третье к 109.

В линии RS-485 к этому PDU добавляются адрес и контрольная сумма — всего одиннадцать байт:

01 03 06 02 2B 00 00 00 64 05 7A

Часть ADU Байты Зачем
Обрамление спереди 01 адрес ведомого: кто именно ответил. В линии несколько устройств, и мастер по этому байту понимает, чей ответ
PDU 03 06 02 2B 00 00 00 64 смысловая часть — та же, что была бы и в сети
Обрамление сзади 05 7A CRC16 по всем предыдущим байтам, младший байт первым. Не сошёлся — кадр молча отбрасывается

В сети вместо адреса и CRC появляется заголовок MBAP — всего пятнадцать байт:

00 01 00 00 00 09 01 03 06 02 2B 00 00 00 64

Часть ADU Байты Зачем
Заголовок MBAP 00 01 идентификатор транзакции: совпадает с номером из запроса, по нему ответ и сопоставляется
Заголовок MBAP 00 00 идентификатор протокола: для Modbus всегда ноль
Заголовок MBAP 00 09 длина: девять байт дальше — один байт unit id плюс восемь байт PDU
Заголовок MBAP 01 идентификатор устройства: тот же, что в запросе
PDU 03 06 02 2B 00 00 00 64 снова без изменений
Обрамление сзади контрольной суммы нет: целостность обеспечивает TCP

Сравните два последних кадра: середина у них совпадает байт в байт, различаются только начало и конец. Именно поэтому шлюз RS-485 ↔ Ethernet не «переводит» протокол, а лишь меняет обёртку — и поэтому при отладке через шлюз сравнивать надо PDU, а не кадры целиком.

Ограничения размеров. Максимальный PDU — 253 байта. Отсюда получаются и остальные пределы:

Что Размер Откуда
PDU до 253 байт ограничение протокола
ADU в RTU до 256 байт 1 байт адреса + 253 байта PDU + 2 байта CRC
ADU в TCP до 260 байт 7 байт заголовка MBAP + 253 байта PDU
Регистров за один запрос 125 125 × 2 байта + код функции + счётчик байт = 252 байта — влезает в PDU
Бит за один запрос 2000 2000 бит = 250 байт данных + служебные байты

Эти цифры — не абстракция: попытка прочитать 130 регистров одним запросом вернёт исключение, потому что ответ просто не помещается в PDU.

Разбор запроса RTU
Прочитаем три регистра хранения, начиная с адреса 107, у устройства с адресом 1:

01 03 00 6B 00 03 74 17

Байты Что это Значение
01 Адрес ведомого устройства 1
03 Код функции Чтение регистров хранения
00 6B Начальный адрес 107 — первый читаемый регистр
00 03 Количество регистров 3
74 17 Контрольная сумма CRC16 младший байт первым

Обратите внимание на порядок: все числовые поля в PDU передаются старшим байтом вперёд, и только CRC — младшим. Это классическая ловушка при написании своего мастера.

Разбор ответа

01 03 06 02 2B 00 00 00 64 05 7A

Байты Что это Значение
01 Адрес ведомого ответило устройство 1
03 Код функции тот же, что в запросе — значит, ошибки нет
06 Число байт данных 6 байт = 3 регистра
02 2B Регистр 107 0x022B = 555
00 00 Регистр 108 0
00 64 Регистр 109 0x0064 = 100
05 7A CRC16

Ответ не содержит адресов регистров — только значения подряд. Сопоставление «значение ↔ регистр» держит у себя мастер, по своему же запросу. Поэтому при разборе ответа важно не потерять контекст запроса.

Тот же обмен в Modbus TCP

00 01 00 00 00 06 01 03 00 6B 00 03

Байты Что это Значение
00 01 Идентификатор транзакции по нему ответ сопоставляется с запросом
00 00 Идентификатор протокола всегда 0 для Modbus
00 06 Длина 6 байт дальше: unit id и PDU
01 Идентификатор устройства (unit id) адрес за шлюзом; при прямом подключении часто 1 или 255
03 00 6B 00 03 PDU та же функция с теми же параметрами

Отличия от RTU ровно два: спереди семибайтный заголовок, сзади нет CRC. PDU не меняется — поэтому конвертер RS-485 ↔ Ethernet может просто переупаковывать кадры.

Как считается CRC16
Контрольная сумма считается по всем байтам ADU, кроме самой суммы. Алгоритм: регистр инициализируется значением 0xFFFF, каждый байт складывается по исключающему ИЛИ с младшим байтом регистра, затем восемь раз сдвиг вправо; если при сдвиге ушла единица, регистр складывается с полиномом 0xA001. В кадр результат укладывается младшим байтом вперёд.

Проверка: для запроса 01 03 00 6B 00 03 получается 0x1774 — в линии это выглядит как «74 17».

Тайминги RTU
В последовательной линии нет ни длины, ни признака конца кадра — границы задаются паузами. Внутри кадра пауза не должна превышать 1,5 символа, между кадрами должна быть не менее 3,5 символов. На скорости 9600 бод символ длится около миллисекунды, то есть межкадровая пауза — около 4 мс.

Отсюда две частые беды: слишком короткая пауза — и устройство склеивает два кадра в один, а слишком длинная задержка внутри кадра — и кадр рвётся на части. На скоростях выше 19200 бод пауза обычно фиксируется на уровне 1,75 мс.

← Все разделы справочника Modbus

Style Selector

Primary Color

Direction