PDA

Просмотр полной версии : Прикол с TP, TON и TOF



Горшунов Сергей
10.03.2009, 16:05
Ситуация следующая:
Составляю программку на SFC, в каждом шаге пишу задержку по времени и привязываю ее к активному шагу. Переходы это сработка выхода ФБ после задержки. По идее когда выходит из шага должна входная переменная ФБ задержка (активный шаг) сбрасываться в ложь. Так все и происходит в режиме эмуляции - все вроде нормально, а вот на практике почему - то не всегда, то есть бывает что при повторном вызове шага оказывается, блок задежки уже отработал. Поэтому приходится в каждом шаге, где я использую задержку вставлять выходное действие по обнулению входа ФБ задержка.
После такого уже стопроцентно всегда ФБ задержка при повторном вызове оказывается "чистым".
Почему?

Dmitry
12.03.2009, 16:12
Попробуй к каждому щагу добавлять действие по выходу примерно такого содержания (time1 типа TP, TON или TOF):

time1.in:=false;
time1;

Партизан
12.03.2009, 17:28
..а вот на практике почему - то не всегда, то есть бывает что при повторном вызове шага оказывается, блок задежки уже отработал.

Странно... Почему не всегда? По идее без обнуления в выходном действии таймер и не должен сбрасываться

Я для таких вещей использую примерно такую схему:

Внутри шага
timer1 (IN:=TRUE, PT:=t#10s);

В выходном действии
timer1 (IN:=FALSE);

Условие перехода timer1.Q

И все четко работает. Чего и вам желаю.

Горшунов Сергей
13.03.2009, 13:58
В том то и дело, что и я так же делаю при выходе из шага, а по идеи так быть не должно.
См. изначальный пост.
То есть я в шаге на вход таймеру (TON, TOF, TP - значения не имеет)подаю не просто true а номер активного шага, в котором он используется:
Объяснение на пальцах:
Активный шаг : step1
timer1 (IN:=step1, PT:=t#10s); переход : timer1.Q
При выходе из шага он становится не активным, соответственно и переменная статуса шага step1 получает ложь, таймер в этом случае должен обнулиться.
Так и происходит например при написании небольшого примера на SFC и эмуляции. Но когда я все это дело в реальной программе делаю и заливаю в ПЛК, запускаю в работу - все это дело начинает само по себе работать: таймеры обнуляются через раз а то и через два, в общем когда захотят тогда и обнуляются по логике вещей такого быть не должно!
Как это так на примере работает, а на реальной программе нет!????:eek:
Просто мне:
1) интересен данный факт
2) надоело при выходе из шага писать действие по "обнулению" счетчика.

Горшунов Сергей
13.03.2009, 14:18
Вот кстати примерчик по быстрому накатал.
Интересный факт:
TON в данном примере работает нормально, а TP ненормально.
Принцип один и тот же. Почему? Даже если вторым переходом ставить отрицание, он всеравносразу переход делает.
Насколько я правильно понимаю систему исполнения алгоритм ее работы таков:
чтение входов - выполнение шага - проверка условия перехода -
если правда - запись выходов и переход на другой шаг
Если ложь - цикл заново
А здесь получается
сначала проверка условия, а уж потом все остальное

Игорь Петров
13.03.2009, 16:50
..Насколько я правильно понимаю систему исполнения алгоритм ее работы таков:
чтение входов - выполнение шага - проверка условия перехода - если правда - запись выходов и переход на другой шаг Если ложь - цикл заново...
Не точно. На каждый шаг есть 2 флага. Из них получается 4 комбинации: шаг не активен – ничего не делать, только что получил активность – выполнить входное действие, имеет активность – выполнять основное действие, потерял активность – выполнять выходное действие. В любом случае реакция на изменение активности произойдет только в след. цикле вызова.

В вышеописанном алгоритме все как-то на соплях. Шаг потерял активность и действие уже не вызывается, но еще делается попытка нечто подсунуть таймеру. Каким-то чудом это иногда получается… Вариант от Партизан совершенно четкий.


..надоело при выходе из шага писать действие по "обнулению" счетчика...
Дык и не надо тут таймеры применять. Если используем МЭК SFC, то там есть действия управляемые по времени. В упрощенном SFC ставим в атрибутах шага минимальное время и все дела. Никаких таймеров. Подробнее: http://www.prolog-plc.ru/docs/iecdeb07.pdf

