Как сделать триггер в st кодесис
Перейти к содержимому

Как сделать триггер в st кодесис

  • автор:

Как сделать триггер в st кодесис

Часовой пояс: UTC + 3 часа (Russia: MSK)

Запрошенной темы не существует.

Часовой пояс: UTC + 3 часа (Russia: MSK)

Как реализовать T-триггер в CoDeSys?

Вот на 2-х Функциональных блоках.
TRIG_Vk(CLK:= knopka, Q=> ); (выделяем фронт нажатия кнопки (ФБ R_TRIG))
SR_Vk(SET1:= TRIG_Vk.Q AND NOT SR_Vk.Q1 , RESET:=TRIG_Vk.Q AND SR_Vk.Q1, Q1=> ); (ФБ SR или RS)

03.03.2010, 11:35

спасибо, получилось. правда это тоже 4 блока, но меньше видно нельзя. я проектирую в Fbd:)

03.03.2010, 12:54
Сообщение от Литрович
спасибо, получилось. правда это тоже 4 блока, но меньше видно нельзя. я проектирую в Fbd:)
выделите в отдельный функциональный блок

30.03.2010, 11:49

можно потробнее? желательно на St.
с кодом для фун. блоков и программы.

30.03.2010, 13:35

вопрос новичка в кодесис ,а что в кодесис нет готовых библиотек фб (счетчики ,регистры сдвига,дешифраторы,и.т.д?)

30.03.2010, 14:33
Николаев Андрей

Ну вот, rovki — прям расстроили ;).
Надо подключить библиотеки Util.lib и Standart.lib — там все есть

30.03.2010, 16:53

стыдно,но все это ,в свое время реализовывал на жесткой логике,потом на однокристалках,(локальные сети,бортовые микро эвм,системы диагностики,испытательные стенды,итд,итп) потом на плк без кодесис технологические линии.сейчас другие задачи и участие в форуме -отдушина(ностальгия) по тем временам.и данный вопрос из разряда «для общего развития».:) .будет необходимость-будет и решение.
меня как раз и интересует почему люди имея такую мощь (кодесис) спрашивают как реализовать тот или иной функциональный блок,и существует ли конвертация проектов из одного языка в другой средствами кодесис, внутри кодесис.а на счет фбд -посмотрел -слабовато,ожидал большего, для электронщика ловить нечего,делай все на элементах малой степени интеграции.

Как программировать на codesys 2.3 новичку? Легко

Как программировать на codesys 2.3 новичку? Легко

Перед тем, как программировать ПЛК в среде разработки CoDeSyS 2.3 новички часто задаются вопросом: А какие системы требуется установить для корректной работы с аппаратом?? А как конфигурировать входы и выходы контроллера?? А каким образом связать устройство с ПК?? И снова, а как, а как?? Все мы с вами понимаем, устройства сложные и алгоритмы объёмные, и на изучение потребуется время. Я вот думаю, может написать небольшую книжку и назвать codesys для чайников? А вы согласны?

Из этой статьи вы узнаете:

Здравствуйте уважаемые коллеги и гости. Пишет вам автор блога kip-world.ru, Гридин Семён, и в этой статье я вам расскажу, как правильно программировать контроллер. Тема достаточно актуальная, я надеюсь после прочтения статьи, некоторые вопросы отпадут самим собой. =)

Как работает ПЛК?

ПЛК(программируемый логический контроллер) — это устройства полностью автоматизирующие работу аппаратов, различных агрегатов и станков. Фактически, это некий блок, который содержит входы и выходы, для подключения датчиков и исполнительных органов. Внутри прописывается логика.

Вычисления в устройстве выполняются циклически. То есть одни и те же действия выполнения программы выполняются в короткий промежуток времени.

В один цикл осуществляемый прибором выполняются следующие операции:

  1. Начало цикла;
  2. Чтение состояния входа;
  3. Выполнение кода пользователя;
  4. Запись состояния выходов;
  5. Обслуживание аппаратных ресурсов;
  6. Монитор системы исполнения;
  7. Контроль времени цикла;
  8. Переход на начало цикла;

Не буду больше разглагольствовать по теории. Давайте сразу перейдём к практике.

Из чего состоит программный комплекс для полноценной работы с ПЛК

Конечно вам поначалу покажется, что слишком много нужно знать, чтобы связать друг с другом основное приложение и утилитки, а потом соединить устройство. Я хочу вам сказать, что ничего сложного в процессе установки и связей — нет. В этом поможет моя статья.

