Не работают вложенные таймеры

Leopoll
Offline
Зарегистрирован: 16.06.2016

Пишу, понимая, что вряд ли кто сможет помочь, но все же. 
Мега, 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

 

b707
Offline
Зарегистрирован: 26.05.2017

обьясните, как таймер на 500мс может быть вложен в таймер на 300 мс?

Для меня это что-то,  не укладывающееся в рамки привычной логики - примерно как трехлитровая банка, вложенная в литровую

Leopoll
Offline
Зарегистрирован: 16.06.2016

Здесь однократно исполняющийся таймер, 300мс - просто задержка, через которую он сработает. Он начинает работать через 300мс, а законит - когда закончит исполняться его содержимое, в т.ч. и другие таймеры. Все работало. 
Если вы знаете более корректный и удобный способ задать временную последовательность действий без delay  и if, буду благодарен. 

Может есть лимит на количество висящих в памяти таймеров?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Leopoll пишет:
Если вы знаете более корректный и удобный способ задать временную последовательность действий без delay  и if...

Я знаю. 

Leopoll
Offline
Зарегистрирован: 16.06.2016

Ваш способ лучше использует ресурсы, чем используемая мной библиотека? Спасибо.
Получается, чтобы реализовать приведенную задачу с нажатием двух кнопок, надо написать четыре функции счетчиков, в каждой из которых вызывать следующий счетчик?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Если ты внятно сформулируешь задачу, то можно тебе даже помочь. 

Leopoll
Offline
Зарегистрирован: 16.06.2016

Спасибо. В данном примере эмулируется нажатие на две кнопки с помощью реле. Нажать первую кнопку, через 300мс отпустить, подождать 500мс, нажать вторую кнопку, через 1600мс отпустить.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

И для этого нужны таймеры ? Где тут пересечение ???

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Leopoll пишет:

Спасибо. В данном примере эмулируется нажатие на две кнопки с помощью реле. Нажать первую кнопку, через 300мс отпустить, подождать 500мс, нажать вторую кнопку, через 1600мс отпустить.

Тут таймеры не нужны: "blink without delay" + "конечный автомат".

Leopoll
Offline
Зарегистрирован: 16.06.2016

Нужны. Параллельно этому идут другие процессы  - считываются датчики, выводится инфа на дисплей, передаются данные, проверяются значения. 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Leopoll пишет:

Нужны. Параллельно этому идут другие процессы  - считываются датчики, выводится инфа на дисплей, передаются данные, проверяются значения. 

см. ответ №8.

Leopoll
Offline
Зарегистрирован: 16.06.2016

Сорри. Отвечал предыдущему коментатору.  "blink without delay" это понятно,  "конечный автомат" это что?

Leopoll
Offline
Зарегистрирован: 16.06.2016

 И потом, "blink without delay" это с использованием IF и только в loop. Мне нужно оформить в отдельную функцию. Поэтому были таймеры.

Azeront
Offline
Зарегистрирован: 20.03.2021

Очень странная реализация таймера, обычно 1 объект = 1 таймер, а здесь аж 16 штук создаются, в независимости от того, будут ли они все использованы или нет.

