
- •Материалы для подготовки к зачету
- •1. Введение
- •1.1 Понятие информации
- •1.2 Количество и качество информации
- •1.3 Понятие системы и ее свойства
- •1.4 Основные признаки систем
- •1.5 Понятие «черного ящика»
- •1.6 Иерархическая система
- •1.7 Управляющие системы
- •1.8 Прямая и обратная связь управления
- •1.9 Основные направления развития автоматизации управления
- •1.10 Автоматизированные системы управления технологическими процессами (асу тп)
- •1.11 Автоматизированная система управления производством (асуп)
- •2. Определение плк
- •3. Устройство плк
- •4. Введение в программирование плк
- •5. Компоненты организации программ (pou)
- •Присваивание значений параметрам функции
- •6. Данные и переменные
- •7. Структурированный текст (st)
- •8. Язык линейных инструкций (il)
- •9. Релейные диаграммы (ld)
- •10. Язык функциональных блок-схем – fbd
- •11. Язык программирования sfc (Sequential Function Chart)
Присваивание значений параметрам функции
Второй способ вызова функции предусматривает непосредственное присваивание значений параметрам функции по именам:
stHello := CONСАТ(STR1:='Добрый ', STR2:='денъ'); Это равносильно:
stHello := CONCAT('Добрый ', 'день'); или:
stHello := CONСАТ('Добрый ', STR2:='день');
Если в программе уже определена переменная с именем, совпадающим с наименованием входного параметра (STR1 := 'Добрый';), вызов может вызывать недоумение:
stHello := CONCAT(STR1:=STR1, STR2:= 'денъ');
На самом деле тут все правильно: слева от знака присваивания — параметр функции, справа — переменная.
Описанный способ вызова функции предполагает возможность задавать параметры в произвольном порядке и опускать некоторые из них. Текущая версия CoDeSys не обеспечивает функциям такую возможность. Единственный смысл такой нотации — в универсальности, приемлемой для функциональных блоков и программ.
Передача параметров функции всегда происходит путем копирования. При любом способе вызова функция получает локальные копии значений переменных.
Функции с переменным числом параметров
Для многих функций трудно предугадать, сколько значений нужно будет обработать в конкретном случае. Например, для функции AND можно ограничиться двумя входами и использовать "лесенку" вызовов функций для обработки большего числа переменных (рис. 3.2).
Рис. 3.2. Соединение двухвходовых AND
На рис. 3.2 представлена не очень красивая конструкция. Было бы значительно удобнее иметь «расширяемую» функцию, которая могла бы адаптироваться под переменное число параметров.
Стандарт МЭК действительно предусматривает такую возможность. В текстовых языках расширение производится добавлением переменных в конец списка параметров:
у := MUX(x_n, xl, х2, хЗ, х4, х5);
По причине сложности реализации транслятора переменное число параметров в пользовательских функциях не используется.
Операторы и функции
Операторы — это символы определенных операций. Но их можно определить и как функции, наделенные определенными привилегиями. Во-первых, код для операторов транслятор создает сам и не требует подключения каких-либо библиотек. Во-вторых, многие операторы имеют особые формы записи в выражениях ST. Например, математические операторы (сложение, вычитание, умножение и деление) имеют традиционное символьное представление в текстовых языках (+, -, *, /). В графических языках операторы выглядят как обычные функции.
В принципе, можно обходиться без символьного представления операторов. Например:
Y := SUB(MUL(4,x),3);
Но символьное представление в ST выглядит значительно лучше:
Y :=4*x-3
Математики пишут еще короче:
Y :=4x-3
Все три записи равноценны по смыслу. Символьные выражения понятнее и дают возможность более сконцентрироваться на сути выражения, а не на форме его представления.
При работе с операторами необходимо обращать внимание на наличие символьной формы представления. Так, для математических и логических операторов в языке ST, как правило, допускается только символьное представление. Выражение Y := AND(xl, x2) вызовет ошибку компиляции. Необходимо писать так: Y := xl AND х2;. Если оператор не имеет символьного представления, то на него распространяются обычные правила вызова функций. Например: y:=SQRT(x).
Обратите внимание, что имена входных параметров для операторов в описании не заданы. Это означает, что вызывать такие функции в ST можно только перечислением параметров.
Функциональные блоки
Функциональный блок — программный компонент, отображающий множество значений входных параметров на множество выходных. После выполнения экземпляра функционального блока все его переменные сохраняются до следующего выполнения. Следовательно, функциональный блок, вызываемый с одними и теми же входными параметрами, может производить различные выходные значения. Сохраняются все переменные, включая входные и выходные. Так, если мы вызовем экземпляр функционального блока, не определяя значения некоторых входных параметров, он будет использовать ранее установленные значения. Возможность задания переменного числа входных значений заложена по определению и не требует каких-либо дополнительных усилий. Извне доступны только входы и выходы функционального блока, получить доступ к внутренним переменным блока нельзя.
С позиций объектно-ориентированного программирования (ООП) функциональные блоки — это объекты, великолепно реализующие инкапсуляцию, т. е. сокрытие деталей реализации. Объединение кода и данных в «одном флаконе» роднит функциональные блоки с классами ООП. Возможность наследования и полиморфизм, к сожалению, пока отсутствуют.
Создание экземпляра функционального блока
Прежде чем использовать функциональный блок, необходимо создать его экземпляр. Эта операция аналогична по смыслу объявлению переменной. Описав новый блок, мы фактически создали новый тип данных подобный структуре. Каждый функциональный блок может иметь любое количество экземпляров. Так, различные экземпляры блока «таймер» совершенно независимы друг от друга. Каждый из них имеет собственные настройки и живет собственной жизнью.
Каждый экземпляр функционального блока имеет свой собственный идентификатор и свою область в статической памяти данных. Объявление еще одного экземпляра блока приводит к выделению еще одной области в памяти данных. Код, очевидно, как и для функции, остается общим.
Экземпляр функционального блока создается в разделе объявлений переменных функционального блока, программы или в разделе глобальных переменных проекта. Как и переменные, он должен получить уникальный идентификатор. Например, создание экземпляра стандартного функционального блока «инкрементный счетчик» с идентификатором ctuTimeMeter выглядит так:
ctuTimeMeter: CTU;
Очевидно, что создавать экземпляры можно только для известных системе блоков. Это библиотечные блоки или блоки, ранее реализованные пользователем. С точки зрения транслятора, создание экземпляра означает выделение необходимой памяти для размещения переменных блока.
Экземпляр функционального блока можно не только вызывать, но и использовать в качестве входных переменных других функциональных блоков.
Функциональным блоком иногда называют экземпляр функционального блока, для краткости. В данном курсе такие неоднозначные сокращения применяться не будут. Позволим себе только называть иногда функциональный блок просто блоком, а экземпляр функционального блока — экземпляром.
Доступ к переменным экземпляра
После создания экземпляра функционального блока можно сразу начать работать с его данными. При этом совсем не обязательно вызывать его. Обращаться к переменным экземпляра можно так же, как к элементам структуры данных, через точку.
Входы экземпляра блока доступны для записи и чтения извне. Выходы — только для чтения. Изменять значения выходов можно только из тела блока, извне нельзя. Транслятор отслеживает такие попытки и выдает сообщение об ошибке.
Вызов экземпляра блока
Вызывать экземпляр функционального блока с перечислением параметров, как функцию, нельзя. Значения входных переменных должны присваиваться непосредственно. В текстовых языках входные переменные перечисляются в скобках, после имени экземпляра. Присваивание входных значений выполняется операцией ':='.
На языке ST:
ctuTimeMeter (RESET := FALSE);
На языке IL:
CAL ctuTimeMeter(RESET := FALSE)
Специальный символ '=>' позволяет получить значения выходов после выполнения блока:
ctuTimeMeter (RESET := FALSE, CU := Inpl, CV => x);
При вызове экземпляра можно определить только необходимые параметры, причем в произвольном порядке. В графических языках неиспользуемые входы и выходы экземпляра блока просто остаются неподключенными.