PDA

Просмотр полной версии : Странное поведение таймера TON, обьявленного как Retain



Мамонов Михаил
25.12.2019, 22:35
Столкнулся со странностью работы таймера TON, объявленного как Retain: при отключении питания контроллера и последующем включении обратно выход таймера ET становится равным PT, соответственно Q=True, независимо от того, какое значение ET было в момент отключения питания. Проявилось на контроллере ПЛК110-24.60-Р.М, прошивка 1.0.11, таргет 3.18.
Для иллюстрации сделал маленькую программку для проверки:
46408
Переменной Start передергиваю таймер, чтобы пошел отсчет времени, и отключаю питание ПЛК примерно на 10..15 секунде. Делаю паузу секунд 30 и вновь включаю ПЛК. Подключаюсь к нему CoDeSys и вижу вот такое:
46409
Выход таймера установлен в True, ET=10min. Но 10 минут гарантированно не прошло, даже минуты еще не прошло!
Если объявление таймера перенести из VAR RETAIN в просто VAR, то таймер после подачи питания начинает считать сначала.
Что это может быть такое с таймером?

приборист
25.12.2019, 22:48
Все с таймером хорошо. Просто он так не умеет.
Нельзя TON остановить или продолжить.
Нужен другой таймер с паузой.

Мамонов Михаил
25.12.2019, 22:57
Да мне и не надо его продолжать, мне надо чтоб он считал в соответствии со своим входом IN. Просто получается так, что таймер используется в функциональном блоке, в котором есть Retain переменные, и CoDeSys автоматом объявляет все внутри этого блока как Retain. Соответственно после передергивания питания все таймеры, которые есть в этом блоке, оказываются сработавшими.

Мамонов Михаил
25.12.2019, 23:01
В догонку, и возможно это является причиной - также странно ведет себя функция TIME(), которая должна возвращать количество миллисекунд, которое прошло от момента подачи питания:
Вот что получается сразу после подачи питания:
46410
Какое то огромное число она возвращает, а секунд через 15..20 благополучно сбрасывается в 0 и начинает считать сначала:
46411
Где-то на форуме промелькнуло, что таймеры из Standard.lib работают, основываясь на этом системном счетчике - может поэтому и таймер срабатывает, т.к. текущее время контроллера в будущее улетает сначала?

PS. Это TIME() не в будущее улетает, это она показывает минус 23 секунды (DINT), потом досчитывает до FFFF FFFF, переходит через 0 и тогда уже нормально считает.
Очень бы хотелось увидеть комментарий от разработчиков - это нормальное поведение или ошибка?

PPS. Сделал блокировку - не разрешаю работать таймерам, пока TIME() не перейдет через 0 - и проблема с таймерами ушла! Но ведь костыль это...

Мамонов Михаил
26.12.2019, 12:56
Почему то все отвечающие отвечают на вопрос, который сами себе придумали... Ну либо я слишком многословно написал. И знаю я про целое беззнаковое и как в нем TIME хранится.
Вопрос - почему TIME() при включении контроллера начинает считать не с нуля, а с минус 23 секунд? Я в первом цикле ПЛК получаю TIME() и сохраняю в переменной DWORD - так вот там число 4294944319. Почему? Я как то был уверен что при подаче питания там 0 должен был быть.
Да, проверил что дает TIME() в первом цикле в ПЛК100 и в ПЛК110-32 старом - там все четко начинается 0

Что до таймеров - так те, которые объявлены как retain, сходят с ума при подаче питания, пока TIME() не дойдет до 0. Вот проблему с ними мне и надо решить.

Мамонов Михаил
26.12.2019, 14:00
Если не сложно - можете на живом ПЛК110 [M02] написать вот такую программку:
46421
и объяснить, почему таймер, ET которого при выключении питания показывал, скажем, секунд 10, при включении питания покажет 10 минут и выход Q таймера будет True?
Может я чего и не понимаю в работе ПЛК, но на ПЛК100 и ПЛК110-32 старой версии после включения ПЛК таймер продолжает считать с того времени, на котором его выключили, а вот в ПЛК110 [M02] сразу срабатывает? В общем то это и был изначальный вопрос.

И да, собственно TIME() меня как то не сильно волнует, просто предположил, что это причина такого поведения таймеров. Дальше про нее можно забыть, пусть считает как может.

Мамонов Михаил
26.12.2019, 17:39
По той же причине, по которой 12-00 Владика +10 часов не есть 22-00 по Москве.
Тогда спрошу по другому - почему в разных моделях ПЛК таймеры ведут себя по разному? Это нормально?
Вот опять всплывет база "TIME()" - в старых контроллерах она стартовала с нуля, а в новых чуть раньше нуля - не в этом ли причина?
Предстваьте этот бедный таймер в ПЛК110[М02] - когда ему выключали питание, у него значение TIME() было секунд 10-20, а когда включили обратно - стало 49 дней. И что ему с этим делать? А теперь в ПЛК100 - при отключении было 10сек, при включении стало 0 - ну и будет считать себе дальше до уставки.
И все зло от того, что GoDeSys самовольно обозвала этот таймер retain-ом, т.к. в ФБ, в который он входит, есть несколько retain-переменных. А таймеру то этот retain не нужен совсем...