Для начала нам нужно установить основной дистрибутив CoDeSyS 2.3 c официального сайта ОВЕН . А, я предлагаю во многих постах, касающихся программирования, использовать устройство ОВЕН ПЛК63 . Так как это универсальное устройство с экраном. У него на борту есть и дискретные входы, и аналоговые входы, и релейные выходы.

Итак, скачиваем программу:

Дистрибутив с сайта

Затем следует стандартная процедура установки. Указываем путь и все время жмём “Далее”, “Далее”.

Инсталл

Следующим этапом будет установка таргетов для плк. Таргет — это некое описание о конфигурации ПЛК. Инструкция подсказывает CoDeSyS 2.3, какое количество и какие входы/выходы имеет устройство.
Скачиваем также с сайта ОВЕН . Рекомендую установить все таргеты, которые там есть. Чтобы потом не искать и не думать об этом, если придется писать алгоритм на другой ПЛК.

Таргеты

Запускаем автоматический установщик, устанавливаем инструкции. Всё, половину пути мы с вами уже сделали в этой работе! После этих всех процедур можно устанавливать библиотеки, но о них позже. Переходим к следующему пункту.

Рабочее окно программы

Дистрибутив мы с вами установили, таргеты тоже. Давайте мы с вами рассмотрим рабочее окно среды разработки, элементы меню и основные вкладки.

Рабочее окно

Основное поле на рисунке выше делится на три области:

  1. Редактор переменных и их типов;
  2. Дерево объектов;
  3. Редактор основного алгоритма программы;

Редактор переменных — здесь мы с вами вводим переменные и присваиваем им типы данных. Для тех, кто не знает, переменная — это имя, к которому будет обращаться программа и возвращать результат. А тип данных определяет род информации, диапазон представления чисел и множество других операций.

Дерево объектов — в этом окне располагаются такие объекты, как функции, функциональные блоки, подпрограммы, конфигурация ПЛК, библиотеки. Об этом я расскажу позже.

Редактор программы — тут мы с вами описываем основной алгоритм программы работы контроллера. Пишется на любом языке стандарта МЭК. Более подробно, можете прочитать статью .

Простой пример на ST

Для удобства восприятия информации я постарался структурировать. Поэтапно расписал последовательность действий. Если возникнут вопросы или пожелания, обязательно пишите в комментариях.

Изначально я размещу в статье код на языке ST. Логика работы заключается в следующем: на дискретный вход прибора подаётся сигнал и через задержку времени включается выход. В принципе задача простая, и мы с вами её решим.

Таймеры и триггеры 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 — функциональный блок «таймер с задержкой включения»

TON(IN, PT, Q, ET)

Входы 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 TON1(); TON TON1(unsigned long PT); // с заданием интервала времени PT
Q = TON1.Run(boolean IN); // вызов "все в одном" TON1.IN = IN; TON1.Run(); Q = TON1.Q;

Временная диаграмма работы TON:

TOF — функциональный блок «таймер с задержкой выключения»

TOF(IN, PT, Q, ET)

Входы 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 TOF1(unsigned long PT); // с заданием интервала времени PT Q = TOF1.Run(boolean IN); // вызов "все в одном"

Временная диаграмма работы TOF:

TP — функциональный блок «импульс-таймер»

TP(IN, PT, Q, ET)

Входы 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 TP1(unsigned long PT); // с заданием интервала времени PT Q = TP1.Run(boolean IN); // вызов "все в одном"

Временная диаграмма работы TP:

R_TRIG — функциональный блок «дeтектор фронта»

Функциональный блок R_TRIG генерирует импульс по переднему фронту входного сигнала. Выход Q равен FALSE до тех пор, пока вход CLK равен FALSE. Как только CLK получает значение TRUE, Q устанавливается в TRUE. При следующем вызове функционального блока выход сбрасывается в FALSE. Таким образом, блок выдает единичный импульс при каждом переходе CLK из FALSE в TRUE.

Пример CODEDESYS на языке ST:

RTRIGInst : R_TRIG ; RTRIGInst(CLK:= VarBOOL1); VarBOOL2 := RTRIGInst.Q;
В Arduino IDE:
R_TRIG R_TRIG1;
Q = R_TRIG1.Run(boolean CLK); // вызов "все в одном" R_TRIG1.CLK = CLK; R_TRIG1.Run(); Q = R_TRIG1.Q;

F_TRIG — функциональный блок «дeтектор спада»

