[Промышленное программирование, Программирование микроконтроллеров] Сервер Modbus TCP для Simatic S7-1200 / S7-1500
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Первая спецификация протокола Modbus была опубликова в 1979 году. Протокол предназначен для опроса подчиненных устройств по принципу «запрос-ответ». Modbus RTU (Remote Terminal Unit) работает по последовательному интерфейсу передачи данных (RS-232, RS-485, RS-422). Сегодня речь пойдет о немного измененном протоколе, Modbus TCP, работающий на прикладном уровне стека протоколов TCP/IP.Для начала посмотрим, как настраивается (программируется, если быть точнее) серверная часть. Modbus TCP Server — аналог Modbus RTU Slave, то есть, является подчиненным устройством. Это важно, не путайте. Сервер лишь отвечает на запросы, но не генерирует их.В данном примере применяется CPU S7-1516 с версией прошивки 2.6. Серия S7-1200 программируется аналогично.Для начала разместим в OB1 экземпляр функционального блока MB_SERVER (Instructions → Communications → Others → MODBUS TCP).
Далее необходимо сделать три вещи. Во-первых, подать что-нибудь на вход MB_HOLD_REG. Этот входной пин экземпляра ФБ должен содержать область памяти, которая выделяется на регистры хранения (holding registers).Небольшое отступление. В версиях библиотек Modbus TCP до 5.0 переменные «дискретные входы» (Discrete inputs), т.е. те двоичные переменные, которые можно только читать — это непосредственно все BOOL'евые переменные из области процесса %I. Coils, «катушки» — дискретные переменные, которые можно и читать, и записывать, это область %Q. Input Registers, «входные регистры» — это слова данных из области %I, точнее %IW. Грубо говоря, все дискретные переменные протокола Modbus и аналоговые входа являются переменными областей памяти I или Q. Это дает возможность читать непосредственно значение входов, а так же записывать значения дискретных выходов напрямую. С моей точки зрения нелогично отдавать возможность управлять дискретными выходами какой-нибудь сторонней системе, пусть даже и теоритическую, поскольку в зависимости от построения прикладного ПО контроллера, на эти выхода будет приходить «правильное» с точки зрения системы значение. Для того, чтобы ограничить клиентам Modbus TCP возможность прямого обращения к выходам, в экземпляре функционального блока есть несколько переменных.
Нас интересуют все переменные, которые начинаются на IB и QB. Указав в качестве значений QB_Count, QB_Read_Count и IB_Count нули, вместо значения по умолчанию 65535, мы запрещаем полностью чтение/запись входов/выходов напрямую.Для чтения/записи регистров хранения, в свою очередь, необходимо отдельно вручную задать область данных. Мой личный опыт показывает, что наиболее удобный способ — это структура, объявленная в глобальном блоке данных со стандартным (а не оптимизированным) доступом. Я сейчас продемонстрирую, «как надо», а под конец данной заметки мы «пройдемся по граблям» и посмотрим типичные ошибки, которые возникнут, если заполнить данное поле неправильно.В версии библиотеки, начиная с 5.0 (требуется прошивка 2.5 для S7-1500 и 4.2 для S7-1200) можно иначе переназначать входные дискреты, катушки и прочие переменные модбас. Например — завести все в битовые переменные глобального блока данных. Необходимо дополнительная конфигурация, которая описана в пункте «Access to data areas in DBs instead of direct access to MODBUS addresses as of version V5.0» встроенной справки.Итак, добавляем глобальный блок данных с «неоптимизированным» доступом в картинках.
Нажать Add new block
Выбрать «Data block» и дать ему осмысленное имя, далее нажать ОК
Вызвать свойства свежедобавленного блока данных
Найти в атрибутах блока галочку «Оптимизированный доступ», снять ее, подтвердить снятие и нажать ОК
Открыть в редакторе блок данных и создать в нем отдельную структуру
Заполнить поля этой структуры. Имеет смысл сразу в коментариях делать пометки о номере(адресе) регистра хранения. Откомпилировать блок данных.
Подать созданную структуру на входной пин MB_HOLD_REGВо-вторых, требуется создать и заполнить структуру типа TCON_IP_v4 или TCON_Configured. Данная структура содержит некоторые подробности для коммуникации контроллера. Лично я предпочитаю первый способ, он мне кажется более аскетичным, а кроме того — он не требует загрузки Hardware, в отличии от второго. В связи с тем, что структура относится к «настроечной» части протокола Modbus, ее можно разместить в уже созданном блоке данных (хотя, никто не запрещает объявить ее, где угодно).
Добавление структуры типа TCON_IP_v4Поле InterfaceID заполним чуть позже, а сейчас пройдемся по остальным полям.ID — внутренний идентификатор соединения. Допустимые значения от 1 до 4096. Каждое соединение (экземпляр блока MBSERVER, хотя на самом деле все немного сложнее). должно иметь свой уникальный идентификатор. Ставлю равным 1.ConnectionType — тип соединения. По умолчанию стоит 11 (0B в шестнадцатиричной системе): TCP. Его и оставляем.ActiveEstablished — оставляем false, в данном случае сервер не является инициатором связи, инициатором связи являютя клиенты.RemoteAddress — если оставить нули, то к серверу сможет подключиться любой клиент. Если задать удаленный IP-адрес конкретно, то к серверу может обратиться только один явно заданный клиент. Оставляем нули.RemotePort — оставляю ноль, не органичиваю и номер порта со стороны клиентаLocalPort — номер TCP порта, по которому будет отвечать сервер. В соответствии со старой-доброй традицией (и RFC) протокол Modbus TCP работает на порту 502 (а игра Doom — по порту 666, но это совсем другая история). Порт 502 я указываю явно.В итоге получаем следующее:
Осталось задать лишь ID интерфейса. Это присвоение я делаю в программное коде, разместив network с присвоением (MOVE) до вызова блока Modbus. Идентификаторы интерфейсов уже созданы в Step 7 автоматически, необходимо лишь найти нужную переменную. В моем случае Modbus будет работать на интерфейсе X1. Его я и нахожу в списке переменных, выпадающем автоматически.
Можно так же подсмотреть название нужной переменной, зайдя в аппаратную конфигурацию, выбрав нужный интерфейс и вкладку System Constants этого интерфейса. Привожу скриншот всего экрана, чтобы было понятно, где искать.
Можно так же просто указать значение 64 для переменной "ModbusData".CONNECT_Struct.InterfaceIdДалее подаем на вход CONNECT заполненную структуру и получаем следующую программу:
И, наконец, в третьих, не забываем про переменные экземпляра MB_SERVER_DB. Я о них говорил выше, описание этих переменных можно почитать во встроенной справке. Если их не трогать, то обмен, все равно, будет работать, это уже вопрос «доводки» обмена и доступа ко «входам» и «выходам».Компилируем программу, загружаем ее в контроллер и выходим Online:
Статус 7002 не означает ошибку, он говорит о том, что соединиение устанавливается. Обязательно почитайте описание возможных значений поля STATUS, пригодится. Перед тем, как начать читать/записывать данные при помощи стороннего Modbus-клиента, дадим переменным ненулевые значения (разумеется, мои любимые — «число зверя» и «три топора»).
В качестве Modbus-клиента можно использовать любой проверенный софт. Главное — правильно сформировать запрос со стороны клиента. В нашем случае объявлено всего 5 регистров хранения, и если запросить 10, то сервер Modbus вернет ошибку, и будет прав. Второй немаловажный момент — не забывайте про порядок байт в слове: если little endian отображать, как big endian, или наоборот, то вместо разумных чисел на экране будет ерунда. На данном скриншоте клиент настроен на опрос 5 регистров хранения, представление данных, как float, настроено «переворачивание» байт в словах:
Чуть выше я говорил, что дискретные выхода контроллера (точнее, биты области %Q) — это и есть «койлы» с точки зрения протокола Modbus, и что при настройках по умолчанию клиент получит возможность как читать сигналы напрямую, так и записывать их. Давайте в этом убедимся. Для начала на модуле дискретных выходов я объявляю переменную, для дальнейшего удобства:
Нулевой бит восьмого байта выходной области. Номер 64, если считать с нуля (8 * 8 + 0 = 64). Задам в контроллере значение «истина» и прочитаю в Modbus-клиенте:
Вижу значение «истина» (читаю один койл с начальным смещением 64). Изменю это значение на «ложь» со стороны modbus:
Значение, разумеется, так же изменилось и в Step 7, и в контроллере, и на выходе модуля (это одно и то же):
Как я уже говорил, нехорошо давать прямой доступ к управлению всяким сторонним системам. Для формирования выходных сигналов есть внутренняя логика программы, продуманные и прописанные алгоритмы управления, защит и блокировок. Поэтому снизим до нуля количество доступных к записи «койлов» (байт выходного простраства, если точнее):
После этого изменения в блоке данных (прямо в online, без перезаливки и перезагрузки контроллера) клиент протокола modbus в ответ на требование записи «катушки» показал табличку «Illegal data address», а именно такое сообщение и вернул сервер. Дополнительную информацию читаем в справке: Restriction of read access to process images as of version V5.0.Теперь давайте посмотрим, что происходит при некорректном назначении области памяти от регистров хранения. В первую очередь достаем встроенную справку Step 7 и читаем:
В качестве регистров хранения применять глобальный блок данных с оптимизированным доступом или битовую область. И вот тут очень интересно. Потому что справка в части «MBHOLDREG parameter» выглядит следующим образом:
Посеридине в качестве примера приведен глобальный блок данных со стандартным доступом. Проведем несколько экспериментов и посмотрим, что из этого получится.Эксперимент №1. Регистры хранения — это структура в блоке данных с оптимизированным доступом (почти, как сделано в этом примере). В этом случае получаем ошибку 8187 : The MBHOLD_REG parameter has an invalid pointer. Data area is too small.
Эксперимент №2. Массив переменных типа WORD, объявленный в «оптимизированном» блоке данных. Работает, со стороны клиента переменные меняются, ошибок нет.
Эксперимент №3. Меркерная область. Работает, с клиента удалось внести значения, ошибок нет.
С моей точки зрения, в документации недостаточно ясно. Должно быть написано «используйте блок данных со стандартным доступом или битовую (меркерную) память», а не «оптимизированным доступом». В случае оптимизированного доступа вполне подойдут массивы слов. И с моей точки зрения самым удобным способом является способ, описанный в изначальном примере. Эксперимент №2 в принципе тоже работоспособен (и тому есть объяснение), но с моей точки зрения неудобен для работы.В следующий раз мы займемся клиентом Modbus TCP.
===========
Источник:
habr.com
===========
Похожие новости:
- [Разработка под Linux, Программирование микроконтроллеров, Схемотехника, Производство и разработка электроники] WSN-LTE шлюз на CC1310 и WP8548. Часть 1
- [Программирование, Системное программирование, Промышленное программирование, Rust] Так ли токсичен синтаксис Rust?
- [Промышленное программирование, Программирование микроконтроллеров] OPC UA для CPU S7-1200 (FW4.4). Настройка сервера
- [Промышленное программирование, SCADA] Веселые уроки WinCC OA. Установка WinCC OA под Debian и перенос прикладного проекта
- [Программирование микроконтроллеров, Электроника для начинающих] STM32 абстрагируемся от регистров CMSIS при настройке GPIO
- [Программирование, C, Программирование микроконтроллеров] К вопросу о сложении или как я нашел ошибку в gcc (на самом деле нет)
- [Промышленное программирование, SCADA] Самоучитель по WinCC OA. Часть 9. Control-скрипт. Небыстро, но правильно. Полноценный запуск ui
- [Промышленное программирование] Квалификация инструментов для разработки встраиваемого ПО
- [Реверс-инжиниринг, Программирование микроконтроллеров, Прототипирование, Интернет вещей, DIY или Сделай сам] Подключаемся к станку по изготовлению профлиста и считываем из него прокатную длинну
- [Тестирование IT-систем, Программирование, Java, IT-стандарты, Промышленное программирование] Принцип слоеного теста
Теги для поиска: #_promyshlennoe_programmirovanie (Промышленное программирование), #_programmirovanie_mikrokontrollerov (Программирование микроконтроллеров), #_siemens, #_simatic, #_s7, #_s71200, #_modbus, #_communication, #_promyshlennoe_programmirovanie (
Промышленное программирование
), #_programmirovanie_mikrokontrollerov (
Программирование микроконтроллеров
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 19:21
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Первая спецификация протокола Modbus была опубликова в 1979 году. Протокол предназначен для опроса подчиненных устройств по принципу «запрос-ответ». Modbus RTU (Remote Terminal Unit) работает по последовательному интерфейсу передачи данных (RS-232, RS-485, RS-422). Сегодня речь пойдет о немного измененном протоколе, Modbus TCP, работающий на прикладном уровне стека протоколов TCP/IP.Для начала посмотрим, как настраивается (программируется, если быть точнее) серверная часть. Modbus TCP Server — аналог Modbus RTU Slave, то есть, является подчиненным устройством. Это важно, не путайте. Сервер лишь отвечает на запросы, но не генерирует их.В данном примере применяется CPU S7-1516 с версией прошивки 2.6. Серия S7-1200 программируется аналогично.Для начала разместим в OB1 экземпляр функционального блока MB_SERVER (Instructions → Communications → Others → MODBUS TCP). Далее необходимо сделать три вещи. Во-первых, подать что-нибудь на вход MB_HOLD_REG. Этот входной пин экземпляра ФБ должен содержать область памяти, которая выделяется на регистры хранения (holding registers).Небольшое отступление. В версиях библиотек Modbus TCP до 5.0 переменные «дискретные входы» (Discrete inputs), т.е. те двоичные переменные, которые можно только читать — это непосредственно все BOOL'евые переменные из области процесса %I. Coils, «катушки» — дискретные переменные, которые можно и читать, и записывать, это область %Q. Input Registers, «входные регистры» — это слова данных из области %I, точнее %IW. Грубо говоря, все дискретные переменные протокола Modbus и аналоговые входа являются переменными областей памяти I или Q. Это дает возможность читать непосредственно значение входов, а так же записывать значения дискретных выходов напрямую. С моей точки зрения нелогично отдавать возможность управлять дискретными выходами какой-нибудь сторонней системе, пусть даже и теоритическую, поскольку в зависимости от построения прикладного ПО контроллера, на эти выхода будет приходить «правильное» с точки зрения системы значение. Для того, чтобы ограничить клиентам Modbus TCP возможность прямого обращения к выходам, в экземпляре функционального блока есть несколько переменных. Нас интересуют все переменные, которые начинаются на IB и QB. Указав в качестве значений QB_Count, QB_Read_Count и IB_Count нули, вместо значения по умолчанию 65535, мы запрещаем полностью чтение/запись входов/выходов напрямую.Для чтения/записи регистров хранения, в свою очередь, необходимо отдельно вручную задать область данных. Мой личный опыт показывает, что наиболее удобный способ — это структура, объявленная в глобальном блоке данных со стандартным (а не оптимизированным) доступом. Я сейчас продемонстрирую, «как надо», а под конец данной заметки мы «пройдемся по граблям» и посмотрим типичные ошибки, которые возникнут, если заполнить данное поле неправильно.В версии библиотеки, начиная с 5.0 (требуется прошивка 2.5 для S7-1500 и 4.2 для S7-1200) можно иначе переназначать входные дискреты, катушки и прочие переменные модбас. Например — завести все в битовые переменные глобального блока данных. Необходимо дополнительная конфигурация, которая описана в пункте «Access to data areas in DBs instead of direct access to MODBUS addresses as of version V5.0» встроенной справки.Итак, добавляем глобальный блок данных с «неоптимизированным» доступом в картинках. Нажать Add new block Выбрать «Data block» и дать ему осмысленное имя, далее нажать ОК Вызвать свойства свежедобавленного блока данных Найти в атрибутах блока галочку «Оптимизированный доступ», снять ее, подтвердить снятие и нажать ОК Открыть в редакторе блок данных и создать в нем отдельную структуру Заполнить поля этой структуры. Имеет смысл сразу в коментариях делать пометки о номере(адресе) регистра хранения. Откомпилировать блок данных. Подать созданную структуру на входной пин MB_HOLD_REGВо-вторых, требуется создать и заполнить структуру типа TCON_IP_v4 или TCON_Configured. Данная структура содержит некоторые подробности для коммуникации контроллера. Лично я предпочитаю первый способ, он мне кажется более аскетичным, а кроме того — он не требует загрузки Hardware, в отличии от второго. В связи с тем, что структура относится к «настроечной» части протокола Modbus, ее можно разместить в уже созданном блоке данных (хотя, никто не запрещает объявить ее, где угодно). Добавление структуры типа TCON_IP_v4Поле InterfaceID заполним чуть позже, а сейчас пройдемся по остальным полям.ID — внутренний идентификатор соединения. Допустимые значения от 1 до 4096. Каждое соединение (экземпляр блока MBSERVER, хотя на самом деле все немного сложнее). должно иметь свой уникальный идентификатор. Ставлю равным 1.ConnectionType — тип соединения. По умолчанию стоит 11 (0B в шестнадцатиричной системе): TCP. Его и оставляем.ActiveEstablished — оставляем false, в данном случае сервер не является инициатором связи, инициатором связи являютя клиенты.RemoteAddress — если оставить нули, то к серверу сможет подключиться любой клиент. Если задать удаленный IP-адрес конкретно, то к серверу может обратиться только один явно заданный клиент. Оставляем нули.RemotePort — оставляю ноль, не органичиваю и номер порта со стороны клиентаLocalPort — номер TCP порта, по которому будет отвечать сервер. В соответствии со старой-доброй традицией (и RFC) протокол Modbus TCP работает на порту 502 (а игра Doom — по порту 666, но это совсем другая история). Порт 502 я указываю явно.В итоге получаем следующее: Осталось задать лишь ID интерфейса. Это присвоение я делаю в программное коде, разместив network с присвоением (MOVE) до вызова блока Modbus. Идентификаторы интерфейсов уже созданы в Step 7 автоматически, необходимо лишь найти нужную переменную. В моем случае Modbus будет работать на интерфейсе X1. Его я и нахожу в списке переменных, выпадающем автоматически. Можно так же подсмотреть название нужной переменной, зайдя в аппаратную конфигурацию, выбрав нужный интерфейс и вкладку System Constants этого интерфейса. Привожу скриншот всего экрана, чтобы было понятно, где искать. Можно так же просто указать значение 64 для переменной "ModbusData".CONNECT_Struct.InterfaceIdДалее подаем на вход CONNECT заполненную структуру и получаем следующую программу: И, наконец, в третьих, не забываем про переменные экземпляра MB_SERVER_DB. Я о них говорил выше, описание этих переменных можно почитать во встроенной справке. Если их не трогать, то обмен, все равно, будет работать, это уже вопрос «доводки» обмена и доступа ко «входам» и «выходам».Компилируем программу, загружаем ее в контроллер и выходим Online: Статус 7002 не означает ошибку, он говорит о том, что соединиение устанавливается. Обязательно почитайте описание возможных значений поля STATUS, пригодится. Перед тем, как начать читать/записывать данные при помощи стороннего Modbus-клиента, дадим переменным ненулевые значения (разумеется, мои любимые — «число зверя» и «три топора»). В качестве Modbus-клиента можно использовать любой проверенный софт. Главное — правильно сформировать запрос со стороны клиента. В нашем случае объявлено всего 5 регистров хранения, и если запросить 10, то сервер Modbus вернет ошибку, и будет прав. Второй немаловажный момент — не забывайте про порядок байт в слове: если little endian отображать, как big endian, или наоборот, то вместо разумных чисел на экране будет ерунда. На данном скриншоте клиент настроен на опрос 5 регистров хранения, представление данных, как float, настроено «переворачивание» байт в словах: Чуть выше я говорил, что дискретные выхода контроллера (точнее, биты области %Q) — это и есть «койлы» с точки зрения протокола Modbus, и что при настройках по умолчанию клиент получит возможность как читать сигналы напрямую, так и записывать их. Давайте в этом убедимся. Для начала на модуле дискретных выходов я объявляю переменную, для дальнейшего удобства: Нулевой бит восьмого байта выходной области. Номер 64, если считать с нуля (8 * 8 + 0 = 64). Задам в контроллере значение «истина» и прочитаю в Modbus-клиенте: Вижу значение «истина» (читаю один койл с начальным смещением 64). Изменю это значение на «ложь» со стороны modbus: Значение, разумеется, так же изменилось и в Step 7, и в контроллере, и на выходе модуля (это одно и то же): Как я уже говорил, нехорошо давать прямой доступ к управлению всяким сторонним системам. Для формирования выходных сигналов есть внутренняя логика программы, продуманные и прописанные алгоритмы управления, защит и блокировок. Поэтому снизим до нуля количество доступных к записи «койлов» (байт выходного простраства, если точнее): После этого изменения в блоке данных (прямо в online, без перезаливки и перезагрузки контроллера) клиент протокола modbus в ответ на требование записи «катушки» показал табличку «Illegal data address», а именно такое сообщение и вернул сервер. Дополнительную информацию читаем в справке: Restriction of read access to process images as of version V5.0.Теперь давайте посмотрим, что происходит при некорректном назначении области памяти от регистров хранения. В первую очередь достаем встроенную справку Step 7 и читаем: В качестве регистров хранения применять глобальный блок данных с оптимизированным доступом или битовую область. И вот тут очень интересно. Потому что справка в части «MBHOLDREG parameter» выглядит следующим образом: Посеридине в качестве примера приведен глобальный блок данных со стандартным доступом. Проведем несколько экспериментов и посмотрим, что из этого получится.Эксперимент №1. Регистры хранения — это структура в блоке данных с оптимизированным доступом (почти, как сделано в этом примере). В этом случае получаем ошибку 8187 : The MBHOLD_REG parameter has an invalid pointer. Data area is too small. Эксперимент №2. Массив переменных типа WORD, объявленный в «оптимизированном» блоке данных. Работает, со стороны клиента переменные меняются, ошибок нет. Эксперимент №3. Меркерная область. Работает, с клиента удалось внести значения, ошибок нет. С моей точки зрения, в документации недостаточно ясно. Должно быть написано «используйте блок данных со стандартным доступом или битовую (меркерную) память», а не «оптимизированным доступом». В случае оптимизированного доступа вполне подойдут массивы слов. И с моей точки зрения самым удобным способом является способ, описанный в изначальном примере. Эксперимент №2 в принципе тоже работоспособен (и тому есть объяснение), но с моей точки зрения неудобен для работы.В следующий раз мы займемся клиентом Modbus TCP. =========== Источник: habr.com =========== Похожие новости:
Промышленное программирование ), #_programmirovanie_mikrokontrollerov ( Программирование микроконтроллеров ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 19:21
Часовой пояс: UTC + 5