среда, 4 мая 2022 г.

Реализация RS-триггера (Latching Relay) на Siemens LOGO! для сети Ethernet

Сегодняшняя история про Siemens LOGO!, а, как всем известно, любая история про Siemens LOGO! - это всегда небольшой танец с бубном. Вот и в этот раз понадобилось, казалось бы, совершить простейшее действие, а оно оказалось не таким уж и простым...

Общие сведения

 
Но начнём с общей информации. Как вообще работает коммуникация LOGO! с панелями оператора? Смотрите, есть такие способы коннектиться с LOGO!:

1. Через драйвер, который в панелях Siemens так и называется "LOGO!". Этот драйвер есть на новых панелях оператора, присутствующих в WinCC в составе TIA Portal'a: KTP, TP и др. Есть этот драйвер и на WinCC Flexible Smart. Но этого драйвера нет ни в новых WinCC Runtime, ни WinCC Flexible Runtime.

2. Через драйвер, который называется "SIMATIC S7 200". Внезапно драйвер для контроллера S7-200 подошёл к LOGO. Причём, он не просто подошёл, а полностью идентичен по части работы. Так что если для панели оператора не доступен драйвер "LOGO!", но есть драйвер S7-200, то можно использовать его. На той же WinCC Flexible Runtime, например, такой способ является самым удобным. А вот на WinCC Runtime из TIA Portal'a драйвера S7-200 почему-то нет...
Сразу, кстати, проясняю насчет драйвера для S7-300/S7-400: через него работать не будет.

3. Через OPC Server. Лично я использую Multi-Protocol MasterOPC Server от компании Insat. Проблем пока не было. Но этот способ, понятное дело, только для PC.

4. Через Modbus TCP. Тут уже, ясное дело, не только панели оператора, а любые другие устройства можно к LOGO цеплять по Ethernet.
 

Драйверы LOGO! и S7-200

 
Итак, по первым двум способам - через драйверы "LOGO!" и "SIMATIC S7 200". Повторяю, эти способы абсолютно идентичны. Тут всё, в принципе, элементарно: I1, I2, I3, I4, I5, I6, I7, I8, I9, I10... превращаются в тэги с адресами I0.0, I0.1, I0.2, I0.3, I0.4, I0.5, I0.6, I0.7, I1.0, I1.1... соответственно. Тоже самое по битам Q и М. Для всего остального нужно задать таблицу Variable Memory Configuration: Tools -> Parameter VM Mapping... Например, вот так:
 
 
 Соответственно, так мы получили адреса VW0, VW2, VW4, VD6. Далее заводим эти теги в таблицу тегов WinCC / WinCC Flexible, получаем что-то типа того:


Обратите внимание, что у Timer_Period значения должны включать в себя 2 числа. В данном случае числа 1 и 14, например:

Но числовое значение у нас только одно, и в нём 1 и 14 превратятся в 114. Почему не сделано два отдельных числа - это загадка для меня. Назовём это "неудобство номер раз".

 

Драйвер Modicon MODBUS TCP/IP

 

Что касается Modbus TCP/IP, то чтобы к нему подключиться, сначала надо создать соединение в LOGO! SoftComfort:

Tools -> Ethernet Connections...

 


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

Возвращаясь к Modbus. Наши адреса VW0, VW2, VW4... становятся регистрами #1, #2, #3 соответственно. Или в более понятном представлении: 4x400001, 4x400002, 4x400003. Обратите внимание, не 4x4000x, а 4x40000x.

Теперь переходим к "проблеме номер два". Проблема связана со счётчиком. У него число представлено в формате двойного слова. С ним нет проблем при использовании драйверов LOGO! и S7-200, а с драйвером Modbus TCP/IP возникает типичная проблема для Siemens'a, у которого имеется неувязочка по части последовательности передачи младшего и старшего слова данных. А функционала, чтобы поменять их местами, конечно же, нет. Эта тема уже затрагивалась при обсуждении Modbus RTU на S7-1200, и никаких вариантов Siemens не предложил. Какой выход? Если счётчик предназначен для небольших чисел, то можно использовать не весь VD6, а только VW8, что соответствует регистру 4x400005. Как забрать полностью VD6, я не знаю. Может быть, как-то через скрипты в WinCC это можно сделать...

Что касается остальных областей памяти. С ними всё просто: есть зарезервированные адреса.


Т.е. заводим в таблицу тегов, например, 0x8193 - это будет у нас Q1.


Как управлять битами


Как все мы знаем, LOGO! не даёт возможностей использовать в логических цепочках биты Q и M, которым до этого не были присвоены значения через катушки Relay Coil. Например:

Здесь, чтобы использовать I3 не нужно ничего: просто добавили контакт, выбрали I3 - и всё хорошо. Чтобы также добавить контакт M1, сначала нужно сделать присвоение, как на рисунке. Без него создать контакт M1 у нас не получится. Следовательно, раз мы сделали присвоение, то пытаться дистанционно управлять таким битом бесполезно. Ситуация, когда управление битом без его использования в программе LOGO! может пригодится касается только дискретных выходов Q контроллера. Т.е. для тех Q, для которых в программе не созданы катушки присвоения, управление можно производить напрямую с панели оператора. 

Чтобы решить проблему с обычными битами, Siemens ввёл дополнительные компоненты:

Выбирая Network input, вы создаете объект с адресом в области памяти V, по умолчанию - V0.0. И уже им можете свободно управлять с панели оператора. Если используете протокол Modbus, то надо не забывать последовательность битов. Например, биты в регистре 4x400006 (VW10) будут располагаться так:


Соответственно, V10.0 - это 4x400006.8 и т.д. В программе LOGO! можем сделать что-то наподобие такого:

Реализация RS-триггера (Latching Relay)

Вот вроде бы как всё хорошо и понятно. Для каких-то компонентов можно расшарить данные через таблицу Variable Memory Configuration, для других задач есть специальные Network-компоненты, где соответствие выставляется в настройках самих этих компонентов. А теперь возникает как бы логичный вопрос: как сделать так, чтобы битом можно было управлять одновременно и с панели оператора, и в программе контроллера? Если помните, то в упомянутом уже S7-200 были три варианта тех самых катушек для присваивания значений битам:

1. Присваивание (=)

2. Установка бита (S)

3. Сброс бита (R)

Вот так это выглядит в инструкции к S7-200:

Однако, в LOGO! нет компонентов для установки и сброса битов. Причина весьма проста: LOGO! SoftComfort не допускает дублирование катушек (и блоков - для случая с FBD). Условно считается, что вся программа на LOGO! выполняется как реальная электрическая схема, а следовательно, многократных присвоений битов быть не может. И хотя программисты прекрасно понимают, что в конечном итоге компилятор выдаст из всех этих блоков самый обыкновенный машинный код, который будет выполняться последовательно, Siemens пока что не делает на LOGO! того, что четверть века назад почему-то спокойно сделал на S7-200. Выход из данной ситуации известен: использование RS-триггеров (Latching Relay). Способ громоздкий и неудобный (поскольку проверки условий установки и сброса бита могут находится в совершенно разных частях программы), но обходимся тем, что есть. И всё было бы хорошо, если бы мы могли задать биту RS-триггера какое-то соответствие в V-memory. Но, к сожалению, возможности это сделать нам не предоставили.

Итак, какие же у нас варианты? Прежде всего надо придумать простой пример. 

Допустим, есть бит который определяет режим работы (0 - ручной, 1 - автоматический режим). Бит этот устанавливается с панели оператора (HMI). И допустим, есть дискретный вход I0, который принудительно переводит этот бит в 0, т.е. в ручной режим. На языке программирования STL это выглядело бы так (второй аргумент в командах R и S я опускаю, чтоб не мешался):