Функциональный блок F_TRIG генерирует импульс по заднему фронту входного сигнала.
Выход Q равен FALSE до тех пор, пока вход CLK равен TRUE. Как только CLK получает значение FALSE, Q устанавливается в TRUE. При следующем вызове функционального блока выход сбрасывается в FALSE. Таким образом, блок выдает единичный импульс при каждом переходе CLK из TRUE в FALSE.

В Arduino IDE:
F_TRIG F_TRIG1; Q = F_TRIG1.Run(boolean CLK); // вызов "все в одном"

RS_TRIG — функциональный блок RS-триггер / SR_TRIG — функциональный блок SR-триггер

Переключатель с доминантой выключения, RS-триггер:

Q1 = RS (SET, RESET1)

Переключатель с доминантой включения:

Q1 = SR (SET1, RESET)

Входные переменные SET и RESET1 — как и выходная переменная Q1 типа BOOL.

В Arduino IDE:
RS_TRIG RS_TRIG1; Q = RS_TRIG1.Run(boolean SET, boolean RESET); // вызов "все в одном"
SR_TRIG SR_TRIG1; Q = SR_TRIG1.Run(boolean SET, boolean RESET); // вызов "все в одном"

Исходный код и пример

plcStandardLib_1.h

/* * plcStandardLib_1.h * * Created on: 01.01.2017 * Author: Admin */ #ifndef PLCSTANDARDLIB_1_H_ #define PLCSTANDARDLIB_1_H_ #if ARDUINO >= 100 #include #else #include #endif /* ------------------- TON ------------------- */ class TON < public: TON(); TON(unsigned long PT); boolean Run(boolean IN); boolean Q; // выходная переменная boolean IN; // входная переменная unsigned long PT; // входная переменная unsigned long ET; // выходная переменная - текущее значение таймера private: boolean _M; // внутренний флаг unsigned long _StartTime; >; /* ------------------- TOF ------------------- */ class TOF < public: TOF(); TOF(unsigned long PT); boolean Run(boolean IN); boolean Q; // выходная переменная boolean IN; // входная переменная unsigned long PT; // входная переменная unsigned long ET; // выходная переменная - текущее значение таймера private: boolean _M; // внутренний флаг unsigned long _StartTime; >; /* ------------------- TP ------------------- */ class TP < public: TP(); TP(unsigned long PT); boolean Run(boolean IN); boolean Q; // выходная переменная boolean IN; // входная переменная unsigned long PT; // входная переменная unsigned long ET; // выходная переменная - текущее значение таймера private: boolean _M; // внутренний флаг unsigned long _StartTime; >; /* ------------------- R_TRIG ------------------- */ class R_TRIG // детектор фронта сигнала < public: R_TRIG(); boolean Run(boolean CLK); boolean CLK; // входная переменная boolean Q; // выходная переменная private: boolean _M; // внутренний флаг >; /* ------------------- F_TRIG ------------------- */ class F_TRIG // детектор спада сигнала < public: F_TRIG(); boolean Run(boolean CLK); boolean CLK; // входная переменная boolean Q; // выходная переменная private: boolean _M; // внутренний флаг >; /* ------------------- RS_TRIG ------------------- */ class RS_TRIG // детектор спада сигнала < public: RS_TRIG(); boolean Run(); boolean Run(boolean SET, boolean RESET); boolean SET; // установка триггера boolean RESET; // сброс триггера boolean Q; // выходная переменная //private: >; /* ------------------- SR_TRIG ------------------- */ class SR_TRIG // детектор спада сигнала < public: SR_TRIG(); boolean Run(); boolean Run(boolean SET, boolean RESET); boolean SET; // установка триггера boolean RESET; // сброс триггера boolean Q; // выходная переменная //private: >; #endif /* PLCSTANDARDLIB_H_ */ 

plcStandardLib_1.cpp