У вас в коде приведено создание таймера, когда вам из пула таймеров объекта 'timer' вам выдается новый свободный таймер (метод 'setTimeout'). Однако нет кода удаления таймера, когда вы возвращаете уже ненужный таймер обратно в пул таймеров объекта 'timer' (метод 'deleteTimer'). Более того, вы даже не считываете ID используемых таймеров (речь именно про "вложенную конструкцию", ID'шники 'timer_reconnectBlynk' и 'timer_induction' вы таки запоминаете).

Возможно, у вас просто закончиваются таймера?

nik182
Offline
Зарегистрирован: 04.05.2015

Зачем оформлять в отдельную функцию? И даже если оформлено, то что мешает внутри функции использовать blink without delay? Всё равно эту подпрограмму придётся вызывать в цикле с периодичностью лучше чем необходимая точность соблюдения интервалов. А blink without delay позволяет выполнять распределённые во времени действия без задержек выполнения остального кода.  

Leopoll
Offline
Зарегистрирован: 16.06.2016

Azeront пишет:
Возможно, у вас просто закончиваются таймера?

Вот, об этом я и думаю. Не нашел информации, сколько таймеров может использовать библиотека 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"

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Один таймер, классическая машина состояний

/*
    Name:       ForumTimersExample.ino
    Created:	26.09.2022 17:13:44
    Author:     DtS
*/

constexpr uint32_t TIME_PRESS1  = 300;
constexpr uint32_t TIME_WAIT    = 500;
constexpr uint32_t TIME_PRESS2  = 1600;

void TimerEnd(void);

extern   TTimerList TimerList;
THandle  hTimer = INVALID_HANDLE;  // один таймер на всё

enum class TAppState : uint8_t {  // состояния программы
    Unknown       = 0,
    PressFirst    = 1,
    ReleaseFirst  = 2,
    PressSecond   = 3,
};

TAppState operator ++(TAppState AEnum, int) {
    constexpr uint8_t MIN_VALUE = static_cast<uint8_t>(TAppState::Unknown);
    constexpr uint8_t MAX_VALUE = static_cast<uint8_t>(TAppState::PressSecond);
    
    uint8_t value = static_cast<uint8_t>(AEnum);
    
    if (++value > MAX_VALUE) value = MIN_VALUE;

    AEnum = static_cast<TAppState>(value);

    return AEnum;
}

TAppState AppState = TAppState::Unknown;

void SetAppState(const TAppState ANewState) {
    
    if (AppState == ANewState) return;

    switch (AppState)
    {
    case TAppState::Unknown:
        TimerList.Stop(hTimer);
        break;
    case TAppState::PressFirst:
        TimerList.Reset(hTimer);
        break;
    case TAppState::ReleaseFirst:
        TimerList.SetNewInterval(hTimer, TIME_WAIT);
        break;
    case TAppState::PressSecond:
        TimerList.SetNewInterval(hTimer, TIME_PRESS2);
        break;
    default:
        break;
    }
}

void TimerEnd(void) {
    SetAppState(AppState++);
}

void setup()
{
    hTimer = TimerList.Add(TIME_PRESS1, STOPPED);
    SetAppState(TAppState::PressFirst);
}

void loop()
{


}

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

В switch надо понапхать что ты там хотел нажимать

b707
Offline
Зарегистрирован: 26.05.2017

Leopoli, вы какой-то бредятиной занимаетесь

Все что вы хотите - отлично делается на миллис, можно в loop, можно в отдельной функции. 16 таймеров - вы с ума сошли?  У вас всего 4 события, идущие один за другим. Значит вам НУЖЕН ОДИН ТАЙМЕР

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

DetSimen пишет:

Один таймер, классическая машина состояний

Вот как вижу такой код - сразу мысли посещают - пора по новой учить C/C++ ...

Leopoll
Offline
Зарегистрирован: 16.06.2016

Azeront пишет:
здесь аж 16 штук создаются

Где тут 16? Для реализации четырех событий используются 3 таймера, который затем уничтожаются. Буду благодарен, если покажете как грамотно использовать только один таймер без многочисленных проверок. Очевидно с помощью case?

Leopoll
Offline
Зарегистрирован: 16.06.2016

DetSimen пишет:

Один таймер, классическая машина состояний

Спасибо, пошел думать. Еще раз спрошу, чем использование этого класса лучше таймеров? У вас тоже ограничение на 16 штук.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Для Уно/Нано у меня ограничение - 10 штук, дак тебе и 10 не надо, достаточно одного. Если ничего не придумаешь - забей, используй другую библиотеку.   

Leopoll
Offline
Зарегистрирован: 16.06.2016

DetSimen пишет:

Для Уно/Нано у меня ограничение - 10 штук, дак тебе и 10 не надо, достаточно одного.

У меня Мега. То есть этот класс можно использовать параллельно с библиотекой SimpleTimer?

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Ржу ...

b707
Offline
Зарегистрирован: 26.05.2017

Leopoll пишет:

 этот класс можно использовать параллельно с библиотекой SimpleTimer?

 

идиот?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Leopoll пишет:
У меня Мега. То есть этот класс можно использовать параллельно с библиотекой SimpleTimer?

Нет. 

P.S.  Почему-то мне кажется, что нам всем будет лучше, если мы сделаем вид, что я тебе ничего не предлагал. Используй SimpleTimer и не парься. 

Leopoll
Offline
Зарегистрирован: 16.06.2016

Ну вот тогда мне десяти таймеров может не хватить, там еще опросы датчиков и пр. Почему и уточнил. 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

ПлАчу ...

b707
Offline
Зарегистрирован: 26.05.2017

Leopoll пишет:

Ну вот тогда мне десяти таймеров может не хватить

если не понимаешь, что делаешь - то 255-ти не хватит.

Если "код написан давно", значит, очевидно, это не первый подход к ардуино. Не думал хоть чуть-чуть повысить свой образовательный уровень и разобраться в языке вместо того чтоб тупо копи-пастить чужие коды из инета?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

За недорого подгоню библиотеку на +100500 таймеров !!!

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

На миллис. Отдельной функцией. Неужели сложно?

void setButtons()
{
  static bool flag = true;
  if (!flag)
  {
    return;
  }
  
  static byte n = 0;
  static uint32_t timer = millis();
  static uint32_t interval = 300;

  digitalWrite(51, HIGH); // Кнопка

  if (millis() - timer >= interval)
  {
    timer = millis();
    switch (n)
    {
    case 0:
      interval = 500;
      digitalWrite(51, LOW); // Кнопка отжать
      break;
    case 1:
      interval = 16000;
      digitalWrite(49, HIGH); // Стрелка вправо
      break;
    case 2:
      digitalWrite(49, LOW); // Стрелка вправо отжать
      flag = false;
      break;
    }
    n++;
  }
}

void loop()
{
  setButtons();

  
}

 

b707
Offline
Зарегистрирован: 26.05.2017

а вообще грустно

Я вообще был в полной уверенности, что подобные либы - бессмысленная вещь. Тот кто совсем дерево - и с библиотекой ниче не поймет, а любой новичок с недельным опытом сам напишет подобное на миллис. Я тут на одном форуме даже пытался лечить мужика - автора подобной либы с таймерами  - на тему бесполезности и кривости его творения. А он мне - у библиотеки хорошая репутация на гитхабе и люди меня благодарят...

Теперь вижу - и вправда, далеко не каждый "интеллигент" осилит написать две строчки на миллис

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Эта задача вообще не для таймеров !!! 

Leopoll
Offline
Зарегистрирован: 16.06.2016

v258 пишет:

На миллис. Отдельной функцией. Неужели сложно?

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

b707
Offline
Зарегистрирован: 26.05.2017

Komandir пишет:

Эта задача вообще не для таймеров !!! 

ну почему, однократный таймер - это тоже таймер

Судя по всему, наш ТС пытается работать на Меге, как будто это стандартный ПК с полноценной ОС. Такому идея РТОС бы очень зашла.

За што я ее, РТОС, и не люблю - как-то очень все просто,  для дебилов, создавай отдельный таск под каждую задачу и ни о чем не думай...

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

b707 пишет:
Я вообще был в полной уверенности, что подобные либы - бессмысленная вещь. ... Я тут на одном форуме даже пытался лечить мужика - автора подобной либы с таймерами  - на тему бесполезности и кривости его творения.

Ну можно я хотя бы сам буду ее использовать, не буду никому предлагать.  Мне иногда пригождаецца. :)

