Не работают вложенные таймеры
- Войдите на сайт для отправки комментариев
Вс, 25/09/2022 - 23:53
Пишу, понимая, что вряд ли кто сможет помочь, но все же.
Мега, 1.8.13. В скетче есть несколько таймеров. Перестали работать вложенные.
digitalWrite (51, HIGH); // Кнопка Serial.println ( "T_ON"); timer.setTimeout (300, []() { // digitalWrite ( 51, LOW); // Кнопка отжать Serial.println ( "T_OFF"); timer.setTimeout(500, []() { // digitalWrite ( 49, HIGH); // Стрелка вправо Serial.println ( "T2_ON"); timer.setTimeout(16000, []() { // digitalWrite ( 49, LOW); // Стрелка вправо отжать Serial.println ( "T2_OFF"); }); }); });
То есть в этом примере Т_ОN и T_OFF сработают а дальше ничего не произойдет.
Программу, насколько помню, не менял уже давно. Все, что смог понять - если отключить несколько других таймеров, то начинает работать.
/////////////////////////////////////////Настраиваем таймеры setSyncInterval ( 10 * 60 ); timer_reconnectBlynk = timer.setInterval(30155L, reconnectBlynk); // проверяем каждые 30 секунд, если все еще подключен к серверу timer_induction = timer.setInterval (3600387L, timerInduction ); timer.setInterval (501, read_sensor); // Опрос сенсоров timer.setInterval (203, blynkprint); // Передача данных
Из этого списка надо откючить первые три, то работает. Причем если отключить любые два из них, то работать не будет. Так что дело не в содержании самих таймеров, как видится.
Сама библиотека.
/* * SimpleTimer.h * * SimpleTimer - A timer library for Arduino. * Author: mromani@ottotecnica.com * Copyright (c) 2010 OTTOTECNICA Italy * * Modifications by Bill Knight <billk@rosw.com> 18March2017 * * This library is free software; you can redistribute it * and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software * Foundation; either version 2.1 of the License, or (at * your option) any later version. * * This library is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser * General Public License along with this library; if not, * write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef BLYNKTIMER_H #define BLYNKTIMER_H #include <Blynk/BlynkDebug.h> // Replace SimpleTimer #define SIMPLETIMER_H #define SimpleTimer BlynkTimer typedef void (*timer_callback)(void); typedef void (*timer_callback_p)(void *); class SimpleTimer { public: // maximum number of timers const static int MAX_TIMERS = 16; // setTimer() constants const static int RUN_FOREVER = 0; const static int RUN_ONCE = 1; // constructor SimpleTimer(); void init(); // this function must be called inside loop() void run(); // Timer will call function 'f' every 'd' milliseconds forever // returns the timer number (numTimer) on success or // -1 on failure (f == NULL) or no free timers int setInterval(unsigned long d, timer_callback f); // Timer will call function 'f' with parameter 'p' every 'd' milliseconds forever // returns the timer number (numTimer) on success or // -1 on failure (f == NULL) or no free timers int setInterval(unsigned long d, timer_callback_p f, void* p); // Timer will call function 'f' after 'd' milliseconds one time // returns the timer number (numTimer) on success or // -1 on failure (f == NULL) or no free timers int setTimeout(unsigned long d, timer_callback f); // Timer will call function 'f' with parameter 'p' after 'd' milliseconds one time // returns the timer number (numTimer) on success or // -1 on failure (f == NULL) or no free timers int setTimeout(unsigned long d, timer_callback_p f, void* p); // Timer will call function 'f' every 'd' milliseconds 'n' times // returns the timer number (numTimer) on success or // -1 on failure (f == NULL) or no free timers int setTimer(unsigned long d, timer_callback f, unsigned n); // Timer will call function 'f' with parameter 'p' every 'd' milliseconds 'n' times // returns the timer number (numTimer) on success or // -1 on failure (f == NULL) or no free timers int setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n); // updates interval of the specified timer bool changeInterval(unsigned numTimer, unsigned long d); // destroy the specified timer void deleteTimer(unsigned numTimer); // restart the specified timer void restartTimer(unsigned numTimer); // returns true if the specified timer is enabled bool isEnabled(unsigned numTimer); // enables the specified timer void enable(unsigned numTimer); // disables the specified timer void disable(unsigned numTimer); // enables all timers void enableAll(); // disables all timers void disableAll(); // enables the specified timer if it's currently disabled, // and vice-versa void toggle(unsigned numTimer); // returns the number of used timers unsigned getNumTimers(); // returns the number of available timers unsigned getNumAvailableTimers() { return MAX_TIMERS - numTimers; }; private: // deferred call constants const static int DEFCALL_DONTRUN = 0; // don't call the callback function const static int DEFCALL_RUNONLY = 1; // call the callback function but don't delete the timer const static int DEFCALL_RUNANDDEL = 2; // call the callback function and delete the timer // low level function to initialize and enable a new timer // returns the timer number (numTimer) on success or // -1 on failure (f == NULL) or no free timers int setupTimer(unsigned long d, void* f, void* p, bool h, unsigned n); // find the first available slot int findFirstFreeSlot(); typedef struct { unsigned long prev_millis; // value returned by the millis() function in the previous run() call void* callback; // pointer to the callback function void* param; // function parameter bool hasParam; // true if callback takes a parameter unsigned long delay; // delay value unsigned maxNumRuns; // number of runs to be executed unsigned numRuns; // number of executed runs bool enabled; // true if enabled unsigned toBeCalled; // deferred function call (sort of) - N.B.: only used in run() } timer_t; timer_t timer[MAX_TIMERS]; // actual number of timers in use (-1 means uninitialized) int numTimers; }; #endif
обьясните, как таймер на 500мс может быть вложен в таймер на 300 мс?
Для меня это что-то, не укладывающееся в рамки привычной логики - примерно как трехлитровая банка, вложенная в литровую
Здесь однократно исполняющийся таймер, 300мс - просто задержка, через которую он сработает. Он начинает работать через 300мс, а законит - когда закончит исполняться его содержимое, в т.ч. и другие таймеры. Все работало.
Если вы знаете более корректный и удобный способ задать временную последовательность действий без delay и if, буду благодарен.
Может есть лимит на количество висящих в памяти таймеров?
Я знаю.
Ваш способ лучше использует ресурсы, чем используемая мной библиотека? Спасибо.
Получается, чтобы реализовать приведенную задачу с нажатием двух кнопок, надо написать четыре функции счетчиков, в каждой из которых вызывать следующий счетчик?
Если ты внятно сформулируешь задачу, то можно тебе даже помочь.
Спасибо. В данном примере эмулируется нажатие на две кнопки с помощью реле. Нажать первую кнопку, через 300мс отпустить, подождать 500мс, нажать вторую кнопку, через 1600мс отпустить.
И для этого нужны таймеры ? Где тут пересечение ???
Спасибо. В данном примере эмулируется нажатие на две кнопки с помощью реле. Нажать первую кнопку, через 300мс отпустить, подождать 500мс, нажать вторую кнопку, через 1600мс отпустить.
Нужны. Параллельно этому идут другие процессы - считываются датчики, выводится инфа на дисплей, передаются данные, проверяются значения.
Нужны. Параллельно этому идут другие процессы - считываются датчики, выводится инфа на дисплей, передаются данные, проверяются значения.
Сорри. Отвечал предыдущему коментатору. "blink without delay" это понятно, "конечный автомат" это что?
И потом, "blink without delay" это с использованием IF и только в loop. Мне нужно оформить в отдельную функцию. Поэтому были таймеры.
Очень странная реализация таймера, обычно 1 объект = 1 таймер, а здесь аж 16 штук создаются, в независимости от того, будут ли они все использованы или нет.
У вас в коде приведено создание таймера, когда вам из пула таймеров объекта 'timer' вам выдается новый свободный таймер (метод 'setTimeout'). Однако нет кода удаления таймера, когда вы возвращаете уже ненужный таймер обратно в пул таймеров объекта 'timer' (метод 'deleteTimer'). Более того, вы даже не считываете ID используемых таймеров (речь именно про "вложенную конструкцию", ID'шники 'timer_reconnectBlynk' и 'timer_induction' вы таки запоминаете).
Возможно, у вас просто закончиваются таймера?
Зачем оформлять в отдельную функцию? И даже если оформлено, то что мешает внутри функции использовать blink without delay? Всё равно эту подпрограмму придётся вызывать в цикле с периодичностью лучше чем необходимая точность соблюдения интервалов. А blink without delay позволяет выполнять распределённые во времени действия без задержек выполнения остального кода.
Вот, об этом я и думаю. Не нашел информации, сколько таймеров может использовать библиотека https://playground.arduino.cc/Code/SimpleTimer/. Она же использует один аппаратный таймер, привязанный к millis? Можно ли параллельно использовать другие библиотеки на других аппаратных таймерах, если такие есть, на Меге ведь четыре таймера? Не понял, как работает getNumTimers(), выдает ошибку.
Точно ли setTimeout не уничтожает за собой таймер? "After f has been called the specified number of times, the interval is deleted, therefore the value timerId is no longer valid"
Один таймер, классическая машина состояний
В switch надо понапхать что ты там хотел нажимать
Leopoli, вы какой-то бредятиной занимаетесь
Все что вы хотите - отлично делается на миллис, можно в loop, можно в отдельной функции. 16 таймеров - вы с ума сошли? У вас всего 4 события, идущие один за другим. Значит вам НУЖЕН ОДИН ТАЙМЕР
Один таймер, классическая машина состояний
Вот как вижу такой код - сразу мысли посещают - пора по новой учить C/C++ ...
Где тут 16? Для реализации четырех событий используются 3 таймера, который затем уничтожаются. Буду благодарен, если покажете как грамотно использовать только один таймер без многочисленных проверок. Очевидно с помощью case?
Один таймер, классическая машина состояний
Спасибо, пошел думать. Еще раз спрошу, чем использование этого класса лучше таймеров? У вас тоже ограничение на 16 штук.
Для Уно/Нано у меня ограничение - 10 штук, дак тебе и 10 не надо, достаточно одного. Если ничего не придумаешь - забей, используй другую библиотеку.
Для Уно/Нано у меня ограничение - 10 штук, дак тебе и 10 не надо, достаточно одного.
У меня Мега. То есть этот класс можно использовать параллельно с библиотекой SimpleTimer?
Ржу ...
этот класс можно использовать параллельно с библиотекой SimpleTimer?
идиот?
Нет.
P.S. Почему-то мне кажется, что нам всем будет лучше, если мы сделаем вид, что я тебе ничего не предлагал. Используй SimpleTimer и не парься.
Ну вот тогда мне десяти таймеров может не хватить, там еще опросы датчиков и пр. Почему и уточнил.
ПлАчу ...
Ну вот тогда мне десяти таймеров может не хватить
если не понимаешь, что делаешь - то 255-ти не хватит.
Если "код написан давно", значит, очевидно, это не первый подход к ардуино. Не думал хоть чуть-чуть повысить свой образовательный уровень и разобраться в языке вместо того чтоб тупо копи-пастить чужие коды из инета?
За недорого подгоню библиотеку на +100500 таймеров !!!
На миллис. Отдельной функцией. Неужели сложно?
а вообще грустно
Я вообще был в полной уверенности, что подобные либы - бессмысленная вещь. Тот кто совсем дерево - и с библиотекой ниче не поймет, а любой новичок с недельным опытом сам напишет подобное на миллис. Я тут на одном форуме даже пытался лечить мужика - автора подобной либы с таймерами - на тему бесполезности и кривости его творения. А он мне - у библиотеки хорошая репутация на гитхабе и люди меня благодарят...
Теперь вижу - и вправда, далеко не каждый "интеллигент" осилит написать две строчки на миллис
Эта задача вообще не для таймеров !!!
На миллис. Отдельной функцией. Неужели сложно?
Спасибо, ничего сложного. Пребывал в уверенности что десяток подобных функций, крутящихся в loop, больше нагрузят процессор, чем использование библиотеки. С учетом того, что именно эту использовать надо будет только раз в час. Ошибался.
Эта задача вообще не для таймеров !!!
ну почему, однократный таймер - это тоже таймер
Судя по всему, наш ТС пытается работать на Меге, как будто это стандартный ПК с полноценной ОС. Такому идея РТОС бы очень зашла.
За што я ее, РТОС, и не люблю - как-то очень все просто, для дебилов, создавай отдельный таск под каждую задачу и ни о чем не думай...
Ну можно я хотя бы сам буду ее использовать, не буду никому предлагать. Мне иногда пригождаецца. :)
Меня очень напрягает название библиотека для нескольких подпрограмм. Эта парадигма уже несколько раз приводила к подобным заблуждениям у начинающих. Реально это тот же код, но только спрятанный от пользователя.
Мне кажется, достаточно беглого взгляда на эту библиотеку, что принять решение никогда ее не использовать.
Мне кажется, достаточно беглого взгляда на эту библиотеку, что принять решение никогда ее не использовать.
за 6 лет вот ни разу не понадобилась, всё ручками, всё ручками...
1. Приведенный вами заголовочный файл библиотеки таймера в самом первом сообщении не совпадает с аналогичным заголовочным файлом ни по ссылке на playground.arduino.cc, ни по ссылке на github автора.
2. Константа "MAX_TIMERS" определяет кол-во таймеров в пуле. Это как и максимальное кол-во одновременно работающих таймеров, так и кол-во структур "timer_t", под которые будет выделена память в любом случае. В вашем заголовочнике константа равна 16, в оригинальном - 10. В истории коммитов на github я не углядел, чтобы она вообще когда-либо менялась, поэтому не понятно, откуда у вас приведенная "разновидность" библиотеки.
3. Посмотрел исходник, таки да, уничтожает, но после завершения вызова коллбэка. Т.е. в тот момент, когда вы внутри коллбэка забираете под себя следующий таймер, предыдущий еще не освобожден.
4. Она прямо "millis()" и использует.
5. Гадать, в чем проблема можно сколько угодно, тем более целиком проект вы не привели, и источник проблемы может быть в другом месте, а "вложенные таймера" - это симптомы. Если память позволяет - создайте еще один объект класса "SimpleTimer", и цепляйте "проблемные" таймера к нему. Тогда можно будет понять, проблема в ограничении таймеров, или в чем-то еще.
Ну и тут народ уже накидал вам другие варианты решений.
Спасибо за подробный разбор. Я привык, что на форуме обычно посылают, что конечно вполне заслужено. Так что ваша информация вдвойне радует.
Эта библиотека входит в пакет библиотек Blynk, на котором и базируется весь проект. Используется первый вариант, на второй вариант разработчики Blynk ссылаются как на свой источник и там есть описание.
Теперь здесь объяснили, что подобные библиотеки кривые. Но для меня, как для пользователя, конечно удобнее, чтобы функция, которая вызывается по сути разово, была в отдельной подпрограмме и занимала несколько строк, а не постоянно теребилась из loop. Хотя МК удобнее по-другому. Но памяти в Меге еще более чем достаточно осталось.
Правильно понял, если написать
то у меня будет 32 таймера?
Можно ли организовать последовательность setTimeout, чтобы использованный таймер сразу удалялся?
Пока прикидываю разные варианты, может соберусь и перепишу все без таймеров.
то у меня будет 32 таймера?
Можно ли организовать последовательность setTimeout, чтобы использованный таймер сразу удалялся?
Пока прикидываю разные варианты, может соберусь и перепишу все без таймеров.
Проще изменить MAX_TIMERS на нужное вам количество. Желательно подсчитать, сколько таймеров вам нужно одновременно, и если это число больше 16, то может быть имеет смысл изменить алгоритм работы.
Какую ошибку вам выдает getNumTimers() ? По моему там может быть только предупреждение о преобразовании типов.
Можно подправить библиотеку, чтобы использованный таймер сразу удалялся, но на этом сэкономится только один таймер. По моему возможная выгода не стоит усилий.
Прежде чем переписывать без таймеров, попробуйте разобраться в коде библиотеки. Она очень маленькая, и познавательная.
Аллилуйя
Проще изменить MAX_TIMERS
Помогло. getNumTimers() заработал, и таки да, показал 18 таймеров на пике (позор мне). freememory показывает еще 5мб свободных.
Можно подправить библиотеку, чтобы использованный таймер сразу удалялся, но на этом сэкономится только один таймер.
Ну если три вложенных таймера, как моем примене ( а может понадобиться и больше, если последовательность нажатий на кнопки будет длиннее), то не один таймер сэкономится.
При вложенностях тратится только один лишний таймер. Можно посмотреть по коду, можно написать тестовую программу с большим числом вложений и выводить getNumTimers();
Впрочем при вызове getNumTimers(); вы и одного лишнего не заметите, т.к. второй таймер занимается на короткое время между началом обработки срабатывания таймера и выходом из него.
Можно посмотреть по коду
Разница в три таймера.
И теперь понял, почему не работает. Количество таймеров постоянно увеличивается, где-то не удаляю старые, создавая новые.
Сделайте пример с этим кодом в сетапе и выводом числа таймеров в loop (с задержкой в 100 мс). У вас будет занят только один таймер при опросе в loop.
(В предыдущем сообщении я имел в виду - можно посмотреть по коду библиотеки)
Сделайте пример
Сделал. Вы были правы.