/* * plcStandardLib_1.h * * Created on: 01.01.2017 * Author: Admin */ #include "plcStandardLib_1.h" /* ------------------- TON ------------------- */ TON::TON() < IN = false; PT = 0; _M = false; _StartTime = 0; Q = false; ET = 0; >TON::TON(unsigned long PT) < IN = false; TON::PT = PT; _M = false; _StartTime = 0; Q = false; ET = 0; >boolean TON::Run(boolean IN) < TON::IN = IN; if (!TON::IN) < Q = false; ET = 0; _M = false; >else < if (!_M) < _M = true; // взводим флаг М _StartTime = millis(); // ET = 0; // сразу = 0 >else < if (!Q) ET = millis() - _StartTime; // вычисляем время >if (ET >= PT) Q = true; > return Q; > /* ------------------- TOF ------------------- */ TOF::TOF() < IN = false; PT = 0; _M = false; _StartTime = 0; Q = false; ET = 0; >TOF::TOF(unsigned long PT) < IN = false; TOF::PT = PT; _M = false; _StartTime = 0; Q = false; ET = 0; >boolean TOF::Run(boolean IN) < TOF::IN = IN; if (TOF::IN) < Q = true; ET = 0; _M = true; >else < if (_M) < _M = false; // сбрасываем флаг М _StartTime = millis(); // ET = 0; // сразу = 0 >else < if (Q) ET = millis() - _StartTime; // вычисляем время >if (ET >= PT) Q = false; > return Q; > /* ------------------- TP ------------------- */ TP::TP() < IN = false; PT = 0; _M = false; _StartTime = 0; Q = false; ET = 0; >TP::TP(unsigned long PT) < IN = false; TP::PT = PT; _M = false; _StartTime = 0; Q = false; ET = 0; >boolean TP::Run(boolean IN) < TP::IN = IN; if (!_M) < if (TP::IN) < _M = true; // взводим флаг М _StartTime = millis(); if (ET < PT) Q = true; >> else < if (Q) < ET = millis() - _StartTime; // вычисляем время if (ET >= PT) Q = false; > else < if (!TP::IN) < _M = false; ET = 0; >> > return Q; > /* ------------------- R_TRIG ------------------- */ R_TRIG::R_TRIG() < CLK = false; _M = false; Q = false; >boolean R_TRIG::Run(boolean CLK) < R_TRIG::CLK = CLK; Q = R_TRIG::CLK && !_M; _M = R_TRIG::CLK; return Q; >F_TRIG::F_TRIG() < CLK = false; _M = true; Q = false; >boolean F_TRIG::Run(boolean CLK) < F_TRIG::CLK = CLK; Q = !F_TRIG::CLK && !_M; _M = !F_TRIG::CLK; return Q; >/* ------------------- RS_TRIG ------------------- */ RS_TRIG::RS_TRIG() < SET = false; RESET = false; Q = false; >boolean RS_TRIG::Run(boolean SET, boolean RESET) < RS_TRIG::SET = SET; RS_TRIG::RESET = RESET; Q = !RESET and (SET or Q); return Q; >boolean RS_TRIG::Run() < Q = !RESET and (SET or Q); return Q; >/* ------------------- SR_TRIG ------------------- */ SR_TRIG::SR_TRIG() < SET = false; RESET = false; Q = false; >boolean SR_TRIG::Run(boolean SET, boolean RESET) < SR_TRIG::SET = SET; SR_TRIG::RESET = RESET; Q = SET or (!RESET and Q); return Q; >boolean SR_TRIG::Run()

plcStandardLib_1_example.ino

#include "plcStandardLib_1.h" #define LED 13 #define ButtonIn 7 TON TON1(500); // Инициализация задержки включения, 500мс. TON TON2(1000); // Инициализация задержки включения, 1000мс. TOF TOF1(500); // Инициализация задержки выключения, 500мс. TP TP1(300); // Инициализация единичного импульса, 300мс. TP TP2(200); // Инициализация единичного импульса, 200мс. R_TRIG R_TRIG1; // Инициализация триггера фронта для кнопки void setup() < pinMode(ButtonIn, INPUT_PULLUP); pinMode(LED, OUTPUT); >void loop() < digitalWrite(LED, TP1.Run(R_TRIG1.Run(TON1.Run(digitalRead(ButtonIn))))); // TON1 - фильтрует дребезг контакта // R_TRIG1 - детектирует фронт сигнала // TP1 - генерирует импульс по фронту digitalWrite(LED, TP2.Run(TON2.Run(!TON2.Q))); // генератор импульса на базе TON и TP // TON2.Run(!TON2.Q)) - генератор единичного импульса // TP2 - генерирует импульс по фронту digitalWrite(LED, TOF1.Run(TON1.Run(digitalRead(ButtonIn)))); // Задержка включения и отключения >

Например, чтобы отфильтровать дребезг контактов кнопки (при размыкании тоже!) достаточно вот такого кода:

FiltredButtonIn = TON1.Run(digitalRead(ButtonIn))

В качестве заключения: вот так в CODESYS выглядит работа генератора импульса на базе цепочки таймеров TON и TP. В начале TON охватывается обратной связью с инверсией, и из него получается генератор единичного импульса, который запускает работу импульс-генератора TP. В моем примере Arduino аналог этого выглядит так:

digitalWrite(LED, TP2.Run(TON2.Run(!TON2.Q)));

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *