Вопрос по функции millis()

Тема в разделе "Arduino & Shields", создана пользователем Andrey_user, 7 авг 2017.

  1. Andrey_user

    Andrey_user Нерд

    Здравствуйте Все.
    Есть термометр на ардуино, который отправляет данные о критической температуре каждые 10 мин, с помощью GSM модуля. Интервал отправки, реализован мной с помощью функции millis(). Но поскольку, через 50 дней счётчик millis() обнуляется (а железка ведь должна работать постоянно), у меня есть сомнения, по поводу того, правильно ли я реализовал, "защиту", от этого "глюка". Меня терзают смутные сомнения, что всё можно реализовать гораздо проще.

    Вот "кусочек" кода:

    if((millis() == 4294967295))

    {
    delay(1); // millis() тут по идее должна сбросится на 0, через 50 дней работы.
    currentTime = millis(); // И переменная должна быть равна 0.
    loopWarm = currentTime;
    loopKalt = currentTime;

    }
    currentTime = millis();

    if(loopWarm >= 4294967294-600000) // Эта моя "защита", от возможного наложения, в 10 мин, если температура будет критической в этот момент, чтобы модуль не смог "забросать" SMS ками.
    {
    count_on = 0; // Не разрешит отправить СМС, если значение loopWarm больше 4294367294 (если оно будет больше, то при прибавлении 600000, будет переполнение unsigned long).
    }
    else
    {
    count_on = 1;
    }


    if(myTemp < 30)
    {
    loopWarm = currentTime; // Если температура ниже 30.
    }

    if((myTemp >= 30)&&(currentTime >= (loopWarm + 600000))) // Сработает, если температура выше, или равна 30, и если текущее время, больше loopWarm, на 10 мин (600000 милисекунд).
    {
    sms_on = 1; // Разрешает отправку SMS
    loopWarm = currentTime;
    }
    if((sms_on == 1)&&(count_on == 1))
    {
    sms(String ("TempCritical: "), String (myTemp), String (" gradus C"), String("+7700000000")); // ВПИШИТЕ НОМЕР, с которого Вы будете звонить на модуль
    sms_on = 0;
    count_on = 0;
    }

    Сильно, не пинайте, я в программировании новичок. Подскажите, какие вы видите ошибки в коде, и как его можно оптимизировать, или вообще изменить.
    Заранее благодарю, за помощь.
     
  2. b707

    b707 Гуру

    Если переписать условие срабатвания как
    (currentTime - loopWarm) >= 600000
    то оно будет работать и до перепеолнения millis. и после, и во время без всяких дополнительных проверок.
     
    Tomasina, AndroT, Andrey_user и ещё 1-му нравится это.
  3. Airbus

    Airbus Радиохулиган Модератор

    А чем Вам delay не delay?У Вас в эти 10 минут между посылками процессор производит сложные вычисления?Или простые решения не для Вас?
     
  4. b707

    b707 Гуру

    Вопрос-то не об этом. Суть вопроса в применении конкретной функции millis, а не в том, как вообще сделать задержку в цикле.
    И не надо советовать плохое. Человек пытается написать цикл без делай - и это очень хорошо. И пусть в этом случае можно все сделать и с использованием делай - зато когда ему понадобится от него избавиться - он же будет готов.
     
    Tomasina и AndroT нравится это.
  5. Andrey_user

    Andrey_user Нерд

    Спасибо, за совет, да действительно в unsigned long нет отрицательных чисел.
     
    b707 нравится это.
  6. Andrey_user

    Andrey_user Нерд

    Да, собственно Вы правы, я ещё, не работал с millis - вот решил попробовать.
     
  7. Airbus

    Airbus Радиохулиган Модератор

    В чем плохое?В данном конкретном случае именно delay чтбы процессор эти 10 минут не жил своей жизнью. millis да это круто где то только это и нужно но в данном случае именно так.И упадет проблема с переполнением.На Си небось delay используете?Или как?
     
  8. b707

    b707 Гуру

    Во-первых, нет никакой "проблемыы с переполнением". Во-вторых. в системах , реагирующих на внешние события - делаи использовать нельзя. От языка программирования это не зависит.
     
  9. Andrey_user

    Andrey_user Нерд

    У меня в коде, и так delay много, а я еще планирую в будущем, ещё датчиков к железке подцепить: хотя Вы конечно правы: у меня показания температуры посылаются через радио модуль NRF24L01, а СМС, это так, дополнительная мера безопасности - не будет же модуль постоянно смски посылать.
     
    Последнее редактирование: 7 авг 2017
  10. Andrey_user

    Andrey_user Нерд

    То есть, вот так должно без проблем с переполнением работать?

    currentTime = millis();

    if(myTemp < 30)
    {
    loopWarm = currentTime; // Если температура ниже 30.
    }

    if((myTemp >= 30)&&((currentTime - loopWarm) >= 600000)) //
    {
    sms(String ("TempCritical: "), String (myTemp), String (" gradus C"), String("+770000000")); //
    loopWarm = currentTime;
    }


    currentTime = millis();

    if(myTemp1 > 18)
    {
    loopKalt = currentTime; // Если температура выше 18.

    }
    if((myTemp1 <= 18)&&((currentTime - loopKalt) >= 600000)) //
    {
    sms(String ("TempDown: "), String (myTemp1), String (" gradus C"), String("+77000000")); //
    loopKalt = currentTime;
    }
     
    Последнее редактирование: 8 авг 2017
  11. b707

    b707 Гуру

    Есть, конечно, даже в Ардуино IDE - см функцию attachInterrupt и другие ... еще можно писать напрямую через регистры МК. ...или я не понял, о чем вы спрашиваете
    Никак не делаю. В событийном программировании (event-driven programming) нет нужды делать паузы. Если подпрограмме нечем заняться - она возвращает управление диспетчеру задач.

    Честно говоря, Airbus, я не вполне понимаю, с чем Вы пытаетесь спорить. То ли Вы недостаточно ясно выражаетесь, то ли просто далеки от этого...
     
  12. Airbus

    Airbus Радиохулиган Модератор

    Да не собираюсь я с Вами спорить.Я вообще далек от программирования.Если Вас это успокоит считайте так.
     
  13. b707

    b707 Гуру

    Ну тогда не сочтите за нотацию, а просто как совет - чем раньше Вы избавитесь от delay в своих скетчах - тем лучше. Delay вообще можно применять только в программах, которые выполняют одновременно СТРОГО ОДНО действие. А таких задач в сфере Ардуино очень мало. Даже мигание двумя светодиодами - уже два действия и написать его через delay весьма трудно, а через millis - запросто.
     
  14. Andrey_user

    Andrey_user Нерд

    А ещё, через массивы можно светодиодами моргать - верно?
     
  15. qwone

    qwone Гик

    Ну а можно мигать так. Тоже программа на millis() построена
    Код (C++):
    /**/
    uint32_t mill;// переменная под millis()
    //--------Cl_Led----------------------------
    //  класс светодиод
    class Cl_Led {
        Cl_Led *next; // <-- указатель на след элемент
        const byte pin;
        const bool inv;
        bool led;
        bool stat;// 1 мигает 0 нет
        uint32_t past, time;
      public:
        static Cl_Led *start; //<-- статический указатель  на начало списка
        static void setup() {
          for (Cl_Led *ii = start; ii != NULL; ii = ii->next)ii->init();
        }
        static void loop() {
          for (Cl_Led *ii = start; ii != NULL; ii = ii->next)ii->run();
        }
        Cl_Led(byte _pin, bool _inv)  // <-- конструктор
          : pin(_pin), inv(_inv) {
          this->next = start ;
          start = this;
        }
        void init() {
          pinMode(pin, OUTPUT);
          OFF();
        }
        void ON() {
          led = 1;
          digitalWrite(pin, led ^ inv);
          stat = 0;
        }
        void OFF() {
          led = 0;
          digitalWrite(pin, led ^ inv);
          stat = 0;
        }
        void blink(uint32_t _time = 500) {
          time = _time;
          past = mill;
          stat = 1;
          led = 1;
          digitalWrite(pin, led ^ inv);
        }
        void run() {
          if (!stat) return;
          if (mill - past >= time) {
            past = mill;
            led = !led;
            digitalWrite(pin, led ^ inv);
          }
        }
    };
    Cl_Led *Cl_Led::start = NULL;
    //------Cl_Btn------------------------------------------
    // класс кнопка
    class Cl_Btn {
        Cl_Btn *next; // <-- указатель на след элемент
        const byte pin;
        void (*Do1)();
        bool btn, btn_old;
        bool bounce = 0; // антидребезговый флаг
        uint32_t past = 0 ;
      public:
        static Cl_Btn *start; //<-- статический указатель  на начало списка
        static void setup() {
          for (Cl_Btn *ii = start; ii != NULL; ii = ii->next)ii->init();
        }
        static void loop() {
          for (Cl_Btn *ii = start; ii != NULL; ii = ii->next) {
            ii->run();
          }
        }
        Cl_Btn(byte _pin, void (*_Do1)())
          : pin(_pin), Do1(_Do1) {
          this->next = start ;
          start = this;
        }
        void init() {
          pinMode(pin, INPUT_PULLUP);
          btn_old = digitalRead(pin);
        }
        void run() {
          if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
            bounce = 1;                              // выставить флаг
            past = mill;                         // сделать временую засветку
          }
          else if ( bounce && mill - past >= 5 ) { // если прошло антидребезговое время
            bounce = 0;                                // то снять флаг
            btn_old = btn ;
            btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
            if (btn_old && ! btn) Do1();
          }
        }
    };
    Cl_Btn *Cl_Btn::start = NULL;
    //---------Компановка---------------------------
    Cl_Led Led1(/*пин*/13,/*инв*/0);
    void Do_Btn1() {
      Led1.ON();
    }
    void Do_Btn2() {
      Led1.OFF();
    }
    void Do_Btn3() {
      Led1.blink(200);
    }
    Cl_Btn Btn1(/*пин*/2,/*обраб наж*/Do_Btn1);
    Cl_Btn Btn2(/*пин*/3,/*обраб наж*/Do_Btn2);
    Cl_Btn Btn3(/*пин*/4,/*обраб наж*/Do_Btn3);
    //----------main()--------------------------
    void setup() {
      Cl_Led::setup();
      Cl_Btn::setup();
    }

    void loop() {
      mill = millis();
      Cl_Led::loop();
      Cl_Btn::loop();
    }
    /*Скетч использует 1614 байт (5%) памяти устройства. Всего доступно 32256 байт.
      Глобальные переменные используют 67 байт (3%) динамической памяти, оставляя 1981 байт для локальных переменных. Максимум: 2048 байт.
    */
     
  16. ostrov

    ostrov Гуру

    Вот так будет дергать верно даже после того как millis() начнет с начала:
    Код (C++):
    if(millis() - lastTime > interval)
    {
      lastTime = millis();
    ....
    }
    При условии, что переменные беззнаковые, само собой.
     
  17. AlexU

    AlexU Гуру

    Это не совсем так. Delay можно применять и при выполнении разных задач одновременно. Вот тут объяснил как: http://forum.amperka.ru/threads/Потоки-в-avr.9856/
    И ни чего страшного в 'delay' нет, просто надо с умом подходить к решению задач.
     
    Airbus и b707 нравится это.
  18. b707

    b707 Гуру

    Спасибо, почитал с интересом. но вообще, подобных библиотек и систем много, мне идея FreeRTOS понравилась больше(теоретически, на практике не пробовал).
    Что касается моего поста - я имел в виду традиционное программирование, без multi-task надстроек.