Просмотр полной версии : Таймеры, переменные и условия
Здравствуйте уважаемые форумчане, прошу подтолкнуть в сторону решения следующей задачи:
есть три булевые переменные vent1,vent2,vent3. Все они включаюся по тамеру, который определяет время работы(true) и время паузы(false) у каждой переменной отдельно, как организоавать цикл для проверки следующего условия:
Если таймер переменной подошел к запуску то проверить, что другие(другая) перменные уже работают более 3 секунд или до их остановки более 3 секунд, то запуститься сразу иначе отложить запуск переменой на 5 секунд.
Под запуском понимается переход в true.
vent1(ENABLE:=stop_vent1, TIMELOW:=Pause_Time1 , TIMEHIGH:=Run_Time1 , OUT=> );
Timer_Run1(IN:=vent1.OUT, PT:=Run_Time1 , Q=> , ET=> );
Timer_Pause1(IN:=NOT vent1.OUT, PT:=Pause_Time1 , Q=> , ET=> );
Pause_Time1 и Run_Time1 переменные для задачи времени
Stop_Vent1 булевая переменная аварийной остановки
Timer_Run1 и Timer_Pause1 таймеры для вывод информации о текущем времени работы и паузы
out1, out2, out3 непосредственно дискретные выходы плк
IF vent2.OUT THEN
IF (Vent1.out AND Timer_Run1.ET < T#3s) OR (Stop_Vent1 AND (NOT out1 AND (Pause_Time1-Timer_Pause1.ET < T#3s))) THEN
out2_ton(in:=TRUE, pt:=T#5s);
out2:=out2_ton.Q;
ostalos2:=(Run_Time2-Timer_Run2.ET);
ELSE
out2:=TRUE;
ostalos2:=(Run_Time2-Timer_Run2.ET);
END_IF
ELSE
out2:=FALSE;
out2_ton(in:=FALSE, pt:=T#0s);
ostalos2:=(Pause_Time2-Timer_Pause2.ET);
END_IF
вот творчество пока на этом зависло...
Обновление переменных, связанных с таймером (например, TON) происходит не само по себе, а только при вызове ФБ - т.е. нужно вызовы ФБ выполнять не в ветках IF, а в основной части, а in:=true/false формировать при помощи переменной. Иначе в ELSE вложенного IF обновление out2_ton.out прекратится.
А по алгоритму. Сейчас пытаюсь решить подобную задачу.
Т.к. программа (на любом из языков IEC) выполняется не одновременно, а последовательно слева направо и сверху вниз, то значит для агрегата (вентилятора) №1 будут актуальны блокировки пуска от других вентиляторов из прошлого машинного цикла.
Т.е. нужны комплекты переменных для каждого агрегата:
- bRequestStart1...3 - запрос включения (из алгоритма)
- bStart1...3 - состояние включения (то, что на пускатель пойдёт)
- bStartPrevious1...3 - состояние включения (то, что на пускатель пойдёт) на предыдущем машинном цикле
- bSwitchingNow1...3 - выполняется отсчёт паузы по переключению от 1 (...3) к остальным агрегатам
- bSwitchingEn1...3 - разрешение 1 (...3) агрегату менять состояние
- таймеры импульсов TP1...3 - для отсчёта паузы запрещающей переключение другим.
Для каждого агрегата определять:
1. разрешение менять состояние bSwitchingEn1 := not(bSwitchingNow2 or bSwitchingNow3)
2. если есть разрешение и необходимость изменения, то изменить состояние
if bSwitchingEn1 and (bRequestStart1 <> bStart1) then
bStart1 := bRequestStart1;
end_if
3. запустить отсчёт таймера TP по условию изменения состояния (bStart1 xor bStartPrevious1) сам таймер за пределами IF
4. изменить состояние bSwitchingNow1 := TP1.out, по которому заблокируется потом переключение других агрегатов
5. обновить bStartPrevious1 := bStart1
И потом повторить это для каждого из агрегатов.
Именно такими блоками и размножить, т.к. код выполняется последовательно и по мере выполнения могут блокироваться переключения для нижерасположенных агрегатов.
У меня код на FBD и не отлажен, для другой среды разработки - показывать нечего.
Мне кажется так нужно
.. для проверки следующего условия:
Если таймер переменной подошел к запуску то проверить, что другие(другая) перменные уже работают более 3 секунд или до их остановки более 3 секунд, то запуститься сразу иначе отложить запуск переменой на 5 секунд..
Это через анус сказано что пауза между переключениями вентов должна быть не менее чем что-то?
Можно и подтолнуть:
Pause : BOOL;
TMR1, TMR2, TMR3 : TON;
TMR_Pause : TOF;
// Отсчёт времени работы или простоя
TMR1(IN := TRUE, PT := SEL(vent1, Pause_Time1, Run_Time1));
TMR2(IN := TRUE, PT := SEL(vent2, Pause_Time1, Run_Time1));
TMR3(IN := TRUE, PT := SEL(vent3, Pause_Time1, Run_Time1));
TMR_Pause(IN := Pause, PT := T#5s); // Таймер паузы - перезапустится, если нужна пауза
Pause := FALSE;
IF NOT TMR_Pause.Q THEN // Пауза выдержана
IF TMR1.Q AND NOT vent1 THEN // Пришло время включить vent1
IF vent2 THEN // vent2 - работает
Pause := Pause OR (TMR2.ET < T#3s OR TMR2.PT - TMR2.ET < T#3s); // если работает меньше 3s или должен скоро остановиться - нужна пауза
END_IF
IF vent3 THEN // vent3 - работает
Pause := Pause OR (TMR3.ET < T#3s OR TMR3.PT - TMR3.ET < T#3s); // если работает меньше 3s или должен скоро остановиться - нужна пауза
END_IF
vent1 := NOT Pause; IF vent1 THEN TMR1(IN := FALSE); END_IF// Запуск vent1 и сброс таймера
END_IF
IF TMR2.Q AND NOT vent2 THEN // Пришло время включить vent2
IF vent1 THEN // vent2 - работает
Pause := Pause OR (TMR1.ET < T#3s OR TMR1.PT - TMR1.ET < T#3s); // если работает меньше 3s или должен скоро остановиться - нужна пауза
END_IF
IF vent3 THEN // vent3 - работает
Pause := Pause OR (TMR3.ET < T#3s OR TMR3.PT - TMR3.ET < T#3s); // если работает меньше 3s или должен скоро остановиться - нужна пауза
END_IF
vent2 := NOT Pause; IF vent2 THEN TMR2(IN := FALSE); END_IF // Запуск vent2 и сброс таймера
END_IF
IF TMR3.Q AND NOT vent3 THEN // Пришло время включить vent3
IF vent1 THEN // vent1 - работает
Pause := Pause OR (TMR1.ET < T#3s OR TMR1.PT - TMR1.ET < T#3s); // если работает меньше 3s или должен скоро остановиться - нужна пауза
END_IF
IF vent2 THEN // vent2 - работает
Pause := Pause OR (TMR2.ET < T#3s OR TMR2.PT - TMR2.ET < T#3s); // если работает меньше 3s или должен скоро остановиться - нужна пауза
END_IF
vent3 := NOT Pause; IF vent3 THEN TMR3(IN := FALSE); END_IF // Запуск vent3 и сброс таймера
END_IF
END_IF
IF TMR1.Q AND vent1 THEN // Пришло время выключить vent1
vent1 := FALSE; TMR1(IN := FALSE); // Стоп vent1 и сброс таймера
END_IF
IF TMR2.Q AND vent2 THEN // Пришло время выключить vent2
vent2 := FALSE; TMR2(IN := FALSE); // Стоп vent2 и сброс таймера
END_IF
IF TMR3.Q AND vent3 THEN // Пришло время выключить vent3
vent3 := FALSE; TMR3(IN := FALSE); // Стоп vent3 и сброс таймера
END_IF
У меня для 5 агрегатов в Owen Logic так получилось
В OwenLogic нет возможности передать время, поэтому в ФБ передаётся целое число с последующим преобразованием в тип time, из-за выбора единиц измерения входной переменной в секундах, домножаю на 1000.
bEnable - это для назначения всех выходов в выключенное состояние - например, при аварийном останове или на период инициализации после подачи питания.
FUNCTION_BLOCK NotAllAtOnce5_
VAR_INPUT
bEnable: BOOL;
bRequest1: BOOL;
bRequest2: BOOL;
bRequest3: BOOL;
bRequest4: BOOL;
bRequest5: BOOL;
nDelay_s: UDINT;
END_VAR
VAR_OUTPUT
bStart1: BOOL;
bStart2: BOOL;
bStart3: BOOL;
bStart4: BOOL;
bStart5: BOOL;
END_VAR
VAR
tDelay: TIME;
bStartPrevious1: BOOL;
bStartPrevious2: BOOL;
bStartPrevious3: BOOL;
bStartPrevious4: BOOL;
bStartPrevious5: BOOL;
tpPause: SYS.TP;
bSwitchEn: BOOL; // разрешение изменить состояние
END_VAR
// преобразование типа и пересчёт значения в [с]
tDelay := UDINT_TO_TIME(nDelay_s * 1000);
// ограничение минимального значения
IF tDelay < T#1s THEN
tDelay := T#1s;
END_IF
// присвоение таймеру для уменьшения параметров в следующих вызовах
tpPause(T := tDelay);
IF bEnable THEN
// обработка для агрегата 1
bSwitchEn := NOT(tpPause.Q) AND (bRequest1 <> bStart1);
IF bSwitchEn THEN
bStart1 := bRequest1;
END_IF
tpPause(I := bSwitchEn); // обновление значения выхода таймера для следующего обработчика
// обработка для агрегата 2
bSwitchEn := NOT(tpPause.Q) AND (bRequest2 <> bStart2);
IF bSwitchEn THEN
bStart2 := bRequest2;
END_IF
tpPause(I := bSwitchEn); // обновление значения выхода таймера для следующего обработчика
// обработка для агрегата 3
bSwitchEn := NOT(tpPause.Q) AND (bRequest3 <> bStart3);
IF bSwitchEn THEN
bStart3 := bRequest3;
END_IF
tpPause(I := bSwitchEn); // обновление значения выхода таймера для следующего обработчика
// обработка для агрегата 4
bSwitchEn := NOT(tpPause.Q) AND (bRequest4 <> bStart4);
IF bSwitchEn THEN
bStart4 := bRequest4;
END_IF
tpPause(I := bSwitchEn); // обновление значения выхода таймера для следующего обработчика
// обработка для агрегата 5
bSwitchEn := NOT(tpPause.Q) AND (bRequest5 <> bStart5);
IF bSwitchEn THEN
bStart5 := bRequest5;
END_IF
tpPause(I := bSwitchEn); // обновление значения выхода таймера для следующего обработчика
ELSE
// отсчёт от момента выключения, для паузы при быстром переключении bEnable
tpPause(I := bStart1 OR bStart2 OR bStart3 OR bStart4 OR bStart5);
// выключить все агрегаты
bStart1 := FALSE;
bStart2 := FALSE;
bStart3 := FALSE;
bStart4 := FALSE;
bStart5 := FALSE;
END_IF
bStartPrevious1 := bStart1;
bStartPrevious2 := bStart2;
bStartPrevious3 := bStart3;
bStartPrevious4 := bStart4;
bStartPrevious5 := bStart5;
END_FUNCTION_BLOCK
Большая благодарность за ваши ответы. EFrol, Вы не то, что подтолкнули, Вы дали просто готовое работающее решение, бери да вставляй. FPavel, и Вам большое спасибо, вчера разбирался с кодом, ради интереса попробовал ИИ, он тоже подтолкнул к идеи Вашего кода, но естественно его примеры не работали. Единственно интерсеный нюанс по коду EFrol:
vent1 := NOT Pause; IF vent1 THEN TMR1(IN := FALSE);
если установить значение время работы для соответствующего таймера равное 0, ну для постоянной паузы вентилятора например (профилактика и т.д.), значение vent1 может "дернуться", понятно что это столько кратковременно, и в железе по факту ничего не происходит, но при откладке в codesys видно, хоть и не всегда, полагаю, что во время исполнения условия, какуюто ничтожную долю времени переменная успевает перевернуться?
ну и в довесок, если нужно vent на стоп поставить, делать время работы 0, или лучше цикл с проверкой переменной Stop_vent? Как правильно?
ну и в довесок, если нужно vent на стоп поставить, делать время работы 0, или лучше цикл с проверкой переменной Stop_vent? Как правильно?
Work1, Work2, Work3 : BOOL; // В работе или нет
// Уже работающие - надо бы выключить не дожидаясь окончания времени работы
IF NOT Work1 THEN vent1 := FALSE; END_IF
IF NOT Work2 THEN vent2 := FALSE; END_IF
IF NOT Work3 THEN vent3 := FALSE; END_IF
// Не работающие таймеры тоже выключить
// Отсчёт времени работы или простоя
TMR1(IN := Work1, PT := SEL(vent1, Pause_Time1, Run_Time1));
TMR2(IN := Work2, PT := SEL(vent2, Pause_Time1, Run_Time1));
TMR3(IN := Work3, PT := SEL(vent3, Pause_Time1, Run_Time1));
тоже так подумал, кроме циклов с отключением уже работающих, но с ними вообще самое то. еще раз большое спасибо за уделенное время.
Powered by vBulletin® Version 4.2.3 Copyright © 2026 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot