• 0

    No products in the cart.

  • Авг, Чт, 2023

Протокол Modbus. Описание и примеры использования.

Modbus — самый широко распространенный промышленный протокол для организации обмена данными между различными устройствами (межмашинное взаимодействие, Machine-to-Machine, M2M). Популярность объясняется многими факторами, среди которых простота реализации, отсутствие необходимости использовать дополнительные микросхемы, и, конечно же, открытость протокола.

Основные плюсы:

  • надежный контроль ошибок.
  • массовая распространенность.
  • открытость.
  • возможность включения в сеть большого количества подчиненных устройств с последующим обращением к любому из них при помощи выделенного ему адреса.

В то же время протокол Modbus не избавлен от некоторых недостатков:

  • организация обмена данными по модели ведущий-подчиненный. При этом подчиненное устройство не может само инициировать отправку данных ведущему, а должно в обязательном порядке ожидать запроса.
  • отсутствует механизм для определения обрыва линии связи.
  • в одном запросе можно прочитать значения только последовательных регистров. Для чтения произвольных регистров необходимо отправлять несколько запросов, что увеличивает нагрузку на сеть.

Обсуждая достоинства и недостатки протокола мы частично забежали вперед, так что теперь давайте разберем все поэтапно.

Как уже было упомянуто, протокол Modbus использует обмен данными по модели ведущий-подчиненный (Master — Slave). Ведущий отправляет запросы, на которые могут отвечать подчиненные. Slave-устройство не может само начать обмен данными, только по команде от master’a.

В качестве физического уровня стандарт предусматривает использование интерфейсов RS-232RS-422 и RS-485. Также существует реализация для TCP/IP — Modbus TCP. Но этот вариант мы сегодня будем затрагивать в меньшей степени.

Сеть Modbus может состоять из нескольких slave-устройств (от 1-го до 247-ми), но master должен быть только один. Каждое из подчиненных устройств имеет свой собственный адрес, соответственно, ведущий может адресовать свое сообщение или запрос конкретному slave-устройству.

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

На адреса slave накладываются некоторые ограничения:

  • диапазон допустимых адресов — 1…247. Значения адресов от 248 до 255 являются зарезервированными, а адрес 0 используется для передачи широковещательных сообщений.
  • master адреса не имеет, он в сети и так один.
  • два подчиненных устройства не могут иметь одинаковые адреса.

Вот как может выглядеть один из вариантов подключения устройств с использованием RS-485:

Здесь у нас присутствует один master и три slave-устройства с адресами от 0x03 до 0x05.

Переходим дальше… Различают несколько логических уровней протокола:

Modbus RTURS-232 RS-422 RS-485Двоичный вариант кодирования данных. Разделителем между пакетами служит временной интервал. То есть сообщение должно начинаться и заканчиваться паузой в течение определенного промежутка времени. Это время не должно быть меньше, чем время передачи 3.5 символов при использующейся скорости передачи данных.Кроме того, в процессе передачи пакета данных не должно быть пауз длительностью, превышающей время передачи 1.5 символов. Соответственно, Modbus RTU очень критичен к временным задержкам, но зато размер пакетов меньше, чем в Modbus ASCII.
Modbus ASCIIRS-232 RS-422 RS-485В данном случае для обмена данными используются исключительно ASCII символы. И в отличие от Modbus RTU начало и конец сообщений определяются специальными символами.Начало пакета — ASCII символ «:» (0x3A), конец — «CR + LF» (0x0D + 0x0A).
Modbus TCPTCP/IPПротокол используется при передаче данных с использованием TCP/IP.

Сегодня, в первую очередь, будем подробно разбирать Modbus RTU и Modbus ASCII. Структура пакетов выглядит следующим образом:

Структура данных Modbus RTU.
Структура данных Modbus ASCII.

В стандарте Modbus принята следующая терминология:

  • ADU (Application Data Unit) — полный пакет данных.
  • PDU (protocol data unit) — часть пакета, содержащая непосредственно полезные данные.

Для расчета контрольной суммы используются разные алгоритмы: для Modbus RTU — CRC16, для ASCII — LRC8. В обоих случаях под контрольную сумму задействованы два байта.

Коды функций можно разделить на три группы:

  • Стандартные коды команд, описанные в Modbus-IDA.
  • Задаваемые пользователем (user-defined function codes) — 65…72, 100…110. Эти коды не описаны в спецификации стандарта и могут использоваться в конкретных изделиях для собственных функций.
  • Зарезервированные (reserved). В эту группу входят коды 9, 10, 13, 14, 41, 42, 90, 91, 125, 126 и 127.

Но прежде, чем перейти к рассмотрению базовых/стандартных команд, необходимо рассмотреть использующуюся модель данных. Выполнение команд протокола Modbus подразумевает чтение и запись данных в регистры устройства. И различают 4 типа регистров, организованных в 4 таблицы данных:

ТаблицаТип элемента
Дискретные входы (Discrete Inputs)1 бит
Дискретные выходы (регистры флагов, Coils)1 бит
Регистры ввода (Input Registers)16-битное слово
Регистры хранения (Holding Registers)16-битное слово

Дискретные входы и регистры ввода доступны только для чтения данных, а, соответственно, дискретные выходы и регистры хранения — для чтения и записи.

Доступ к регистрам таблицы осуществляется при помощи 16-ти битного адреса. Первому элементу таблицы соответствует адрес 0. Таким образом, каждая из этих 4-х таблиц может включать в себя вплоть до 65536 регистров (адреса 0…65535 — 16 бит).

Вот теперь давайте рассмотрим конкретные команды из группы стандартных:

  • 0x01 (1) — чтение значений из нескольких регистров флагов — Read Coil Status.
  • 0x02 (2) — чтение значений из нескольких дискретных входов — Read Discrete Inputs.
  • 0x03 (3) — чтение значений из нескольких регистров хранения — Read Holding Registers.
  • 0x04 (4) — чтение значений из нескольких регистров ввода — Read Input Registers.
  • 0x05 (5) — запись значения одного флага — Force Single Coil.
  • 0x06 (6) — запись значения в один регистр хранения — Preset Single Register.
  • 0x07 (7) — чтение сигналов состояния — Read Exception Status.
  • 0x08 (8) — диагностика — Diagnostic.
  • 0x0B (11) — чтение счетчика событий — Get Com Event Counter.
  • 0x0C (12) — чтение журнала событий — Get Com Event Log.
  • 0x0F (15) — запись значений в несколько регистров флагов — Force Multiple Coils.
  • 0x10 (16) — запись значений в несколько регистров хранения — Preset Multiple Registers.
  • 0x11 (17) — чтение информации об устройстве — Report Slave ID.
  • 0x14 (20) — чтение из файла — Read File Record.
  • 0x15 (21) — запись в файл — Write File Record.
  • 0x16 (22) — запись в один регистр хранения с использованием маски «И» и маски «ИЛИ» — Mask Write Register.
  • 0x18 (24) — чтение данных из очереди — Read FIFO Queue.
  • 0x2B (43) — Encapsulated Interface Transport.

И, конечно же, мы не можем не разобрать конкретные примеры запросов и ответов при работе по Modbus.

Протокол Modbus. Примеры команд.

Первым делом займемся чтением данных — коды функций 0x01, 0x02, 0x03, 0x04. В общем виде запросы ведущего и ответы подчиненного выглядят следующим образом (здесь мы рассматриваем только часть пакета — PDU):

Протокол Modbus, чтение данных.

Обратите внимание, что в запросе передается количество элементов(!), то есть ячеек таблиц данных (регистров). А в ответе для указания размера данных используются уже байты. Значения адреса и количество элементов передаются в виде 16-битных слов, при этом старший байт передается первым.

Пойдем дальше обобщенного описания формата и проанализируем команды для конкретного устройства. В качестве этого устройства я использую сервопривод серии ASDA-A2, который для обмена данными использует как раз-таки протокол Modbus, причем поддерживает и Modbus RTU, и Modbus ASCII.

Пусть нам надо прочитать данные, расположенные по адресам 0x0200 и 0x0201, slave-устройства с адресом 0x01. Запрос master’а для Modbus RTU будет таким:

Протокол Modbus RTU, команда чтения, пример запроса.

Здесь у нас в запросе, указано, что мы хотим прочитать значение двух элементов (регистров). И ответ slave:

Команда чтения, пример ответа.

А в ответе уже видим, что прочитано 4 байта, поскольку значение одного регистра — это 2 байта (16 бит), а регистров у нас тоже 2. Таким образом, полученные значения:

  • Адрес 0x0200 — 0x00B1
  • Адрес 0x0201 — 0x1F40

CRC Low и CRC High — это соответственно младший и старший байты 16-ти битной контрольной суммы.

В Modbus ASCII все несколько иначе, запрос выглядит так (в кавычках указаны ASCII символы):

ASCII, команда чтения, пример запроса.

Ответ подчиненного:

Протокол Modbus ASCII, команда чтения, пример ответа.

И в первом и во втором случае запрашиваем значения одних и тех же регистров и, соответственно, получаем в ответ одинаковые данные.

При чтении битов регистров флагов или дискретных входов запрос выглядит точно также, а вот байты данных ответного сообщения иначе:

Чтение регистров флагов или дискретных входов.

Здесь одно значение флага или дискретного входа занимает один бит. И все эти биты упакованы в байты, а если число запрошенных флагов/входов не распределяется по байтам (не кратно 8), то «лишние» биты заполняются нулями. Как в последнем байте на этой схеме.

Переходим к записи. Для записи одного значения используются команды с кодами 0x05 и 0x06. Запрос в целом похож на уже рассмотренный (при чтении данных), только вместо количества элементов для чтения передаются данные, которые будут записаны:

Формат команды записи.

При записи значений флагов или дискретных входов число 0xFF00 соответствует включенному состоянию, 0x0000 — выключенному. В случае успешного выполнения запроса подчиненное устройство отправляет ведущему точную копию этого запроса.

С этим разобрались 👍 Но необходимо рассмотреть еще и случай записи нескольких значений (коды команд 0x10 и 0x0F). В общем виде формат запроса такой:

Modbus, запись нескольких элементов.

И, в обязательном порядке, рассмотрим практический пример. Пусть нам требуется записать значения 0x0BB8 и 0x0000 по адресам, начинающимся с 0x0112. Запрос и ответ Modbus RTU:

RTU, команда записи, пример запроса.
RTU, команда записи, пример ответа.

И для Modbus ASCII:

Протокол Modbus ASCII, команда записи, пример запроса.
Протокол Modbus ASCII, команда записи, пример ответа.