В общем, пока сделал проще - на первом цикле ПЛК у всех проблемных таймеров дергаю IN в False и обратно в True - и таймеры честно начинают считать сначала.

Мамонов Михаил
26.12.2019, 18:05
Ну как бы из справки CoDeSys:
"Энергозависимыми или независимыми могут быть переменные и функциональные блоки. Чтобы сделать переменную энергонезависимой, при её объявлении добавьте слово RETAIN. Если хотя бы одна такая переменная объявлена внутри блока, то весь функциональный блок с остальными переменными становится энергонезависимым."
У меня внутри ФБ есть и RETAIN-переменные, и таймеры. Следовательно, в том числе и все таймеры этого блока стали энергонезависимыми. Не так разве?

Мамонов Михаил
26.12.2019, 18:29
Тогда если можете подсказать - как лучше решить такую задачу:
Есть несколько одинаковых установок, управляемых ПЛК. Алгоритм этих установок одинаковый, количество меняется от проекта к проекту. В алгоритме каждой установки есть некоторое количество задержек времени (TON), и есть энергонезависимые защелки, счетчики и т.п., которые запоминают состояния алгоритма на случай отключения питания. Как лучше реализовать такую систему?
Мне показалось естественным создать функциональный блок, который выполняет требуемый алгоритм, вставить требуемое количество таких блоков в проект ПЛК и связать блоки с входами-выходами ПЛК. Да, поскольку внутри блоков есть Retain, CoDeSys сделала Retain все блоки целиком, но запас по объему памяти Retain-ов еще приличный, я особо не беспокоился.
Такие проекты уже много лет работали на контроллерах ПЛК110 [M01]. При переходе на [M02] ФБ правильно функционировать отказались, и теперь я ищу почему. Первое на что наткнулся - на изменившееся поведение таймеров.

Мамонов Михаил
26.12.2019, 18:37
Не нужен ретайн-таймер - объявляете его вне фб-блока. В чем проблема-то ?
Не нужен. Но вся идея этого ФБ в выполнении алгоритма с кучей задержек. Если вынести из него таймеры - ФБ не останется. И ретейны тоже не вынести, их там много.


В чем самовольно если доки сами доки и цитируете? Ну скажем так, не самовольно, но принудительно.
А вообще не рассчитывал, что программа, годами работающая на одной версии ПЛК, может отказаться на работать на другой, но под той же версией среды программирования и с теми же библиотеками.

Мамонов Михаил
26.12.2019, 19:38
как один из вариантов, создать пользовательский тип данных, а.к.а структура. ....
А вот это очень интересная идея, не догадался. Буду смотреть в этом направлении.


У Вас прозвучало 2 вопроса.
1.Не хочу ретайн-таймер внутри ретайн-фб.
-Объявляете неретайн таймер вне ретайн-фб. -Передаете ссылку на этот таймер в ретайн-фб через IN_OUT. И всё.
2.Хочу продолжить отсчет после включения питания
Не, второй вариант точно не хочу. Если бывает такое надо - делаю через TIME(), TON все таки не для этого.
Передать ссылки на 12..15 таймеров в каждый ФБ, которых тоже около десятка, ну или те же структуры, не так изящно, как иметь готовую коробочку-ФБ со всем необходимым внутри, но если это более правильно с точки зрения дальнейшей переносимости программы, то видимо только так. Конечно хотелось сделать просто - кинул готовый блок, входы-выходы привязал и больше никаких телодвижений. Оно удобнее получается, когда программы приходится писать довольно редко, с ФБ меньше шансов забыть что-то где-то объявить и связать.


Это был баг воспринятый как норма. Исправили.))
Вот это точно :)

Мамонов Михаил
26.12.2019, 19:58
Ой, точно нездоровое.. Но что поделаешь, дребезжащие контакты и болтающиеся стрелки на электроконтактных манометрах. Работаем с тем что есть... Уже думаю, не переписать ли часть этих задержек через TIME() и выкинуть TON. Ну и как то надо оптимизировать количество, это да. Алгоритмы нарастали постепенно, много лет, переносились с контролеров одного производителя на другие, и если где то нужна была задержка, то проще было ее воткнуть и не заморачиваться. Как всегда времени на разработку нисколько, пару дней на доработку программы и на объект... Да и алгоритмов таки весьма много, вылизывать все банально нет времени