En eno в codesys что это
Таймеры и триггеры CODESYS. Еще один шаг Arduino к классическому ПЛК
Случается программировать контроллеры (ПЛК) в среде CODESYS. Все, кто имел дело с этой системой, знают, что в любом проекте присутствует библиотека Standard.lib, в которой реализованы базовые таймеры, триггеры, счетчики и некоторое кол-во других функций и функциональных блоков. Многие из этих блоков постоянно используются в программах для ПЛК. А сама библиотека, как и языки программирования CODESYS, является воплощением стандарта IEC 61131-3, т.е. призвана помочь при программировании классических ПЛК задач.
Одна из особенностей программ для ПЛК в том, что основной цикл программы должен выполняться без существенных задержек, в нем не должно быть внутренних циклов с неопределенным временем выхода или синхронных вызовов «задумчивых» функций, особенно это касается коммуникаций по медленным каналам. Обновление входных и выходным образов процесса происходит только на границе основного цикла, и чем дольше мы будем «сидеть» внутри одной итерации цикла, тем меньше мы будет знать о реальном состоянии объекта управления, в конечном итоге сработает watchdog переполнения времени выполнения цикла. Многие могут мне возразить, сказав, что современные ПЛК многозначны, есть с поддержкой аппаратных прерываний. Согласен, но разговор о таких системах не входит в мои планы, я же хочу поговорить о (квази, псевдо — выбирайте) ПЛК однозадачной реализации (без прерываний) на базе микропроцессорной платформы Arduino, в котором есть только один основной цикл. Кстати, не лишним будет сказать, что на написание данной заметки меня сподвигла статья Ардуино-совместимый ПЛК CONTROLLINO, часть 1 о попытке аппаратного воплощения Arduino в пром. ПЛК.
Несколько слов об Arduino. С точки зрения программиста ПЛК, Arduino — это типичный контроллер с одним очень быстрым или, наоборот, очень медленным циклом loop(). На время выполнения цикла не накладывается никаких ограничений, и он может отработать и один, и бесконечное кол-во раз — по замыслу программиста. Когда программа проста и сводится к выполнению последовательных операций, регуляторов, без параллельных событий, то достаточно чередовать операции бесконечными вложенными циклами проверки условий и синхронными задержками типа delay(). Последовательные шаги такой программы будут выполняться буквально построчно, просто и логично. Но, как только возникает необходимость в программировании параллельных операций, необходимо менять парадигму программы.
В однозадачной системе добиться видимой параллельности можно только очень быстрым последовательным сканированием параллельных состояний, не задерживаясь подолгу на каждом вызове функции или проверке условия. С физическими входами-выходами проблем нет, функции отрабатывают достаточно быстро, а вот delay() становится неоправданным тормозом. И вот тут на смену приходят неблокирующие таймеры, те самые, которые в программировании ПЛК являются классикой. Суть в том, что для их работы используется миллисекундный счетчик времени, и все действия привязаны к значениям этого глобального счетчика.
А теперь давайте вспомним ту самую Standard.lib из CODESYS. В ней как раз реализованы МЭК-овские неблокирующие таймеры. Я взял ее за основу и портировал функции таймеров и триггеров в библиотечный код Arduino (С++). Т.е. попытался приблизить Arduino к классическому ПЛК.
Ниже я приведу краткое описание портированных функциональных блоков (FB) CODESYS и их аналоги в моей библиотеке plcStandardLib, все временные диаграммы верны для новой библиотеки Arduino. Подробнее описание исходных блоков можно посмотреть, например, в русскоязычной справке по CODESYS.
TON — функциональный блок «таймер с задержкой включения»
Входы IN и PT типов BOOL и TIME соответственно. Выходы Q и ET аналогично типов BOOL и TIME. Пока IN равен FALSE, выход Q = FALSE, выход ET = 0. Как только IN становится TRUE, начинается отсчет времени (в миллисекундах) на выходе ET до значения, равного PT. Далее счетчик не увеличивается. Q равен TRUE, когда IN равен TRUE, а ET равен PT, иначе FALSE. Таким
образом, выход Q устанавливается с задержкой PT от фронта входа IN.
В Arduino IDE:
Временная диаграмма работы TON:
TOF — функциональный блок «таймер с задержкой выключения»
Входы IN и PT типов BOOL и TIME соответственно. Выходы Q и ET аналогично типов BOOL и TIME. Если IN равен TRUE, то выход Q = TRUE и выход ET = 0. Как только IN переходит в FALSE, начинается отсчет времени (в миллисекундах) на выходе ET. При достижении заданной длительности отсчет останавливается. Выход Q равен FALSE, если IN равен FALSE и ET равен PT, иначе — TRUE. Таким образом, выход Q сбрасывается с задержкой PT от спада входа IN.
В Arduino IDE:
Очень похоже на TON, для краткости:
Временная диаграмма работы TOF:
TP — функциональный блок «импульс-таймер»
Входы IN и PT типов BOOL и TIME соответственно. Выходы Q и ET аналогично типов BOOL и TIME. Пока IN равен FALSE, выход Q = FALSE, выход ET = 0. При переходе IN в TRUE выход Q устанавливается в TRUE и таймер начинает отсчет времени (в миллисекундах) на выходе ET до достижения длительности, заданной PT. Далее счетчик не увеличивается. Таким образом, выход Q генерирует импульс длительностью PT по фронту входа IN.
В Arduino IDE:
Очень похоже на TON, для краткости:
Временная диаграмма работы TP:
R_TRIG — функциональный блок «дeтектор фронта»
Функциональный блок R_TRIG генерирует импульс по переднему фронту входного сигнала. Выход Q равен FALSE до тех пор, пока вход CLK равен FALSE. Как только CLK получает значение TRUE, Q устанавливается в TRUE. При следующем вызове функционального блока выход сбрасывается в FALSE. Таким образом, блок выдает единичный импульс при каждом переходе CLK из FALSE в TRUE.
Пример CODEDESYS на языке ST:
В Arduino IDE:
F_TRIG — функциональный блок «дeтектор спада»
Функциональный блок F_TRIG генерирует импульс по заднему фронту входного сигнала.
Выход Q равен FALSE до тех пор, пока вход CLK равен TRUE. Как только CLK получает значение FALSE, Q устанавливается в TRUE. При следующем вызове функционального блока выход сбрасывается в FALSE. Таким образом, блок выдает единичный импульс при каждом переходе CLK из TRUE в FALSE.
В Arduino IDE:
RS_TRIG — функциональный блок RS-триггер / SR_TRIG — функциональный блок SR-триггер
Переключатель с доминантой выключения, RS-триггер:
Переключатель с доминантой включения:
Входные переменные SET и RESET1 — как и выходная переменная Q1 типа BOOL.
Язык функциональных блоковых диаграмм (FBD) и его применение
Написанная на данном языке программа для контроллера состоит из некого списка цепей, которые одна за другой выполняются сверху — вниз. Кроме того, здесь имеется возможность присвоения отдельным цепям меток, в этом случае станет доступно использование инструкций перехода на метку, дабы изменять последовательность исполнения цепей, и создавать условия и циклы.
Таким образом, программа, написанная на графическом языке FBD, представляет собой набор связанных друг с другом функциональных блоков, выходы и входы которых соединены линиями связи. Линии связи отражают определенные программные переменные, через которые происходит обмен данными от блока — к блоку.
Отдельный блок несет на себе конкретную функцию (логическое «и», «не», счетчик и т. д.), при этом один блок может иметь несколько выходов и входов. Изначально значения переменных задаются константами или со специальных входов, а выходы их связываются дальше с другими переменными программы или с выходами ПЛК.
На рисунке приведен пример программы, написанной на языке функциональных блоковых диаграмм FBD. Как видите, такое изображение программы очень наглядно отражает алгоритм, что и делает данный язык довольно простым и удобным для разработки ПО для ПЛК.
В процессе программирования на языке FBD применяются как стандартные блоки из библиотек, так и блоки, сами написанные на FBD или на иных языках стандарта МЭК 61131-3. Блок представляет собой элемент программы, своего рода подпрограмму, функциональный блок или функцию (логическое «НЕ», «ИЛИ», «И», таймер, счетчик, триггер, математическая операция, обработка аналогового сигнала и т. д.).
Из таких блоков графически составляются выражения, образующие цепи: к выходу одного блока присоединяется следующий блок, далее — еще блок, и так образуются цепи. По ходу цепи порядок выполнения блоков соответствует порядку их соединения, а результат выполнения цепи либо подается на выход ПЛК, либо записывается в какую-то внутреннюю переменную.
Рассмотрим кусочек программы, написанной на языке FBD: В умножить на 4, затем поделить на А, и записать результат в переменную result. В псевдокоде это будет выглядеть так: result := B*4/A. Возможно также добавление к блокам специальных управляющих входов EN и выходов ENO, для управления вызовами отдельных блоков: логический ноль, поданный на вход EN, запретит вызов данного блока, а выход ENO в случае ошибки сообщит о ней, и прервет тем самым выполнение цепи до конца.
Как видите, язык FBD до крайности нагляден, удобен, и потому прост в освоении даже специалистами — прикладниками, не имеющими специальной подготовки по информатике. Код выполняется последовательно, структура команд внутри кода проста, поэтому программа транслируется очень быстро и задача выполняется надежно.
Есть различные модификации языка программирования FBD, отличающиеся наличием тех или иных ограничений или расширений.
Например, существует разновидность FBC, допускающая применение только чистых функций с одним выходом без промежуточных переменных — модификация для функционального программирования.
Или модификация CFC (Continuous Function Chart), позволяющая установить порядок выполнения диаграмм не просто последовательной цепочкой, а по усмотрению разработчика ПО. С CFC разработчик получает больше свободы, хотя код получается более длинным.
Пример языка FBD в STEP 7:
Преимущество языка FBD перед языком релейных диаграмм LD возрастает с увеличением сложности алгоритма управления. Алгоритм управления написанный в FBD, позволяет легче, чем в LD, отслеживать изменения в программе и искать возможные ошибки во время отладки.
В целом, принципы работы обоих языков очень похожи. Своей популярностью они обязаны прозрачности обозначений, благодаря которой код относительно небольших программ можно быстро понять, даже без особых знаний программирования.
Мы планируем развивать эту тему здесь:
Курс по программированию контроллеров:
Structured Text
Книга «Изучаем Structured Text МЭК 61131-3»: Ссылка на книгу
Общие сведения о языке FBD¶
FBD (Function Block Diagram) – это графический язык программирования высокого уровня, обеспечивающий управление потока данных всех типов. Позволяет использовать мощные алгоритмы простым вызовом функций и функциональных блоков. Удовлетворяет непрерывным динамическим процессам. Замечательно подходит для небольших приложений и удобен для реализации сложных вещей подобно ПИД регуляторам, массивам и т. д. Данный язык может использовать большую библиотеку блоков, описание которых приведено в приложении 2. FBD заимствует символику булевой алгебры и, так как булевы символы имеют входы и выходы, которые могут быть соединены между собой, FBD является более эффективным для представления структурной информации, чем язык релейно-контактных схем.
Основные понятия и конструкции языка¶
Согласно IEC 611313, основными элементами языка FBD являются: переменные, функции, функциональные блоки и соединения.
Переменные бывают входные, выходные и входные/выходные. На рис. 1 показаны: входная переменная – «in_var», выходная переменная – «out_var» и входная/выходная переменная – «in_out_var».
Рис. 1 – Изображение переменной в языке FBD
Графическое изображение функции приведено на рис. 2. С левой стороны располагаются входы (IN1 и IN2), с правой стороны выходы (OUT).
Рис. 2 – Изображение функции в языке FBD
Аналогично, изображение функционального блока, приведённое на рис. 3, имеет с левой стороны входы (S1 и R), с правой стороны выход (Q1).
Рис. 3 – Изображение функционального блока в языке FBD
Соответственно, переменные соединяются с входными и выходными параметрами функций и функциональных блоков. Входные переменные могут быть соединены только с входными параметрами функции или функционального блока, выходные переменные – только с выходными параметрами функции или функционального блока, входные/выходные переменные – как входами, так и с выходами функции или функционального блока. Также выходной параметр одной функции или функционального блока может быть напрямую соединён с входным параметром другого.
Рис. 4 – Пример соединения переменных, функций и функциональных блоков
Все функциональные блоки могут быть вызваны с дополнительными (необязательными) формальными параметрами: EN (входом) и ENO (выходом). Пример такого функционального блока приведен на рис. 5.
Рис. 5 – Изображение элементарного функционального блока с параметрами EN/ENO
Если функциональный блок вызывается с параметрами EN/ENO и при этом значение EN равно нулю, то алгоритмы, определяемые в функциональном блоке, не будут выполняться. В этом случае значение ENO автоматически устанавливается равным 0. Если же значение EN равно 1, то алгоритмы, определяемые функциональным блоком, будут выполнены. После выполнения этих алгоритмов без ошибок значение ENO автоматически устанавливается равным 1. Если же возникает ошибка во время выполнения этих алгоритмов, то значение ENO будет установлено равным 0. Поведение функционального блока одинаково как в случае вызова функционального блока с EN = 1, так и при вызове без параметров EN/ENO.
Для более компактного соединения входов и выходов различных функций и функциональных блоков используются элементы «Соединение», показанные на рис. 6:
Рис. 6 – Изображение соединений в языке FBD
Они бывают двух видов: входное соединение и выходное выходные соединение. Основная задача соединений – передать значение из одного выхода на другой вход без прямого соединения выхода и входа. На рис. 5.7 показан пример, в котором выходное значение OUT функции BOOL_TO_INT передаётся на вход IN2 функции ADD:
Рис. 7 – Пример использования соединения на FBD диаграмме
Пример программы на языке FBD¶
На рис. 8 приведена FBD диаграмма, состоящая из следующих функциональных блоков: SR0, AND, TP0.
Рис. 8 – пример FBD диаграммы
Функциональный блок SR0 представляет собой Бистабильный SR-триггер. У него имеются входы S1, R1 и выход Q1, а так же дополнительный вход EN и выход ENO, позволяющие включать и выключать выполнение SR0. Выход Q1 с помощью соединён с входом IN1 блока AND, представляющий собой «Логическое И». Вход IN2 типа BOOL соединён с литералом «BOOL#1», который всегда положительный. Выход OUT блока AND соединён с входом IN функционального блока TP0, представляющий собой повторитель импульсов. Вход PT типа TIME, соединён с литералом «T#5s», который задаёт значение 5 секунд.
Если после запуска выполнения данного функционального блока enabled равно True и переменная S1_IN тоже True, функциональный блок SR0 начинает выполняться. На выходе OUT функционального блока AND будет значение True как только Q1 у SR0 будет равен True. Следовательно, как только OUT становится True вход IN функционального блока TP0 принимает тоже True и начинается отсчёт таймера ET (см. рис. 9).
Рис. 9 – Выполнение FBD диаграммы
Пока данный таймер не достигнет значения PT выход Q у функционального блока TP0 будет равен True. При достижении таймером ET значения PT, т.е. через 5 секунд выход Q становится False (см. рис. 10).
Рис. 10 – Выполнение FBD диаграммы
Как только вход IN функционального блока TP0 становится значения FALSE, счётчик ET сбрасывается в T#0s.
Язык непрерывных функциональных схем CFC. Часть 2
Во второй части статьи продолжим рассказ о свойствах и настройках редактора CFC программного пакета CODESYS.
Свойства редактора CFC
Рабочая область редактора CFC имеет ряд полезных настроек. Можно настроить точки сетки (Инструменты – Опции – CFC-редактор – Вид) или оставить по умолчанию белый фон. Для задания фиксированного размера рабочей области должен присутствовать программный код редактора на рабочей области. Делаем на рабочей области и заходим в меню CFC – Редактировать рабочий лист. По умолчанию размер области подстраивается под расположение элементов программы. В правом нижнем углу рабочей области находятся кнопки управления визуальным представлением кода программы: масштабирование ( + ), лупа, захват рабочей области редактора. Лупа существенно упрощает работу с крупными проектами: при выводе всей программы на рабочую область элементы становятся слабо различимыми, и лупа позволяет отчетливо видеть код, не прибегая к масштабированию рабочей области.
Условный оператор на языке CFC и работа с логическими переменными
Реализация условий на языке CFC – часто задаваемый вопрос пользователей. Данная задача решается средствами редактора CFC в два клика: необходимо нажать ПКМ на блоке и выбрать пункт EN/ENO. Блоку добавится «условный» вход EN и выход ENO типа BOOL. Когда на вход EN приходит значение TRUE, то блок становится активен, значение на выходе ENO устанавливается TRUE. Если на вход EN пришло FALSE, то блок «замораживается», на выходе ENO – значение FALSE. «Заморозка» блока означает, что значения на выходе остаются постоянными и равными значениям в последнем цикле контроллера перед выключением блока. Об этом важном моменте нужно всегда помнить. Например, недостаточно отключить блок управления при работе с регуляторами (ПИД, гистерезис), его выходы необходимо обнулить, в противном случае есть вероятность подачи сигнала на открытие задвижки или на нагрев ТЭНа, что может привести к поломке оборудования.
При работе с переменными типа BOOL возникают задачи инвертировать их значения. Для этого нажимаем ПКМ на входе или выходе блока, работающего с логической переменной, и выбираем пункт Инверсия. Примером инверсии «условного» входа EN/выхода ENO служит переключение режима работы двух блоков по сигналу от одной переменной (рис. 2).
Линии связи
Начиная с версии CODESYS V3.5 SP3, проблема с наложением линий связи друг на друга при их близком расположении или на элементы схемы осталась в прошлом. Чтобы не тратить время на перетаскивание элементов схемы и перестроение линий связи, введена функция трассировки. Если автоматическая трассировка не справилась, и возникла ситуация с наложением или некорректным построением линий связи, на помощь приходит ручная трассировка. Для этого потребуется нажать на кнопку трассировки и выбрать Установить все соединения (рис. 3).
Еще одна опция для работы с линиями связи редактора CFC – изменение цвета. В крупных проектах, содержащих большое число линий связи и различные типы данных, разбиение по цветам помогает избежать ошибок при построении схем и отладить уже готовую программу. Изменить цвета линий можно в меню Инструменты, в разделе Опции, на вкладке CFC-редактор, Вид.
Обратные связи
В первой части статьи была рассмотрена автоматическая нумерация блоков в соответствии с потоком данных, которая начала действовать с версии CODESYS V3.5 SP15. Рассмотрим частные случаи автоматической нумерации блоков, охваченных обратной связью (ОС). В первом примере (рис. 4) порядок элементов, охваченных ОС, совпадает с их расположением на рабочей области редактора и с порядком их выполнения: последовательно слева направо.
Во втором примере элементы, охваченные ОС, расположенные в шахматном порядке (рис. 5), нумеруются построчно: сначала элементы верхней строки, затем – нижней.
Аналогичная построчная нумерация элементов, охваченных ОС, показана на рис. 6. Данное свойство автоматической нумерации присуще только элементам, охваченным ОС. При ее отсутствии автоматическая нумерация происходит строго в соответствии с потоком данных.
В версии CODESYS V3.5 SP15 вместе с автоматической нумерацией элементов программы появилась возможность установить порядок выполнения элементов с обратной связью (рис. 7). По умолчанию порядок выполнения элементов с ОС осуществляется в соответствии с потоком данных – слева направо. Чтобы изменить порядок, следует нажать ПКМ на элементе, который должен являться начальным, в открывшемся меню выбрать Порядок выполнения, далее пункт Задать начало обратной связи, тогда над выбранным элементном появится значок Play.
Важно помнить, что при назначении какого-либо элемента начальным в группе элементов с ОС, остальные элементы не нумеруются согласно рассмотренному выше свойству автоматической нумерации. Чтобы избежать ошибок, связанных с порядком выполнения блоков, необходимо внимательно следить за расположением элементов на рабочей области редактора.
Функциональные блоки
Информация этой части статьи важна для многих пользователей. Речь пойдет о разделе VAR_INPUT CONSTANT в функциональных блоках. В раздел записываются пользовательские константы так же, как и в VAR CONSTANT, только с одним отличием: при запущенном приложении значения переменных из раздела VAR CONSTANT изменять нельзя, а из раздела VAR_INPUT CONSTANT – можно.
Важно отметить, что изменять значения констант из раздела VAR_INPUT CONSTANT можно только в программном комплексе CODESYS. Начальное значение переменных можно задать двумя способами: присвоить конкретное значение или привязать внешнюю переменную программы.
Значение внешней переменной записывается в переменную из раздела VAR_INPUT CONSTANT один раз при запуске приложения. На функциональных блоках в коде программы отображается кнопка Параметры, открывающая диалоговое окно, в котором можно задать значения переменных из раздела VAR_INPUT CONSTANT (рис. 8). Кнопка активна и при запущенном приложении. В процессе работы программы на контроллере переменные VAR_INPUT CONSTANT изменять нельзя.
Конверсия данных на CFC
Рассмотрим разные подходы к выполнению арифметических и других операций на языках ST и CFC.
При операции сложения на языке ST складываются две переменные с типами USINT (usiVar1=100 и usiVar2=200), результат присваивается переменной типа UDINT (UINT), тогда операция сложения выполнена верно (uiVar=300) (рис. 9).
Если ту же операцию реализовать на языке CFC, то результат выполненной операции будет неверным (44 вместо 300) (рис. 10). Ошибка является следствием того, что к выходному контакту блока суммы внутри самого блока привязана неявная переменная, которая определяется «наибольшим» типом входных переменных.
Таким образом, результат суммы переменных сначала формируется внутри самого блока (значение неявной переменной), а уже после присваивается переменной, стоящей на выходе блока. Следовательно, при сложении двух переменных типа USINT и ожидаемом результате типа UDINT (UINT) возможно переполнение внутренней неявной переменной, что в конечном итоге приводит к неверному результату. Это решается применением явной конверсии типов хотя бы для одной из входных переменных из типа USINT в UDINT (UINT), тогда тип внутренней неявной переменной установится UDINT (UINT) (рис. 11).
© Автоматизация и Производство, 2021. Все права защищены. Любое использование материалов допускается только с согласия редакции. За достоверность сведений, представленных в журнале, ответственность несут авторы статей.
Издание зарегистрировано Федеральной службой по надзору в сфере связи, информационных технологий и массовых коммуникаций. Свидетельство о регистрации средств массовой информации ПИ № ФС77-68720.