вопрос про millis()

Тема в разделе "Флудилка", создана пользователем CYITEP_BAC9I, 4 июл 2017.

  1. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    Всем наше здравствуйте. Вопрос для самопроверки. Делаю мозги для мульти варки и необходимо несколько таймеров для отсчета и индикации времени. В разных режимах с момента закипания, с момента включения и т.д. Модуля реального времени у меня нет поэтому пользуюсь средствами millisардуино. Как сделать индикацию времени с момента наступления события я вроде представляю вычесть из текущей отметки millisсобственно millis сколько он там натикал с момента включения. Однако уж очень это энергоёмко. Есть ли более изящный способ? Чтобы на индикатор выводить время не с включения ардуино а именно с нужного момента?
    Код (C++):
    uint16_t T1; //переменная для отсчета времени с момента включения ардуино
    static uint16_t T2; // переменная для отсчета времени с момента события
    uint16_t T3; //разница времени
    #define KNOPKA 1 //для примера приведена кнопка

    void setup() {
      pinMode (KNOPKA, INPUT);

    }

    void loop() {
      T1 =millis(); // засекаем время с начала работы ардуино(можно и без этой переменной)
      //Здесь в коде что то неопределенно долго делается
      //как только происходит какое либо событие, нажатие кнопки старт или срабатывание
      //температурного датчка. начинается отсчет таймера
    if(digitalRead(KNOPKA) == HIGH || Temp >98)
    {
      T2 = millis(); //засекаем текущее время

      T3 = T1 - T2 ; // или проще  millis() - T2 ;
      //далее переменную T3 преобразуем в минуты и часы и выводим на дисплей
    }

     
    }
     
  2. NikitOS

    NikitOS Король шутов Администратор

    к переменной равной нулю прибавлять 1 каждую секунду:D:D
     
    CYITEP_BAC9I нравится это.
  3. mcureenab

    mcureenab Гуру

    У millis тип

    Код (C++):
    unsigned long millis()
    в uint16_t только одна минута влезет.

    Зачем вам

    Код (C++):
    T1 =millis(); // засекаем время с начала работы ардуино(можно и б
    ?

    сохраняйте время события. и отнимайте его от millis() чтобы получить прошедшее от события время.
     
    CYITEP_BAC9I нравится это.
  4. mcureenab

    mcureenab Гуру

    Условие

    Код (C++):
    if(digitalRead(KNOPKA) == HIGH || Temp >98)
     
    проверяет состояние, а не событие. Например, пока температура больше 98 время как бы события постоянно обновляется, не течет.

    Это:
    Код (C++):
      //Здесь в коде что то неопределенно долго делается
     
    в принципе так можно делать. Но обычно функция loop завершается сразу после проверки состояний и короткой реакции на них.

    Если что-то делается "неопределенно долго ", другие функции в это время недоступны.
     
    CYITEP_BAC9I нравится это.
  5. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    в смысле вы имели в виду такую конструкцию? Тут только минуты и часы, т.к секунды не нужны.

    Код (C++):
     static unsigned long Timer = millis();
          if (millis() - Timer > 59999)
          {
           Minuty++ ;
           Timer = millis();
           if(Minuty >59)
           {
            Minuty =0;
            Chasy++;
           }
          }
    Интересно конечно, но сурово.
    всем большое спасибо, все уяснил, тему можно зарыть.
     
    Последнее редактирование: 4 июл 2017
  6. mcureenab

    mcureenab Гуру

    Так нельзя делать:

    Timer = millis();

    время будет дрейфовать.
    Нам нужен тик 1 раз в минуту, поэтому задаём интервал строго 60 сек. :

    Timer += 60000;

    И расчёт секунд тоже не тривиальная задача. Она должна быть решена тут же, в расчёте минут.
     
    CYITEP_BAC9I нравится это.
  7. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    как непросто однако оказалось. Нееее я лучше по простому
    Код (C++):
    millis() - T2;
    а потом переведу в минуты и секунды.
    Но для общего развития пытаюсь все таки понять как можно решить этот вопрос.
    так допустимо? или я неправильно понял?

    Код (C++):
    static bool  Flag =1; //или вынести в инициализацию
    static unsigned long Timer ;
    if (Flag ==1)
    {
      Timer = millis(); // для того чтобы получить время для сравнения
      Flag =0;
    }


          if (millis() == Timer += 60000)
          {
           Minuty++ ;
           Flag =1;    
           if(Minuty >59)
           {
            Minuty =0;
            Chasy++;
           }
          }
    кстати нашел на другом Ардуиновском форуме вообще интересное решение
    каждые 0.5 секунд меняем состояние ноги в данном случае 13, потом считываем и при каждом
    HIGH на ноге прибавляем 1 сек к таймеру.

    Код (C++):
    if (millis() - previousMillis >500)

    {

       previousMillis = millis();  //запускаем таймер

       digitalWrite(13, !digitalRead(13));//меняем значение порта каждые 0.5секунд  

       if(digitalRead(13)==HIGH)//если 13 нога лог1 то...

       {
         sek++;//переменная секунда + 1
    }
     
     
    но как я писал обойдусь по простому вычту время когда была нажата кнопка или датчик температуры превысил порог, из millis() а потом просто и непринужденно переведу в минуты и часы.
    большое спасибо, что находите время на консультацию даже по таким мелочам
     
  8. DetSimen

    DetSimen Guest

    много таймеров https://github.com/DetSimen/Arduino-
    секундный таймер делается вапще на раздва. + еще 7 асинхронных с разной выдержкой.
     
    CYITEP_BAC9I и arkadyf нравится это.
  9. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    Спасибо. Сложновато для новичкофф, но и это скурим)
     
  10. DetSimen

    DetSimen Guest

    Спрашивай, если непонятно, постараюсь ответить быстро.
     
  11. DetSimen

    DetSimen Guest

    Вот например простейшие часы.

    Код (C++):

    template <typename T> Print &operator << (Print &s, T n) { s.print(n); return s; }


    extern TTimerList TimerList;
    THandle  hSecondTick;

    byte hours = minutes = seconds = 0;  // часы, минуты, секунды

    void setup()
    {
      hSecondTick = TimerList.AddSeconds(tmrSecondTick, 1); // раз в секунду будет вызываться tmrSecondTick
    }

    void tmrSecondTick(void)
    {
    seconds++;
    if (seconds<60) return;
    seconds=0; minutes++;
    if (minutes>59)
    {
       minutes=0;
       hours++;
      }
      if (hours>23) hours=0;
      Serial<<hour<<':'<<minutes<<'\n';
    }

    void loop()
    {
    }

     
     
    CYITEP_BAC9I и arkadyf нравится это.
  12. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    Спасибо вам большое. и за скетч и за ссылку. Я только начал подбираться к битовым операциям в С++, поэтому пока неуразумею что к чему, вопросов будет черезчур много). так что сам потихоньку буду вникать а то некрасиво получится и скетч дали еще и разжуют ) так не научусь сам ничему:) .а пока что такие выражания типа
    Код (C++):
    cli();
        TCCR5A = 0; TCCR5B = 0;
        TCNT5 = 0;
    вводят в панику).
    Еще раз большое спасибо. постараюсь разобрать сам скетч по строкам чтоб осознать что к чему и главное зачем.
     
  13. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    бодрый вечер всем.
    написал свой первый собственный таймер
    Код (C++):
     static unsigned long Counter_05_sec = millis(); //static
    if (millis() - Counter_05_sec > 499)
          {
             Counter_05_sec = millis();    
           switch_30 = !switch_30  ;      
             
         // Serial.println("switch_30");
      //Serial.println(switch_30);

    if (switch_30 ==1)
    {
      Sekundy_t++;

    if (Sekundy_t>59)                                  
      {
        Minuty++ ;                                  
        Sekundy_t=0;                                    
      }
    if (Minuty>59)                                      
      {
        Chasy++;                                      
        Minuty=0;                                      
      }

      }
      }
    проще некуда. вставлять можно в любое место кода. не надо захватывать и вычитать millis(). можно наплодить их кучу в разных местах. НО, он собака отстает на секунду каждую минуту. это ошипка кода? или особенность Дуни? ставлю 498 и все идет секунда в секунду по секундомеру с телефона.
    а вообще меня millis() ,бесить начал уже. в конструкции switch case . я думал что захват millis(), произойдет в момент перехода в нужный case. Фига с два, у меня 5 таймеров в 5 разделах case. и они все захватывают millis() одновременно в момент как я вхожу в этот цикл. Написано немного сумбурно но код сильно большой чтоб его выкладывать. к тому же сам стараюсь понять в чем цимес. Гуру С++ напишете методичку как работает millis(), с разными примерами. как работает static long при захвате. Все будут премного благодарны за этот труд!
    Кстати первый раз за карьеру ардуньщика столкнулся с тем что мне уже не хватает памяти Дуни про мини)
     
  14. mcureenab

    mcureenab Гуру

    У вас дрейф точки отсчёта происходит.
    millis () - Counter_05_sec это не 500 мс.
    Прибавляйте к Counter_05_sec строго 500 а не неизвестную величину millis ()
     
    arkadyf и CYITEP_BAC9I нравится это.
  15. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    Cпасибо понял!!!
    даже если и неправильно понял, выражение
    Код (C++):
    if (millis() == Counter_05_sec + 500)
    решило все вопросы. прогнал уже 20 минут отклонения нет ни на секунду!
     
    Последнее редактирование: 10 июл 2017
  16. mcureenab

    mcureenab Гуру

    Отвратительно!
     
  17. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    прошу "звонок другу"). подсказки или ссылки на ресурс. Конечно самому хочется додуматся, оно и закрепится надолго. но не придумывается ничего лучше.
    Код (C++):
    static unsigned long Counter_05_sec = millis(); //static
        if (millis() - Counter_05_sec == 1000) //if (millis() - Counter_05_sec > 498)
          {
             Counter_05_sec = millis();        
      Sekundy_t++;
    Serial.println(Sekundy_t);
    if (Sekundy_t>59)                                  
      {
        Minuty++ ;                                  
        Sekundy_t=0;
        Serial.println(Minuty);                                  
      }
    if (Minuty>59)                                      
      {
        Chasy++;                                    
        Minuty=0;                                      
      }


      }
    работает нормально, точность устраивает. но хочется конечно знать и правильный способ.
    при переходе с полусекунд на секунды возможная погрешнасть по моему вообще минимальна
     
  18. mcureenab

    mcureenab Гуру

    Теперь вашей функции надо передавать управление не реже 1 раза за 1мс. Иначе она пропустит отсчёт. Это новая ошибка. В прежней редакции можно было дёргать её 1 раз в 0.5 сек. Но и это условие можно смягчить.

    И даже если время выделять, она может дрейфовать на 1мс/с. Это старая ошибка, которую вы не стали исправлять. Только смягчили за счёт условия "не реже 1 раза за 1мс".

    Три статических переменных:
    Sekundy_t
    Minuty
    Chasy
    Как то жирно по моему. Не удивительно, что памяти не хватает. Их можно из millis() запросто извлечь. Вряд ли они очень часто нужны.
     
    Последнее редактирование: 11 июл 2017
    CYITEP_BAC9I нравится это.
  19. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    вечер добрый. спасибо)ю
    как перевести millis() в минуты и часы написал , но это в принципе не ново.
    Код (C++):

    byte Chasy, Minuty, Sekundy_t,  ms;
    unsigned long  Current;
    unsigned long n;
    void setup() {
      Serial.begin(9600);// put your setup code here, to run once:

    }

    void loop() {
    static unsigned long start = millis(); //получаем текущее время
      Current = millis()- start; // полуяаем разницу между текущим временем и началом старта millis()

    Chasy=int(Current/3600000); //вычисляем часы и минуты
      n=Current%3600000;
      Minuty=byte(n/60000);
      n=n%60000;
      Sekundy_t=byte(n/1000);
      ms=n%1000;

    }
       
    но не нравится мне такие таймеры. я не понял почему но
    Код (C++):
    static unsigned long start = millis();
      Current = millis()- start;
    в этом моменте у меня часто происходят косяки. причину пока не могу уловить.
    или не заводится функция, или наоборот хрен обнулишь начальную переменную start. (но это мои тараканы и воюю с ними пока безуспешно)
    а таймер типа

    Код (C++):
    static unsigned long Counter_05_sec = millis();
        if (millis() - Counter_05_sec >= 1000)
    Заводится всегда и в любом месте программы.
    И главное начинает отсчет с нужного момента, без всяких усилий.
    Сейчас думаю как же идеологически правильно это должно быть:)
     
  20. mcureenab

    mcureenab Гуру

    CYITEP_BAC9I нравится это.