LD  I0.0
R   V9.0      // это вот наш бит, допустим, который на HMI выглядит
              // в виде переключателя "РУЧН/АВТО"

Т.е. мы бы управляли битом V9.0 дистанционно (в программе этот момент бы никак не фигурировал), а дополнительно сбрасывали бы его по I0.0. Но мы не можем так сделать, т.к. у нас нет катушки для сброса бита компонента Network Input, которым мы управляем с панели оператора. Установка и сброс мы делаем через RS-триггер. Следовательно, на языке STL это было бы так:

// V10.3 - это бит, привязанный к переключателю "РУЧН/АВТО" на HMI
// V9.0  - это RS-триггер, определяющий режим работы
LD  I0.0
R   V10.3     // наш бит надо сбросить при блокирующем сигнале I0.0
ON  V10.3     // если I0.0 = true или V10.3 = false => тогда...
R   V9.0      // "РУЧН"
LDN I0.0
A   V10.3     // если I0.0 = false и V10.3 = true => тогда...
S   V9.0      // "АВТО"

Попробуем что-то подобное изобразить для LOGO!:


И вроде бы всё неплохо начиналось.. Но есть один нюанс: как мы будем сбрасывать бит V10.3 по условию, что замкнулся вход I1? Эта та самая вторая строчка "R V10.3" в моем примере на STL. Если мы этого не сделаем, то I1 хоть и обнулит SF006, но NI4 (V10.3) продолжит оставаться равным 1. Значит, на экране режим работы всё также будет отображаться как "АВТО", хотя по факту будет уже "РУЧН".

Как выйти из этой ситуации? Я предлагаю следующее решение: использовать счётчик. Компонент счётчик (Up/Down Counter) это ведь тоже по сути своей триггер. Только у него входы не R и S, а R и Cnt. Cnt прибавляет +1 к текущему значению счётчика. Например, было 0, стало 1. Мы можем задавать значение, выше которого бит счётчика устанавливается, а ниже - сбрасывается. Т.е. зададим это значение равным 1, и бит счетчика будет сбрасываться при 0 и устанавливаться при больше или равно 1. В чём важное для нашей задачи отличие счётчика от RS-триггера? Как было показано выше, мы можем расшаривать текущее значение счётчика и редактировать его на панели оператора. Если же наш счётчик будет работать в пределах 0..1, т.е. иметь всего два возможных значения, то в этом случае получится, что из всего того двойного слова данных, где это значение хранится, нас будет интересовать один-единственный бит. Самый первый бит. Тот, который отличает текущее значение 0 от значения 1. И вся наша задача легко и просто ушла в одну строку:

Следует не забывать, что у компонента "Счётчик" первый верхний вход - это сброс. Важно не перепутать с компонентом "RS-Триггер", у которого сбросом является второй вход.


Как изображено на самом первом рисунке в этой статье, текущее значение счетчика у нас имеет адрес VD6. Соответственно, интересующий нас бит имеет адрес V9.0 (или 4x400005.16 в случае с Modbus). Меняя этот бит, мы меняем значение счётчика. А сам счетчик настроен на включение при значении больше или равно 1:

Вот мы и получили, по сути дела, то, что и хотели получить в самом начале:

LD  I0.0
R   V9.0

Естественно, что мы можем не только сбрасывать бит триггера программно, но  устанавливать его:


 

В данном примере мы управляем дискретным выходом Q1, привязанным к нашему управляющему биту V9.0 блока C003. Помимо того, что мы можем менять значение V9.0 на панели оператора или в СКАДА, также в коде программы входом I1 этот бит принудительно сбрасывается, а входом I2 принудительно устанавливается. Единственный нюанс: счетчик не должен считать больше 1. Поэтому после I2 стоит бит проверки (M10 == false), что счетчик в данный момент = 0. Эту проверку нельзя выполнить напрямую из-за ограничений среды разработки (контакт C003 не может приходить в блок C003), поэтому задействован промежуточный бит M10, что, в общем-то, не сильно загромоздило нам программу.