В обсуждении на форуме iadt.siemens.ru была затронута интересная тема -
Когда для хранения статических данных целесообразно использовать (вложенные) FB, а когда приемлемо передавать статические переменные в FC через интерфейс?
Ответ на этот вопрос у Бергера не найдешь, ибо «работает» много вариантов. Выбор того или иного варианта определяется, главным образом, «стилем программирования». В свою очередь, вопросы стиля в сфере промышленной автоматизации считаются моветоном, а на марше - "зачем? лишь бы меньше думать/делать и чтоб работало".
Между тем, именно "стиль программирования" определяет уровень на котором ведется разработка, и напрямую влияет на удобство (и вообще возможность) дальнейшего сопровождения и развития проекта.
Между тем, именно "стиль программирования" определяет уровень на котором ведется разработка, и напрямую влияет на удобство (и вообще возможность) дальнейшего сопровождения и развития проекта.
Рассмотрим варианты реализации функции счетчика импульсов (именно она обсуждалась на форуме).
- "Простой FB". Организовывать отдельную FB только для того, чтобы хранить единственную битовую переменную (для определения фронта) - явно не лучшая идея. Скрывать элементарную функциональность за абстрактным именем FB, которое еще к тому же будет отображаться в FBD с еще более абстрактным экземплярным именем - это значит обрекать себя на то, что раз за разом придется заглядывать в исходный код, с тем чтобы очередной раз вспомнить что это за функция.
- "Вообще без FC/FB". Противоположным подходом является непосредственная реализация простого функционала с использованием базовых функций языка и создание необходимых статических переменных в глобальных DB (или данных FB). Действительно, «простая программа счетчика» занимает два-три нетворка и требует всего нескольких статических переменных. Таким образом, в случае однократного использования функционала – этот способ наиболее удобен. Неудобства возникнут, если все-таки функционал используется многократно, и особенно внутри одного FB.
Мне приходилось иметь дело с исходным текстом на FBD, в которой типовая операция из двух нетворков была размножена порядка ста (!) раз, а переменные были намешаны как «изюм» в тесте. Нет, все-таки в «каше» ;). Естественно, варятся такие «блюда» известным методом копи-паста, что приводит к ошибкам типа «скопировали и не поправили».
В подобных случаях рано или поздно настает момент, когда применение типовой функции становится необходимо и лучше предусмотреть это заранее.
Кроме того, даже в элементарных случаях, нередко «всплывают» нюансы, которые небыли учтены изначально, а соответствующие изменения весьма трудоемки. Классические случаи «недогляда» - переполнение и инициализация. - «FC». Реализовать типовые алгоритмы в виде функций – является логичной ступенькой эволюции растущего проекта. При этом достигается многократное использование кода, а при правильном интерфейсе – простота, наглядность, компактность. Камнем преткновения здесь становится именно интерфейс.
Функция не имеет возможности хранить статические данные, поэтому, в случае необходимости, их необходимо передавать через входные/выходные переменные.
При вызове функции должны быть привязаны (заданы) все входные/выходные переменные. Таким образом, даже если в программе не используются часть входных/выходных данных - все равно должны быть привязаны «переменные-заглушки».
Не малая часть параметров функции задается в виде литералов (численных значений) и на их передачу (равно как и на передачу «заглушек») затрачивается дополнительное время в процессе каждого вызова.
Кроме того, большая часть этих численных значений являются «настройками», т.е. должны быть доступны для изменения в процессе выполнения и, желательно, чтобы они были сосредоточены вместе, а не «размазаны» по всей программе.
Если интерфейс функции получается достаточно простым, то лучше использовать FC, в противном случае - «проблемы интерфейса» решаются за счет использования функциональных блоков (FB). - «Полноценный FB». Типовые алгоритмы в виде функциональных блоков обладают наибольшим потенциалом, так как являются своеобразной реализацией объектно-ориентированного подхода в зачаточной стадии. В отличие от более развитых собратьев, у экземпляра FB (объекта) есть только один метод (сам FB), в котором и необходимо реализовать все поведение объекта. Однако основное преимущество объектно-ориентированного подхода – инкапсуляция данных - реализуется. За счет этого исчезает необходимость в создании «внешних» хранилищ данных, которые с ростом проекта имеют тенденцию превращаться в «помойку» (в глобальном блоке данных или меркерной памяти).
Интерфейс вызова функционального блока, может быть существенно упрощен, за счет того, что параметры типа STAT в нем не отображаются. В качестве переменных типа IN, OUT, INOUT указываются только параметры, присутствие которых в интерфейсе вызова целесообразно. Кроме того, параметры FB могут не указываться при вызове, при этом они сохраняют свое значение заданное, например, при создании экземпляра.
Сохраняемые переменные создаются внутри экземплярного блока и доступны по имени как на этапе компиляции так и в процессе выполнения, это дает возможность удобно «параметризировать» алгоритм, например, при объявлении блока данных из исходного текста на SCL.
Однако, если функционал достаточно прост (как в случае с простым счетчиком) использование FB не приносит никаких преимуществ, а лишь вносит накладные расходы на создание экземпляров. Таким образом, см. пункт 1 и… круг замкнулся.
Какой же способ использовать? Универсального решения нет, а с точки зрения работоспособности программы – разницы нет, ибо «и так работает». И все же - разница есть. И она, как правило, на столько же очевидна как разница между жигулем и мерседесом, если принимать во внимание не только формальные признаки наличия колес, руля и способности к передвижению. :)
Комментариев нет:
Отправить комментарий