Top.Mail.Ru

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

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

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

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

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

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

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

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

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

В качестве физического уровня стандарт предусматривает использование интерфейсов RS-232, RS-422 и RS-485. Также существует реализация для 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:

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

А в ответе уже видим, что прочитано 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, команда записи, пример ответа.

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

Подписаться
Уведомить о
guest

16 комментариев
Старые
Новые
Межтекстовые Отзывы
Посмотреть все комментарии
Валерий
Валерий
2 лет назад

Спасибо!

Павел
Павел
2 лет назад

Николай, а будут практические примеры использования modbus rtu на stm32 ??

Павел
Павел
Ответ на комментарий  Aveal
2 лет назад

Надо расти дальше. Очень хочется реализовать)

Павел
Павел
Ответ на комментарий  Aveal
2 лет назад

Большая часть моего опыта работы с микроконтроллерами STM32 взята как раз с этого сайта) моих знаний маловато для публикации чего то стоящего .

Андрей
Андрей
Ответ на комментарий  Aveal
2 лет назад

Мне бы тоже хотелось посмотреть простейший пример для RTU Slave. Просто запрос от ПК к STM-ке через QModbus например. Чтение ,скажем , input reg с записанным заранее числом. Существующие примеры слишком запутанны для начинающих.

Павел
Павел
Ответ на комментарий  Aveal
2 лет назад

Я за вариант modbus rtu с использованием микросхемы sp3485

Андрей
Андрей
4 месяцев назад

Здравствуйте! Вопрос по модбасу: устройство на базе ATMega16, программа на основе freemodbus 1.5, отказывается связываться с ПК (RS485-USB) на скорости 1200 бод. На скоростях выше все работает. С чем это может быть связано? Может подскажете в какую сторону смотреть?

Андрей
Андрей
Ответ на комментарий  Aveal
4 месяцев назад

Проверил тестовой программкой. Данные с устройства на ПК через USART проходят на скорости 1200. Похоже проблема в библиотеке freemodbus

Андрей
Андрей
Ответ на комментарий  Андрей
4 месяцев назад

Нашел )) Единственная скорость из моего списка при которой задействован регистр UBRRH. В библиотеке только UBRRL применялся

16
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x