Запрограммированое в предыдущей части поведение задвижки… нелогично. В обработчике нажатия кнопки «Открыть» или «Закрыть» мы непосредственно задавали значение элемента под названием Position. При том, что в самом DPT у нас уже предусмотрены команды «Открыть» и «Закрыть».
Разумеется, в реальной жизни для управления каким-либо агрегатом мы, как правило, задаем значение соответсвующей команды, представленной в виде переменной контроллера. Поскольку реального контроллера в этом workshop пока нет, мы будем имитировать поведение технологического оборудования посредством скрипта.
Но для начала изменим обработчик нажатия на кнопки «Открыть» и «Закрыть».
Меняем на
main(mapping event)
{
dpSet("System1:Flap1.Commands.Open", 1, "System1:Flap1.Commands.Close", 0);
}
Обратите внимание, что этот скрипт задает значение двум DPE, но, как было сказано в конце прошлой части, это выполняется одним сообщением. Выставляется команда «Открыть» и сбрасывается команда «Закрыть», это своего рода «защита от дурака» (которая, в принципе, должна и так быть в прикладной программе контроллера, но мы перестраховываемся).
Аналогично поступаем со скриптом кнопки «Close»
Проверим выполнение скрипта нажатия кнопок, меняются ли переменные команд в модуле Para
Разумеется, в настоящий момент положение заслонки не меняется, так как нет обработчика команд. По нажатию кнопок сейчас должны менять свои значения тэги open и close соответствующей точки данных.
Для создания скрипта мы должны в gedi найти в дереве проекта Scripts, нажать правую кнопку мыши и выбрать Add New CTRL Script
Дадим осмысленное имя файла скрипта, я его назвал Model
После нажатия ОК скрипт появляется в дереве проекта
Далее двойным кликом на файле открываем скрипт для редактирования. Теперь необходимо продумать поведение модели и структуру самого скрипта. С учетом ярко-выраженного событийного поведения всей системы WinCC OA, этот скрипт должен вызывает функцию dpConnect, завязанную на одну из переменных команд управления задвижкой. Разберемся по шагам.
Вызываем dpConnect на изменение значения переменной команды. В данном случае у нас очень упрощенная модель, защита от дурака реализована в скриптах нажатия кнопки, поэтому достаточно будет привязаться и к одной команде.
Создаем callback функцию на изменение значения команды в рамках модели поведения.
Другие варианты поведения модели неверны с точки зрения идеалогии WinCC OA. Если в самом «глобальном» скрипте вызывать dpGet для чтения значения переменной команды, то этот скрипт надо вызывать постоянно, с определенной периодичностью.
Напоминаю, что у функции dpConnect есть два аргумента. Первый аргумент — имя callback-функции (я назвал ее OnOpen_CB), второй — имя точки данных, на которую происходит подписка. Итого, в упрощенном виде, без каких-либо проверок функция main скрипта Model выглядит так:
main()
{
dpConnect("OnOpen_CB", "System1:Flap1.Commands.Open");
}
Далее напишем саму callback-функцию. У нее тоже два аргумента — имя точки данных (тип данных string) и «новое» значение этой точки данных (должно соответствовать типу данных «исходной» точки). Получается вот такая заготовка.
void OnOpen_CB(string dp1, bool bNewValue)
{
;
}
Дописываем обработчик, он очень простой. Если значение команды «открыть» равно «истина», то задаем положение задвижки, равное 90. Если значение равно «ложь», то значение — 0.
void OnOpen_CB(string dp1, bool bNewValue)
{
if (bNewValue) {
dpSet("System1:Flap1.Inputs.Position", 90);
} else {
dpSet("System1:Flap1.Inputs.Position", 0);
}
}
Теперь этот созданный скрипт необходимо как-то вызвать. Для исполнения «глобальных» скриптов используется Control Manager. Следовательно, требуется добавить в список менеджеров системы вызов еще одного менеджера (Control), где в качестве параметра задается имя исполняемого скрипта. В системе есть уже один вызов Control. И его трогать не следует во избежание нехороших последствий. Разве что, вы работаете с системой на уровне эксперта, но тогда зачем вам читать эти заметки?
В консоли WinCC OA нажимаем кнопку Append new manager, выбираем в появившемся окне менеджер Control. Для первого запуска свежесозданного скрипта имеет смысл выбрать режим запуска (Start mode) ручной (manual), чтобы не наблюдать попытки перезапуска в случае ошибок в самом скрипте. В качестве параметров вызова менеджера необходимо указать его номер в системе. В нашем случае это будет номер 2. Почему 2? Потому что менеджер с номером 1 в системе уже существует. Менеджеры одного типа в системе должны запускаться со своим уникальным номером. Именно одного типа. Это значит, что в системе может быть ui с номером 1 и ctrl с номером 1, а вот два ui (или ctrl) с одним и тем же номером быть не должны. Поэтому в качестве агрумента запуска я указываю строку «-num 2». Кроме того, требуется передать имя исполняемого скрипта. Вызов нового менеджера выглядит следующим образом:
Остается нажать кнопку ОК и запустить менеджер вручную кнопкой Manager Start либо мышью через вспывающее меню (новый менеджер при этом должен быть выделен в списке). Если все сделано правильно, то добавленный менеджер позеленеет и примет статус 2.
Теперь остается проверить работу симуляции.
Следует обратить внимание на то, что Control Manager запускает скрипт (точнее, свою функцию main) один раз при старте. После выполнения функции main() необходимые callback функции продолжают находится в памяти ПК, они исполняются при выполнении условий, указанных в dpConnect (по изменению значения переменной). Однако, если в сам скрипт были внесены изменения, то необходимо вручную остановить соответствующий экземпляр control-менеджера и запустить его заново. Без останова-запуска изменения не будут приняты.
Сам control manager при запуске создает свой отдельный процесс. Его функция main выполняется в отдельной нитке (потоке, thread). Callback функция (в нашем случае OnOpen_CB) так же запускается в отдельном потоке. После выполнения функция main перестает работать, но callback продолжает находится в памяти ПК (в своем потоке) и вызывается при изменениях «подписанной» переменной.