Горшунов Сергей
13.03.2009, 22:19
В вышеописанном алгоритме все как-то на соплях. Шаг потерял активность и действие уже не вызывается, но еще делается попытка нечто подсунуть таймеру. Каким-то чудом это иногда получается… Вариант от Партизан совершенно четкий.


Вот это мне и интересно почему же все таки это происходит? Так сказать на соплях...
Недоработка системы программирования? Или я что-то не понимаю. Ведь нестабильность работы - признак недоработки...

Crusash
06.07.2009, 10:15
Здраствуйте, я реализую задержку также как и Партизан(если я его правельно понял), вот моя функция:


tmrZ(In:=start_tmr,pt:=T#1450MS);
IF ACP_get_zapros=1 THEN
start_tmr:=FALSE;
//выполняю первую процедуру
ACP_get_zapros:=7;
start_tmr:=TRUE;
END_IF
IF ACP_get_zapros=7 AND tmrZ.Q=TRUE THEN
start_tmr:=FALSE;
//выполняю вторую процедуру
ACP_get_zapros:=0;
start_tmr:=TRUE;
END_IF

Где tmrZ:TON

Проблема в том что tmrZ, get_zapros и start_tmr приходится обьявлять как Глобальные переменные, потому что обьявлять внутри функции както боязно. Как можно их локализовать(кроме конечно ACP_get_zapros управляющая функцией) и гарантировать их жизнь? Потому как подобных процедур у меня много, а плодить стока переменных совсем не хочется.

И какие ещё есть методы реализации зодержки?

Pruvet
06.07.2009, 10:40
Здравствуйте!
В своем коде я использую функцию задержки из примера со светофором документа CodeSys_V23_RU.pdf

Экземпляр функции объявлен в области глобальных переменных.

DELAY:WAIT;

Перед каждым шагом, в котором я использую задержку
я сбрасываю таймер:
DELAY.ZAB(IN:=0)

Шаг с задержкой выглядит так:
DELAY(TIME_IN:=время)

Во время работы шага с задержкой не дожидаясь окончания задержки ПО может сбросить цикл программы на Init (например по нажатию кнопки на панели ОПЕРАТОРА),
а после этого неостановившийся таймер продолжает считать, и
команда:
DELAY.ZAB(IN:=0)
его не сбрасыывает, т.е. выход Q экземпляра TP ZAB не равен FALSE.

Как корректно сбросить экземпляр TP?

Игорь Петров
06.07.2009, 14:14
tmrZ(In:=start_tmr,pt:=T#1450MS);
IF ACP_get_zapros=1 THEN
start_tmr:=FALSE; //обнулили вход экземляра ФБ
....
start_tmr:=TRUE; //и сразу опять установили
//в след. цикле вызываем ФБ с опять установленным
входом. Итого, никто его со сброшенным входом ни разу не вызвал и сделать свою работ по сбросу шансов у него нет... в ST с этим нужно тщательнее.

И какие ещё есть методы реализации зодержки?
См. функцию Time()

Игорь Петров
06.07.2009, 14:33
Экземпляр функции объявлен в области глобальных переменных.


Функции не имеют экземпляров.



DELAY.ZAB(IN:=0)

Это нормальный сброс, но учтите что таймер управляется
перепадами сигналов. Если перед этим он вызывался с 1, теперь с 0, то будет сброс.

* При наблюдении значений переменных в отладчике, нужно совершенно четко понимать, что отображает и считывает он данные из контроллера асинхронно, несколько раз в секунду. Контроллер за это время несколько сотен циклов прокрутит. Переменная могла 200 раз поменяться, а на экране видно не будет. См. трассировку.

* В SFC действие шага выполняется последний раз уже после того как шаг активность потерял!!! В это время уже работает след. шаг. Таково требование стандарта МЭК. В этом есть глубокий смысл (если интересно, то поясню какой).

Crusash
06.07.2009, 14:40
Ну так он сбрасываться должен с помощью DELAY.ZAB(IN:=false) , почему ты на вход ТР посылаешь 0 и CDS на это не ругается, непонятно!!!
А вообще в самой функции стоит прописать сразу после инициализации сброс входа в false...
А ещё лучше используй TON...

Crusash
06.07.2009, 15:11
tmrZ(In:=start_tmr,pt:=T#1450MS);
IF ACP_get_zapros=1 THEN
start_tmr:=FALSE; //обнулили вход экземляра ФБ
....
start_tmr:=TRUE; //и сразу опять установили
//в след. цикле вызываем ФБ с опять установленным
входом. Итого, никто его со сброшенным входом ни разу не вызвал и сделать свою работ по сбросу шансов у него нет... в ST с этим нужно тщательнее.
Точно точно, затупил малёк, странно что тот пример у мя отробатывает))), но правельнее так:

IF ACP_get_zapros=1 THEN
start_tmr:=FALSE;
tmrZ(In:=start_tmr,pt:=T#1450MS);
//выполняю первую процедуру
ACP_get_zapros:=7;
start_tmr:=TRUE;
tmrZ(In:=start_tmr,pt:=T#1450MS);
END_IF
IF ACP_get_zapros=7 AND tmrZ.Q=TRUE THEN
//выполняю вторую процедуру
ACP_get_zapros:=0;
END_IF

И всётаки, если я эти переменные (tmrZ и start_tmr) объявлю в этой функции, скока они жть будут? Или в КДС об этом можно не думать?

Игорь Петров
06.07.2009, 15:13
FALSE и 0 нет разницы.
Про TON правильный совет. TP обязан отработать интервал всегда, 0 на входе или 1 ему до фонаря, если его запустили, то он выдаст импульс четко заданной длительности.

Игорь Петров
06.07.2009, 15:19
И всётаки, если я эти переменные (tmrZ и start_tmr) объявлю в этой функции, скока они жть будут? Или в КДС об этом можно не думать?

Думать надо. Все же из примера не видно это именно функция или ФБ... В функции будут обновляться при каждом ее вызове. Тут надо сделать ФБ, объявить все локально, и переменные будут жить вечно :) Не надо их глобальными делать.

Crusash
06.07.2009, 15:28
Думать надо. Все же из примера не видно это именно функция или ФБ... В функции будут обновляться при каждом ее вызове. Тут надо сделать ФБ, объявить все локально, и переменные будут жить вечно :) Не надо их глобальными делать.
Большое спасибо, что прояснили этот момент...
А если в PROGRAM сделать, переменные долго проживут?
...
забыл уточнить: почему не сробатывает такой вызов tmrZ.IN:=TRUE;
вход меняется, а выходы нет...

Pruvet
06.07.2009, 16:58
Ну так он сбрасываться должен с помощью DELAY.ZAB(IN:=false) , почему ты на вход ТР посылаешь 0 и CDS на это не ругается, непонятно!!!
А вообще в самой функции стоит прописать сразу после инициализации сброс входа в false...
А ещё лучше используй TON...

Спасибо за совет, уже внимательно почитал PDF, особенно диаграммы работы и сделал TON, заработало...

Игорь Петров
07.07.2009, 14:59
А если в PROGRAM сделать, переменные долго проживут?

Да, долго. Программа похожа на ФБ, но не имеет экземпляров. Например, написал я свой таймер. Ну из программы 1 могу сделать. Все. Сделать их несколько, чтобы каждый имел свои внутренние данные = разные времена запуска, выдержки... никак, тут только ФБ с экземплярами.

Обычно 'программы' делают на верхнем уровне. Если многозадачный проект, то он имеет несколько программ, связанных с задачами. Внутри программы используем функции и ФБ.



забыл уточнить: почему не сробатывает такой вызов tmrZ.IN:=TRUE;
вход меняется, а выходы нет...
Дык это и не вызов совсем. Это просто изменение входа. Можно заранее все нужные входы поустанавливать в разных местах, затем вызов сделать совсем пустой, типа:
tmrZ;

Для полного понимания, подумайте над этим: допустим нужна такая штука как блок данных. Т.е. никакого кода, просто некий набор взаимосвязанных данных. В CoDeSys делаем пустой ФБ, без кода, только с переменными и получаем что надо. Это имеет право на жизнь. Можно наделать экземпляров этих блоков, хранить в них данные, обращаясь через точку. Это и есть метод работы с данными без вызова самого ФБ.

Crusash
08.07.2009, 11:20
Отлично, всё встаёт на свои места,
спасибо что объяснили...

Сергей71
08.07.2009, 14:08
Для полного понимания, подумайте над этим: допустим нужна такая штука как блок данных. Т.е. никакого кода, просто некий набор взаимосвязанных данных. В CoDeSys делаем пустой ФБ, без кода, только с переменными и получаем что надо. Это имеет право на жизнь. Можно наделать экземпляров этих блоков, хранить в них данные, обращаясь через точку. Это и есть метод работы с данными без вызова самого ФБ.

А можно в ФБ добавить Action (Save, Read итп) и и вызывая ФБ().Read или ФБ().Save писать и читать, например в файл.