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

Продолжаем подробно разбирать стандарты передачи данных. И героем сегодняшней статьи станет протокол Modbus! Впервые спецификация протокола Modbus была опубликована ни много ни мало, а в 1979 году, но до сих пор не утратила своей актуальности! Итак, приступаем…

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

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

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

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

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

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

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

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

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

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

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

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

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

Пример сети Modbus.

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

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

Modbus RTU RS-232 RS-422 RS-485

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

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

Modbus ASCII RS-232 RS-422 RS-485

В данном случае для обмена данными используются исключительно ASCII символы. И в отличие от Modbus RTU начало и конец сообщений определяются специальными символами.

Начало пакета – ASCII символ “:” (0x3A), конец – “CR + LF” (0x0D + 0x0A).

Modbus TCP TCP/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:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

И для Modbus ASCII:

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

Довольно большая получилась статья, но очень уж хотелось затронуть все по максимуму… И, на самом деле, некоторые моменты остались раскрытыми до конца 🙂 Например, расчет контрольной суммы для Modbus RTU и Modbus ASCII, алгоритмы там абсолютно разные. Так что в ближайшее время будет еще как минимум одна статья с примером программы для расчета LRC и CRC, оставайтесь на связи!

Поделиться!

Подписаться
Уведомление о
guest
0 Комментарий
Inline Feedbacks
View all comments

Присоединяйтесь!

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Сентябрь 2020
Пн Вт Ср Чт Пт Сб Вс
 123456
78910111213
14151617181920
21222324252627
282930  

© 2013-2020 MicroTechnics.ru