А не вспомнить ли нам Модбас? Или как общаются устройства.

Modbus пока что все еще является одним из самых распространенных и самое главное самых доступных промышленных протоколов, тк почти на каждом устройстве есть COM-порт, а порог входа (понимание как работает) у этого протокола минимальный из тех, что я встречал.

Если заглянуть в историю, то в 1979 году разработчиками ПЛК линейки Modicon (на данный момент хозяин товарного знака «великий» Schneider Electric) – и, собственно, название протокола означает «Modicon Bus». Собственно на данный момент протокол можно сказать стал самодостаточным, т.к. в 2004г Schneider Electric передала права на Modbus некоммерческой организации Modbus IDA (сайт http://www.modbus.org/).

Физический уровень
Физический уровень
  • RS-232/422/485 — последовательные интерфейсы, широко распространенные в промышленности. Интерфейсы RS-422/485 обеспечивают дальность сигнала до 1200 метров. Используются протоколы Modbus RTU/ASCII
  • Сети TCP/IP — физическим каналом передачи данных могут любые ethernet-интерфейсы. Используется протокол Modbus TCP

Ну что ж, начнем с того, что есть понятие шины, интерфейса, протокола, если не мучать мозг сложными определениями, а просто сравнить их, то под Шиной понимается физическая возможность передачи сигнала, то есть только «провода» (в нашем случае, хотя это может быть и оптика где-то в другом способе), но абсолютно никак не характеризуются другие характеристики, которые уже описывает интерфейс.

То есть мы говорим например двухпроводная шина данных, когда вспоминаем, что для связи по I²C (последовательная асимметричная шина для связи между интегральными схемами внутри электронных приборов) требуется два провода - две двунаправленные линии связи (SDA и SCL), которая применяется для соединения низкоскоростных периферийных компонентов с процессорами и микроконтроллерами. Хотя в промышленности, зашумленной наводками более перспективно смотрится шина, на которой основан интерфейс RS-485, основанный на двухпроводной двунаправленной полудуплексной (пока один говорит, другой слушает) дифференциальной передаче данных, который тоже базируется на двухпроводной шине. Аналог в виде RS-422 не так популярен в силу большего количества проводов/сигналов. Ну а TCP/IP имея ряд преимуществ, все же не так распространен в силу того, что на сам TCP/IP требуется больше ресурсов, что делает изделие более дорогим, хотя сейчас он стал встречаться гораздо чаще, чем раньше.

Тут кстати стоит заметить, что часто для передачи данных по RS-485 на ПЛК можно встретить кроме стандартных двух основных контактов для подключения сигнала (+ и - или А и В) еще и «землю» (GND, но не стоит ее путать с заземлением, это опорный потенциал нуля для микросхем, которые организуют передачу данных), так вот этот контакт не обязателен, т.к. для организации RS-485 по классике достаточно только двух проводов, но по факту иногда (не всегда) на выходе прибора устанавливают не специализированные микросхемы с гальванической развязкой, а более дешевые аналоги без развязки, которые могут очень неприятно подвести в самый нужный момент, и чтобы этого не произошло, лучше этот проводник использовать. Назначение у него достаточно просто объясняется - он предназначен для того, чтобы уравнять потенциалы «земли», тк при отсутствии третьего провода утечки изоляции могут привести к произвольно большим перепадам между «нулем» одного прибора и «нулем» другого, что может привести к потере информации, передаваемой по сети, или возможному выходу из строя оборудования. При соединении между собой «нулей» приборов, есть вероятность, что по третьему проводу потечет большой ток поэтому некоторые производители рекомендуют соединять точки не напрямую, а через резистор например 100 Ом.

Вернемся к исходной теме ближе: RS-485стандарт двухпроводной дифференциальной передачи данных, который является основой для организации протокола Modbus.

Некоторые особенности интерфейса:

  • Двунаправленная полудуплексная передача данных. Поток последовательных данных передаётся одновременно только в одну сторону, для передачи в другую сторону требуется переключение приёмопередатчика.
  • Симметричный канал связи. Для приёма и передачи данных используются два равнозначных сигнальных провода, которые обозначаются латинскими буквами «А» и «В».
  • Дифференциальный (балансный) способ передачи данных. При передаче «1» разность потенциалов между «А» и «В» положительная, при передаче «0» — отрицательная.

Так мы подошли к подведению итога сравнения протокола с интерфейсом: интерфейс шины и протокол отличаются тем, что интерфейс — это совокупность средств и правил взаимодействия между элементами системы, который в том числе определяет уровни сигналов, понимание «0» и «1», форматы данных и методы передачи команд, часто включающий в себя и определения шины для передачи данных, а протокол — это набор правил, по которым передаются данные. Не будем сильно вникать в описание интерфейса (если конечно кому-то интересно, можете поглядеть здесь), а перейдем напрямую к Modbus. То есть если мы слышим о настройках последовательной связи типа 9600бит/сек (это речь про скорость передачи, которая определяет, с какой частотой будут следовать биты), контроль четности (и вообще контроль за работой порта), о количестве бит данных в условном «байте», а также о стартовых и стоповых битах, то речь будет идти об интерфейсе (в нашем случае я буду базироваться на RS-485, как вы поняли), а не о протоколе Modbus, он это не регламентирует, ну разве что чуть-чуть, за счет того, что обычно для режима RTU количество бит данных 8, а для ASCII - 7 (если используется еще и бит контроля четности, то обычно его тоже принято добавлять к битам информации, но в чистом виде это видно в основном, когда пытаются настроить работу порта на микроконтроллере типа STM32 или ESP32 и др., на ПЛК обычно видим стандартные 7 и 8 бит). Итак что же за ASCII и RTU? Это вариации реализации передачи данных, которые выбираются пользователем, они уже напрямую относятся к Modbus.

Modbus ASCII

Данные кодируются символами из таблицы ASCII и передаются в шестнадцатеричном формате.

Тут конечно же стоит объяснить, что это за переход такой: все просто допустим надо передать два байта информации, это в шестнадцатиричном виде для числа 6814 будет число 1A9E, берем каждый символ и переводим по таблице в числа, так для 1 в шестнадцатиричном варианте будет число 31 (49 в десятичном), это значение и передается вместо «1», далее идет A, это число 41 в шестнадцатиричном виде (65 в десятичном), ну и так далее, порядок передачи определен, но опишу я его ниже при разборе протокола.

Начало каждого пакета обозначается символом двоеточия (ну передается конечно же число, которое по таблице ASCII соответствует этому символу - 0x3A или 58), а конец — символами возврата каретки и переноса строки. Это позволяет использовать протокол на линиях с большими задержками и оборудовании с менее точными таймерами, но при этом накладные расходы при передаче конечно же выше. В конце следует контрольная сумма LRC и суффикс (два символа).

Modbus RTU

В протоколе Modbus RTU данные кодируются в двоичный формат, и разделителем пакетов служит временной интервал. В конце следует контрольная сумма, которая считается намного сложнее, чем LRC в ASCII, там и полиномы таблицы, а название у нее CRC, алгоритм найти в интернете не проблема, как и онлайн калькулятора для проверки. Этот протокол критичен к задержкам и не может работать, например, на модемных линиях. При этом, накладные расходы на передачу данных меньше, чем в Modbus ASCII, так как длина сообщений меньше (компактность).

Modbus TCP

Структура пакетов схожа с Modbus RTU, данные также кодируются в двоичный формат, и упаковываются в обычный TCP-пакет, для передачи по IP-сетям. Проверка целостности, используемая в Modbus RTU, не применяется, так как TCP уже имеет собственный механизм контроля целостности.

Формат пакета

Формат пакета данных Modbus
Формат пакета данных Modbus

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

ADU (Application Data Unit)

— пакет Modbus целиком, со всеми заголовками, PDU, контрольной суммой, адресом и маркерами. Отличается, в зависимости от реализации протокола.

А не вспомнить ли нам Модбас? Или как общаются устройства., image #3
Пакет сообщения Modbus подробно
1 of 2

Как мы видим основу составляет последовательность байт, которая определяет адрес слейва, код функции (!очень важный момент!, потом о нем будет очень много подробнее) и последовательность байт, которая определяется кодом функции, затем контрольная сумма.

PDU (protocol data unit)

— основная часть пакета, одинаковая для всех реализаций протокола. Содержит сам payload.

Адрес устройства

— адрес получателя, то есть slave-устройства. В одном сегменте Modbus-сети могут находится до 247 устройств (какие то числа зарезервированы для коротких сообщений). Только slave-устройства имеют различающиеся адреса, master-устройство не имеет адреса (хотя это не мешает иметь устройству свой адрес, он скорее всего относится к другому функционалу, например для связи с программатором). Адрес «0» используется для широковещательных запросов от master, при этом, slave-устройства не могут отвечать на эти широковещательные пакеты.

Контрольная сумма (LRC/CRC)

— алгоритмы проверки целостности пакетов. В Мodbus RTU и ASCII используется 2 байта контрольной суммы. В Modbus RTU применяется алгоритм CRC16, в Modbus ASCII — более простой и менее надежный LRC8. В Modbus TCP контрольная сумма не добавляется в ADU, так как целостность проверяется на уровне TCP.

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

Регистры и функции Modbus

В упрощенном виде, структура запросов Modbus состоит из кода функции (чтение/запись), и данных, которые нужно считать или записать. При этом, коды функции различаются для разных типов данных. Разберем, какие бывают регистры Modbus, и функции для работы с ними. Точнее как создатель протокола понимал, потому как в текущем «бардаке» гораздо легче работать непосредственно с кодами функций нежели с регистрами. Но бывает и такое, что как например в Сименсе или в панелях Винтек, нет возможности напрямую использовать код функции, а приходится хошь-не-хошь понимать что за регистры такие от нас требуют, хотя в слейв устройстве про них никакой речи нет, а предлагаются коды функций. Вот такой бардак…

Регистры в понимании протокола Modbus
Регистры в понимании протокола Modbus
  • Discrete Inputs — дискретные входы устройства, доступны только для чтения. Диапазон адресов регистров: с 10001 по 19999. Имеют функцию «0x02» — чтение группы регистров. При этом чтение происходит НЕ поштучно (0 или 1 будет передано НЕ целым байтом, а битом в слове ответа, каждый бит в слове ответа отвечает за свой байт со смещением, по мере заполнения байта биты перемещаются в следующий байт).
  • Coils — дискретные выходы устройства, или внутренние значения. Доступны для чтения и записи. Диапазон адресов регистров: с 20001 по 29999. Имеет функции: «01» — чтения группы регистров, «05» — запись одного регистра, «15» — запись группы регистров
  • Input Registers — 16-битные входы устройства. Доступны только для чтения. Диапазон адресов регистров: с 30001 по 39999. Имеют функцию: «04» — чтение группы регистров
  • Holding Registers — 16-битные выходы устройства, либо внутренние значения. Доступны для чтения и записи. Диапазон адресов регистров: с 40001 по 49999.

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

Как мы видим области памяти по протоколу Modbus совместно с выбором действия (чтение или запись) четко соответствуют кодам функций.

Но самое главное что должен был заметить внимательный читатель, что регистры начинаются не с нулевого адреса, а с 1 (хххх1), но при этом протокол модбаса работая со смещениями отправляет для регистра например номером 40001 адрес равный 40001 - 40001, то есть адрес будет в самом пакете 0. Это очень важно, тк часто это смещение в 1 дает ошибки, но об этом чуть ниже, а сейчас немного практики. Еще немного по другому опишу, потому как проблема очень часто проявляет себя: при задании адреса номером регистра первым символом адреса является идентификатор области памяти, о котором написано и выше и ниже, следующие же 4 символа содержат адрес регистра в DEC в диапазоне 0001…9999, но как следует из документации – адресация регистров ведется с единицы (а не с нуля, как при физической адресации). Т.е. «регистр с адресом 30001» в данном случае будет означать «Input-регистр с адресом 0».

Команду MODBUS можно настроить двумя основными способами – либо в явном виде указав код функции, либо указав область памяти (регистр). При указании в явном виде всё понятно – пользователь просто выбирает из списка нужную функцию. Такой способ, к примеру, используется в среде CODESYS V3.5:

А не вспомнить ли нам Модбас? Или как общаются устройства., image #6

Но, например, в ПО EasyBuilder, с помощью которого конфигурируются панели оператора Weintek, нет возможности выбрать код функции в явном виде – вместо этого в настройках элемента визуализации пользователь видит вот такой список обозначений:

А не вспомнить ли нам Модбас? Или как общаются устройства., image #7

Можно подумать, что 0x, 1x и т.д. – это и есть коды функций. Но это не так - это ошибка. В данном случае, 0x … 6x – это идентификаторы областей памяти Modbus, то есть как бы нам намекают что мы вводим номер регистра, который начинается с 4х например. Но и тут есть заковырка, видите на картинке выше написано Zero-based Addressing, это означает, что смещение, про которое я говорил выше не действует, и адрес, введенный в поле прямиком полетит в пакет, никакие действия с вычитанием не будут исполнены. А вот если будет выбран протокол без этого указания, ждите того, что из вашего адреса будет вычтена единица.

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

А не вспомнить ли нам Модбас? Или как общаются устройства., image #8

2x отстутствует, тк при работе с ПЛК первых поколений этот идентификатор использовался для доступа к памяти барабанного командоаппарата, ну и естественно сейчас потребность в командоаппарате отпала, и вместе с ним отказались и от 2х.

Тут еще не описаны идентификаторы 5x и 6x, но тут все просто (хотя нифига не просто, они задолбали и больше запутали), поскольку для областей Coils и Holding-регистров доступно по 2 функции записи (одного и нескольких бит/регистров соответственно – 0x05/0x0F для Coils и 0x05/0x10 для Holding-регистров), то Weintek предоставляет специальные идентификаторы 0x_multi_coils (для функции записи группы бит 0x0F) и 6x (для функции записи Holding-регистров 0x06) и соответственно уже для 4х у нас функция 0х06 не поддерживается, а остается только 0х10. Таким образом, это предоставляет возможность пользователю выбирать все нужные комбинации для функций чтения/записи индивидуально. То есть если принципиально нужно работать с регистрами например ПЧ и написано, что запись в них не поддерживает команду 0х10, но требует использовать 0х06, то нужно выбирать не 4х, а 6х, как для чтения, так и для записи. Ну или наоборот, если некоторые slave-устройства не поддерживают функцию 0x06 и требуют использования функции 0x10 даже для записи одного регистра (сложно сказать зачем?), но факт, то выбирается 4x.

Осталось рассказать об идентификаторе 5x – как видно из документации, он соответствует области 4x с «переставленным» порядком регистров – то есть если в памяти slave-устройства лежит значение 0xAABBCCDD, то при использовании идентификатора 4x мы получим на панели именно 0xAABBCCDD, а при использовании 5x – значение 0xDDCCBBAA (с инвертированным порядком регистров). Эта возможность полезна, так как в разных устройствах данные могут храниться с разным порядком регистров, а протокол Modbus, как мы уже говорили, не специфицирует типы данных (иначе, соответственно, в стандарте был бы жестко определен порядок регистров при передаче значений различных типов).

Ну и еще одна из проблем система счисления, в которой записаны адреса. В повседневной жизни мы в основном используем десятичную систему (DEC), но в системах автоматизации часто используется шестнадцатеричная (HEX). Иногда ПО поддерживает ввод адреса в разных системах счисления – например, в CODESYS V3.5 адрес регистра можно указать как в DEC, так и в HEX, причем в HEX двумя способами – с «общепринятым» префиксом 0x и «мэковским» (определенным в стандарте МЭК 61131-3) 16#.

Ну чтож, конечно этой информации недостаточно, чтобы вы могли написать программу под микроконтроллер типа STM32, но вполне достаточно, чтобы понять как настроить связь в панели оператора или ПЛК типа S7-1200 и уж тем более в DVP от дельты, там адреса задаются в чистом виде, а код функции либо заложен в инструкции (MODRD код 0х03, MODWR код 0х06) либо подбирается в параметре, указываемом в инструкции как входной, по аналогии с дельтовской MODRW и у FX3 от Mitshubish это ADPRW в параметре задается код функции, а в зависимости от этого кода другой параметр содержит указатель на область памяти с payload, которая должна быть заполнена или подготовлена как раз под введенный код функции, правильность лежит на программисте ПЛК.

Вот кстати как это выглядит на дельте (без учета настройки порта):

А не вспомнить ли нам Модбас? Или как общаются устройства., image #9

Достаточно выставить в единицу бит М1122, запустить команду MODRD, указать адрес слейва и адрес регистра для чтения (тут не путаться, это не адрес 40001, он попросту не влезет в размер регистра области D ПЛК, а именно адрес, что будет помещен в команду модбас, уже со смещением, то есть с вычитанием цифры отвечающей за область памяти и вычитанием 1, тк здесь у дельты адреса начинаются с нуля, хотя большинство производителей придерживаются правила указывать адрес уже без этого смещения, и правильно делают, хотя и разводят бардак с точки зрения спецификации Модбас). Остается только взять результат из специальной области памяти, в данном случае два регистра потребовались потому, как в ПЛК был включен режим 8-бит, когда каждый новый байт ответа помещается в свой регистр. Для команд типа MODRW область памяти, куда будет помещен результат вообще указывается в явном виде во входных параметрах объявления команды, что еще больше упрощает работу с ней. И по поводу чек суммы можно не беспокоиться, если конечно не пытаетесь реализовать свободный протокол, и такие команды есть в ПЛК, у дельты и у Mitshubish для этого одинаковое название - RS.

103 views·1 share