Список таймеров v2.0

Тема в разделе "Глядите, что я сделал", создана пользователем DetSimen, 5 фев 2019.

  1. DetSimen

    DetSimen Guest

    Много таймеров из одного
    Основная задача, стоящая перед горе-программистом AVR это не строгий математический анализ каких-нить бестолковых данных, не быстрое преобразование Фурье и даже не унылое мигание светлодиодиком. Основная задача, занимающая 80% программы - измерение временных интервалов. Чаще всего требуется узнать, скока времени прошло перед/после какого-нить события, чтобы не пропустить и вовремя откликнуться на него. Кто-то (90% новичков) жизни своей не мыслят без функции delay(), кто-то постоянно теребонькает несчастную millis(), зачастую, делая это неправильно и со священным ужасом ожидая страшного переполнения. Сложность в том, что временных интервалов по ходу программы требуется много, часто и, как правило, разных. Например, время конверсии даччика DS18B20 при максимальном 12-битовом разрешении составляет 750 миллисекунд, и раньше, чем вычислится температура опрашивать снова его бессмысленно. Для других даччиков время опроса будет совершенно другое, и временной интервал для него, соотвецтвенно - тоже. На экран информацию чаще 1 раза в 50 миллисекунд выводить тоже неприлично, только лишняя трата ресурсов, нервов и самого экранчика, значит опять надо где-то хранить время, когда вывод осуществлялся последний раз, чтоб не обращаться к нему чаще положенного. Везде, куда не посмотришь - время, время и время...

    Кто-то, не мудрствуя лукаво, использует для своих целей delay() и не парится, даже не понимая, что процессор во время выполнения этой функции просто висит в холостом цикле, не делая ничего полезного, и не способен исполнять что-то иное (на самом деле способен, канеш, но для новичков это тайна). В некоторых задачах, будь то простейший Blink или управление светлодиодной лентой это не критично, но если delay() используется в программе управления газовой горелкой, тут впору эвакуировать из дома родных и близких (и кота) на время эксплуатации такой горелки.

    Более продвинутые открыли для себя функцию millis() и поглядывают/поплевывают на делейщиков с высоты своего воображаемого Олимпа как исполненные благодати Свидетели Переполнения. И пестрят их программы чуть более чем полностью конструкциями вида

    if (millis()-lastmillis > myinterval) dosomething();

    а то и

    if (lastmillis+myinterval>millis()) dosomething();

    но последние, обычно, к исходу 49-х суток взрываются вместе с переполнившимся millis-om() и угрозы больше не представляют.

    delay() похож на дубину, которой нерадивый пользователь со всего маху шарашит бедный процессор по голове, после чего ему становится очень трудно стоять без сознания и он валяется в отключке некоторое заданное количество времени. Естественно, ничего другого он делать в этом состоянии не способен.

    millis() в этом отношении гораздо гуманнее. Он похож на хозяина раба, который вручил ему наручные часы, и строго настрого наказал следить за временем, если не хочется получить дубиной по башке, как в прошлый раз. И вот человечек, выполняя свою нехитрую работу, всё время пялится на часы, чтоб узнать не прошло ли достаточно времени, чтоб включить/выключить что то важное. Иначе, не уследишь/забудешь и улетишь вабнимку с газовым котлом Марс заселять вместе с родными и близкими (и котом), а жалка. Такое можно, канеш, потерпеть, если временной интервал один, но как только их становится несколько, да еще и друг от друга зависящих, выполнение задания превращается в атнюдь не тривиальную задачу (мошт, лучше дубиной, а?).

    То что предлагаю я, можно назвать будильником. Человек заводит себе несколько будильников на разное время и спокойно занимается своими делами. По мере срабатывания каждого, можно ненадолго отвлечься, включить/выключить то что нужно/ненужно и спокойно продолжить заниматься своими делами дальше. Если действие было однократное, будильник можно отключить, а если совсем-совсем однократное - то и выбросить. Если действие периодическое, а так чаще всего и бывает, ничего делать не нужно, через ранее заданный интервал будильник сам по себе сработает снова.

    далее -> https://github.com/DetSimen/Arduino_TimerList
     
    Daniil, ИгорьК, AlexU и ещё 1-му нравится это.
  2. parovoZZ

    parovoZZ Гуру

    А на Сях это как пришить?
     
  3. DetSimen

    DetSimen Guest

    структурами сделать
     
  4. parovoZZ

    parovoZZ Гуру

    крутяк. Прям как T1 в attiny261 =)
     
  5. AlexU

    AlexU Гуру

    Красивости кода для.
    Есть критические участки кода, типа:
    Код (C++):
    void TTimerList::Init()
    {
        byte oldSREG = SREG;  // начало критической секции
        cli();
    ........................................
        SREG = oldSREG; // конец критической секции
    }
    Их можно оформить следующим образом.
    Создаём небольшой класс для критических секций:
    Код (C++):

    /*
    * CriticalSection.h
    */


    #ifndef CRITICALSECTION_H_
    #define CRITICALSECTION_H_

    #include <avr/io.h>
    #include <avr/interrupt.h>

    class CriticalSection
    {
    public:
      CriticalSection () { oldSREG = SREG; cli(); };
      ~CriticalSection () { SREG = oldSREG; };
    private:
      uint8_t oldSREG;
    };

    #endif /* CRITICALSECTION_H_ */
    И потом в начало каждой критической секции помещаем декларацию объекта этого класса, например:
    Код (C++):
    void TTimerList::Init()
    {
        CriticalSection crit;

        TCCR0A = TCCR0A & 0b11111100;
        OCR0A = TIMER0_ONE_MS;
        TIMSK0 |= 0x3;
        TIFR0 = TIFR0 | 0x2;
    }
    Прелесть в том, что компилятор сам добавит в начале секции код из конструктора, а в конце код из деструктора. Секции могут выделять участок кода, а не всю функцию целиком, например:
    Код (C++):
    void loop()
    {
    ........................
      Serial.print("test1");
      { // критическая секция
        CriticalSection crit;
        PORTD = 0xAC;
        data = PINC;
      }
      Serial.print("test2");
    .........................
    }
     
    DetSimen и ИгорьК нравится это.
  6. DetSimen

    DetSimen Guest

    У avr gcc есть ATOMIC_BLOCK, делает примерно то же самое. Я просто подумал, что в данном контексте это лишнее
     
  7. DetSimen

    DetSimen Guest

    Updated. Исправлены глупые ашыпки, добавлены новые. :)
     
  8. AlexU

    AlexU Гуру

    Да, делает то же самое, но это макрос. А использование макросов в C++ не приветствуется, хотя и не запрещается.
    Здесь не соглашусь. Для новичков, которые будут знакомиться с Вашим кодом, такие фишечки могут быть полезными.
     
    DetSimen нравится это.
  9. DetSimen

    DetSimen Guest

    Чот я очкую. :)
     
  10. DetSimen

    DetSimen Guest

    Сутки прошли, а дядяВитя меня в пухипрах не разнес. Страшна.
     
  11. parovoZZ

    parovoZZ Гуру

    А он сюда не заглядывает.