Пользователськие структуры DDT и функциональные блоки DFB

Задача: Управление однотипными бункерами.
Создать программу в UNITY PRO для управления 3 мя бункерами: один - сахарного сиропа, два - воды, алгоритм которых описывается в быстром старте.
В напорных баках необходимо поддерживать заданный пределами уровень жидкости с помощью насосов M1
При выбранном режиме START, насос М1 должен:
- включаться при отключении сигнализатора LS1 (нижний предел)
- отключаться при срабатывании сигнализатора LS2 (верхний предел).
Таким образом в напорном баке будет всегда жидкость в пределах размещения сигнализаторов предельных уровней.
При выбранном режиме STOP, насос М1:
- включается при нажатии оператором кнопки ManPump,
- отключается через 5с по отключении кнопки.
Питание датчиков, переключателя, кнопки и реле цепи управления пускателя =24В.
Самый простой способ решения задачи - написать программу для одного бункера (в быстром старте она приведена), отладить её и размножить методом копирования еще на два бункера. Кроме простоты, преимуществом даного подхода является возможность индивидуального подхода к алгоритму управления каждым бункером, а также относительная простота отладки. Однако если индивидуального подхода не требуется, а количество бункеров будет намного больше, например десятки, то возникает ряд недостатков в таком подходе:
-при необходимости изменения программы, это нужно будет делать в каждой копии;
-величина программы увеличивается пропорционально количеству копий;
  Учитывая однотипность бункеров и одинаковый алгоритм управления, есть смысл уменьшить программу одним из следующих способов:
- используя массивы и циклы: то есть все переменные заложить в массив с количеством еллементов, равным  количеству бункеров, а программу обработки вставить в тело цикла;
- используя подпрограммы
Решение 1. С помощью DDT и SR. SR (Подпрограммы) очевидно остались в UNITY для совместимости со старыми приложениями PL7, при их конвертировании в новые версии UNITY PRO. Без них обойтись можно, используя более удобный механизм DFB. Тем не менее в этом решении мы вопсользуемся SR а также пользовательскими структурами DDT.
Как мы уже знаем, подпрограммы UNITY PRO не могут принимать фактических параметров при вызове. Однако реализация вызова функций/процедур с передачей параметров всё равно на нижнем уровне реализуется приблизительно следующим способом: 
- в стек помещаются нужные входные параметры процедуры/функции;
- запускается нужная процедура/функция, код которой  использует значения стека;
- по окончанию процедуры или ранее, идет возврат в основную программу, с помещением в стек возвращаемых параметров;
Мы можем воспользоваться этим же приниципом. Однако вместо стека мы будем использовать какую-то выделенную область памяти. Чтоб работать с ней как с единым целым, удобно воспользоваться структурными переменными. Таким образом последовательность работы программы будет следующей:
- в структурную переменную записываются нужные значения входных параметров;
- запускается подпрограмма, код которой использует значение структурной переменной;
- по окончанию подпрограммы идет возврат в основную программу, где значение выходных параметров считывается со структурной переменной;  
Создаем пользовательский структурный тип DDT "Bunker": 
Предназначение полей StartDelay и TimeOFF описываются немного позже. Далее создаем 4-ре структурных переменных типа Bunker:
D - переменная, используемая в подпрограмме, аля формальный параметр;
B_Sugar, B_Water1, B_Water2  - переменные, используемые как фактические параметры.
Основу подпрограммы, которую назовем "Bunker" будет содержать код, приведенный в быстром старте  как 2-й вариант на яызке LD.
 Однако программу пришлось модифицировать, а именно:
- обычные переменные заменены на структурные по причинам, описаным ранее по тексту;
- вместо таймеров использован подсчет импульсов.
Таймер в подпрограмме использовать можно, но это будет один екземпляр на все вызовы, а нужно чтоб таймеры работали независимо друг от друга. Поэтому таймеры TOF в подпрограмме были заменены счетчиком импульсов (см. генерация импульсов), которые далее в тексте называются таймерами. Эти таймеры характеризуются следующими значениями:
- TimeOFF - поакзывающим обратное время в масштабе 100 мс;
- StartDelay - сигнализирующим о пуске таймера;
 Рассмотрим работу программы. В режиме Start, всё работает аналогично как во 2-м варианте LD быстрого старта. В режиме Stop (-|/|- D.Start) включение D.M1 производится нажатием кнопки D.ManPump, а отключение - по отключению D.ManPump и когда остановится таймер D.StartDelay=FALSE, алгоритм работы которого описан далее.
Как описано выше, механизм таймера основан на подсчете импульсов определенной периодичности. В режиме Stop, при включенном двигателе D.M1, отключенной кнопке ручного запуска насоса (-|/|- D.ManPump) и не запущенном таймере (-|/|- D.StartDelay), что соответствует ситуации отпускания кнопки ручного запуска насоса, - время обратного отсчета устанавливается в исходную точку D.TimeOFF:=50, и выставляется в TRUE перем D.StartDelay (таймер запущен).
Во время работы таймера (-| |- D.StartDelay), при каждом срабатывании импульса Imp100ms, D.TimeOFF уменьшается на 1. Таким образом скорость уменьшения D.TimeOFF будет зависеть от периодичности срабатывания Imp100ms. В основной программе нужно обеспечить, чтоб Imp100ms  срабатывал через каждые 100 мс ровно на один цикл. При этих же условиях проверяется достиг ли таймер нижнего предела, и если да - D.StartDelay скидывается, что означает окончание работы таймера.
 Основную программу напишем на ST.
Первые две строки обеспечивают генерацию импульсов Imp100ms длительностью один цикл и с периодичностью 100 мс. Остальные три - вызывают подпрограмму Dozator, передавая туда фактические параметры путем присвоения перемнной D (аля формальному параметру) значение нужных переменных. После вызова подпрограммы, происходит обратное присвоение выходных параметров. 
Решение 2. С помощью DFB. Использование DFB более удобный механизм, чем использование подпрограмм. Создадим пользовательский тип функционального блока (DFB Type) с именем BunkerDFB:
 Как видно с рисунка секция Logic практически не отличается от прдеставленой в 1-м варианте решения быстрого старта. Единственным отличием является привязка уставки таймера Timer1.PT к переменной OFFTime, которая определена в секции public функционального блока. Этого не было в постановке задачи, мы его ввели для максимального раскрытия использования DFB. Таким образом, екземпляры DFB можно настраивать на конкретное время задержки отключения в режиме Stop.    
В переменных проекта достаточно создать три экземпляра DFB и вызвать их в программе, привязав входыи выходы блоков к нужным фактичесим параметрам. 
 
Кроме того в любом месте программы можно определить настройку времени отключения OFF_Time нужного функционального блока. 

 
 
 
 
 
Comments