Для нумерации шагов создайте тип данных перечисление (значения имеют тип INT), программа станет более осмысленной.
Пример:
Писать условия IF в начале программы, в которых есть "AND step=Х" незачем - у вас есть ниже CASE - перенесите эти IFы в соответствующие подпункты CASE (TONы, которые выполняются по "IN := step=Х" тоже в принципе можно убрать внутрь CASE, но могут быть нюансы)Код:TYPE enState : ( gc_step_0 := 0 , (* Шаг 1 *) gc_step_1 := 1 , (* Шаг 2 *) gc_step_2 := 2 , (* Шаг 3 *) gc_step_3 := 3 , (* Шаг 4 *) gc_step_4 := 4 , (* Шаг 5 *) gc_step_5 := 5 , (* Шаг 6 *) gc_step_6 := 6 (* Шаг 7 *) ); END_TYPE
Никаких выводов не сделали, зачем вам 8 таймеров, если одного за глаза, только время меняйте и запускайте снова, так же по шагам.
Даже пример готовый выкладывал, только кол-во шагов уменьшить осталось и нужные выходы включать.
Последний раз редактировалось kondor3000; 11.02.2024 в 17:24.
Вы про GetTime? Если да, то я не понимаю как это работает.
Таймер.png
Что не понятного тут? В зависимости от входящего шага State, меняется время для таймера, для каждого шага своё время. Например для шага State=1 время t0=5.
Время в таймере надо задавать в ms, так как время конвертируется PT= UDINT_TO_TIME (CurMinute),
если не умножить на 1000, то вы получите 5ms, и шаги просто пролетят с 1 до 12 за пол секунды.
Умножение на 1000 это перевод времени в секунды, 5*1000=5000ms=5секунд,
а умножение на 60000 перевод в минуты 5*60000=300 000ms=300 секунд=5 минут
Переменная Zad и переключает либо отсчёт в секундах, либо в минутах. Там ведь даже подписано!
Всё что нужно сделать, запустить эмуляцию, нажать Старт и смотреть как работает.
Последний раз редактировалось kondor3000; 11.02.2024 в 19:15.
Спасибо за развернутый ответ! Первым же делом хотел посмотреть как это работает в эмуляции, но при открытии файла вылазит куча ошибок, в том числе и в самой программе.
Безымянный.jpg
Безымянный2.jpg
Безымянный3.jpg
Безымянный4.jpg
Офигеть, вы за столько времени, даже примеры на сайте не открывали?
Просто у вас таргеты не все стоят, как вы будете примеры открывать, они все для разных ПЛК сделаны. Поставьте все таргеты один раз и всё. У меня примеры для ПЛК154UM https://owen.ru/product/codesys_v2/service_po иногда для ПЛК154АM или ПЛК110_60_М
То, что биб-ка другой версии, это фигня, всё будет работать. Главное, что бы она вообще была. Библиотеки тоже желательно все поставить сразу.
https://owen.ru/product/codesys_v2/libraries
Последний раз редактировалось kondor3000; 12.02.2024 в 15:21.
Я повторно предлагаю вам попробовать SFC, чтобы решать подобные задачи
Можно конечно применить эрзац SFC на ST:
Код:FUNCTION_BLOCK SFC VAR_INPUT xInBtnStart, xInBtnStop: BOOL; InTime: INT; END_VAR VAR_OUTPUT OutState: enState; xOutError, xOutCtrl, xOutAdd: BOOL; END_VAR VAR Init: BOOL; NewState: enState := gc_step_0; tTime: TIME; fbBtnStart, fbBtnStop: R_TRIG; fbTON: TON; END_VAR (* КОД ВЫПОЛНЯЕМЫЙ ВСЕГДА *) fbBtnStart(CLK := xInBtnStart); fbBtnStop(CLK := xInBtnStop); xOutError := FALSE; IF NOT Init THEN Init := TRUE; NewState := gc_step_0; ELSE CASE NewState OF (* Шаг 1 *) gc_step_0: (* ДЕЙСТВИЯ ПРИ ВХОДЕ В ШАГ *) IF NewState <> OutState THEN OutState := NewState; END_IF; (* ДЕЙСТВИЯ *) xOutCtrl := xInBtnStart; (* call sw ctrl timer *) fbTON(IN := TRUE, PT := T#10s); (* ПЕРЕХОДЫ *) IF fbBtnStart.Q AND fbTON.Q THEN NewState := gc_step_1; fbTON(IN := FALSE); (* ELSIF УСЛОВИЕ THEN NewState := НОВОЕ СОСТОЯНИЕ; ELSIF УСЛОВИЕ THEN NewState := НОВОЕ СОСТОЯНИЕ; *) END_IF; (* (* ДЕЙСТВИЯ ПРИ ВЫХОДЕ ИЗ ШАГА *) IF NewState <> OutState THEN END_IF; *) (* Шаг 2 *) gc_step_1: (* ДЕЙСТВИЯ ПРИ ВХОДЕ В ШАГ *) IF NewState <> OutState THEN fbTON.PT := T#30s; IF InTime > 0 THEN fbTON.PT := REAL_TO_TIME(InTime * 1000.0); END_IF; END_IF; (* ДЕЙСТВИЯ *) OutState := NewState; xOutCtrl := TRUE; (* call sw ctrl timer *) fbTON(IN := TRUE); (* ПЕРЕХОДЫ *) IF fbBtnStop.Q THEN NewState := gc_step_0; ELSIF fbTON.Q THEN NewState := gc_step_2; fbTON(IN := FALSE); (* ELSIF УСЛОВИЕ THEN NewState := НОВОЕ СОСТОЯНИЕ; ELSIF УСЛОВИЕ THEN NewState := НОВОЕ СОСТОЯНИЕ; *) END_IF; (* (* ДЕЙСТВИЯ ПРИ ВЫХОДЕ ИЗ ШАГА *) IF NewState <> OutState THEN END_IF; *) (* Шаг 3 *) gc_step_2: (* ДЕЙСТВИЯ ПРИ ВХОДЕ В ШАГ *) IF NewState <> OutState THEN OutState := NewState; END_IF; (* ДЕЙСТВИЯ *) xOutError := TRUE; xOutCtrl := FALSE; (* ПЕРЕХОДЫ *) IF fbBtnStop.Q THEN NewState := gc_step_0; (* ELSIF УСЛОВИЕ THEN NewState := НОВОЕ СОСТОЯНИЕ; ELSIF УСЛОВИЕ THEN NewState := НОВОЕ СОСТОЯНИЕ; *) END_IF; (* (* ДЕЙСТВИЯ ПРИ ВЫХОДЕ ИЗ ШАГА *) IF NewState <> OutState THEN END_IF; *) (* ОШИБКА СОСТОЯНИЯ *) ELSE OutState := gc_step_0; END_CASE; (* КОД ВЫПОЛНЯЕМЫЙ ВСЕГДА *) xOutAdd := NewState = gc_step_0 OR gc_step_1; END_IF;
Вот смотрю на варианты и всегда вижу почерк автора...
Кто-то (как ТС) выход таймера через => делает, но использует лишнюю переменную.
Кто-то (как и я) через TIMER.Q...
Сколько людей, столько и решений одной задачи. Поэтому надо свое придумывать, или перенимать наиболее понравившуюся манеру написания...