nik182
Offline
Зарегистрирован: 04.05.2015

Меня очень напрягает название библиотека для нескольких подпрограмм. Эта парадигма уже несколько раз приводила к подобным заблуждениям у начинающих. Реально это тот же код, но только спрятанный от пользователя.   

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Azeront пишет:
Очень странная реализация таймера, обычно 1 объект = 1 таймер, а здесь аж 16 штук создаются, в независимости от того, будут ли они все использованы или нет.
Вот-вот.

Мне кажется, достаточно беглого взгляда на эту библиотеку, что принять решение никогда ее не использовать.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andriano пишет:

Azeront пишет:
Очень странная реализация таймера, обычно 1 объект = 1 таймер, а здесь аж 16 штук создаются, в независимости от того, будут ли они все использованы или нет.
Вот-вот.

Мне кажется, достаточно беглого взгляда на эту библиотеку, что принять решение никогда ее не использовать.

за 6 лет вот ни разу не понадобилась, всё ручками, всё ручками...

Azeront
Offline
Зарегистрирован: 20.03.2021

1. Приведенный вами заголовочный файл библиотеки таймера в самом первом сообщении не совпадает с аналогичным заголовочным файлом ни по ссылке на playground.arduino.cc, ни по ссылке на github автора.

Leopoll пишет:
Где тут 16?

2. Константа "MAX_TIMERS" определяет кол-во таймеров в пуле. Это как и максимальное кол-во одновременно работающих таймеров, так и кол-во структур "timer_t", под которые будет выделена память в любом случае. В вашем заголовочнике константа равна 16, в оригинальном - 10. В истории коммитов на github я не углядел, чтобы она вообще когда-либо менялась, поэтому не понятно, откуда у вас приведенная "разновидность" библиотеки.

Leopoll пишет:
Точно ли setTimeout не уничтожает за собой таймер?

3. Посмотрел исходник, таки да, уничтожает, но после завершения вызова коллбэка. Т.е. в тот момент, когда вы внутри коллбэка забираете под себя следующий таймер, предыдущий еще не освобожден.

Leopoll пишет:
Она же использует один аппаратный таймер, привязанный к millis?

4. Она прямо "millis()" и использует.

5. Гадать, в чем проблема можно сколько угодно, тем более целиком проект вы не привели, и источник проблемы может быть в другом месте, а "вложенные таймера" - это симптомы. Если память позволяет - создайте еще один объект класса "SimpleTimer", и цепляйте "проблемные" таймера к нему. Тогда можно будет понять, проблема в ограничении таймеров, или в чем-то еще.

Ну и тут народ уже накидал вам другие варианты решений.

Leopoll
Offline
Зарегистрирован: 16.06.2016

Azeront пишет:

Спасибо за подробный разбор. Я привык, что на форуме обычно посылают, что конечно вполне заслужено. Так что ваша информация вдвойне радует.

Эта библиотека входит в пакет библиотек Blynk, на котором и базируется весь проект. Используется первый вариант, на второй вариант разработчики Blynk ссылаются как на свой источник и там есть описание.

Теперь здесь объяснили, что подобные библиотеки кривые. Но для меня, как для пользователя, конечно удобнее, чтобы функция, которая вызывается по сути разово, была в отдельной подпрограмме и занимала несколько строк, а не постоянно теребилась из loop. Хотя МК удобнее по-другому. Но памяти в Меге еще более чем достаточно осталось. 
Правильно понял, если написать 

SimpleTimer timer;
SimpleTimer timer1;

то у меня будет 32 таймера?

Можно ли организовать последовательность setTimeout, чтобы использованный таймер сразу удалялся?

Пока прикидываю разные варианты, может соберусь и перепишу все без таймеров.

 

Upper
Offline
Зарегистрирован: 23.06.2020

Leopoll пишет:

то у меня будет 32 таймера?

Можно ли организовать последовательность setTimeout, чтобы использованный таймер сразу удалялся?

Пока прикидываю разные варианты, может соберусь и перепишу все без таймеров.

Проще изменить MAX_TIMERS на нужное вам количество. Желательно подсчитать, сколько таймеров вам нужно одновременно, и если это число больше 16, то может быть имеет смысл изменить алгоритм работы.
Какую ошибку вам выдает getNumTimers() ? По моему там может быть только предупреждение о преобразовании типов.

Можно подправить библиотеку, чтобы использованный таймер сразу удалялся, но на этом сэкономится только один таймер. По моему возможная выгода не стоит усилий.

Прежде чем переписывать без таймеров, попробуйте разобраться в коде библиотеки. Она очень маленькая, и познавательная.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Leopoll пишет:
может соберусь и перепишу все без таймеров

Аллилуйя

Leopoll
Offline
Зарегистрирован: 16.06.2016

Upper пишет:

Проще изменить MAX_TIMERS 

Помогло. getNumTimers() заработал, и таки да, показал 18 таймеров на пике (позор мне).  freememory показывает еще 5мб свободных. 

Upper пишет:

Можно подправить библиотеку, чтобы использованный таймер сразу удалялся, но на этом сэкономится только один таймер.

Ну если три вложенных таймера, как моем примене ( а может понадобиться и больше, если последовательность нажатий на кнопки будет длиннее), то не один таймер сэкономится. 

Upper
Offline
Зарегистрирован: 23.06.2020

При вложенностях тратится только один лишний таймер. Можно посмотреть по коду, можно написать тестовую программу с большим числом вложений и выводить getNumTimers();

Впрочем при вызове getNumTimers(); вы и одного лишнего не заметите, т.к. второй таймер занимается на короткое время между началом обработки срабатывания таймера и выходом из него.

 

Leopoll
Offline
Зарегистрирован: 16.06.2016

Upper пишет:

 Можно посмотреть по коду

 digitalWrite (51, HIGH); // Кнопка 
  Serial.print ( "T_ON ");Serial.println(timer.getNumTimers()); // Вывод
  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.print ( "T2_OFF ");Serial.println(timer.getNumTimers()); // Вывод на три больше
      });
    });
  });

Разница в три таймера. 
И теперь понял, почему не работает. Количество таймеров постоянно увеличивается, где-то не удаляю старые, создавая новые. 

Upper
Offline
Зарегистрирован: 23.06.2020

Сделайте пример с этим кодом в сетапе и выводом числа таймеров в loop (с задержкой в 100 мс). У вас будет занят только один таймер при опросе в loop.

(В предыдущем сообщении я имел в виду -  можно посмотреть по коду библиотеки)

Leopoll
Offline
Зарегистрирован: 16.06.2016

Upper пишет:

Сделайте пример

Сделал. Вы были правы.