Срабатывание таймера только после выполнения условий

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

  1. FlameWind

    FlameWind Нерд

    Вобщем никак не могу разобраться с таймерами millis().
    Как сделать чтобы отсчет таймера начинался только после соблюдения определенных условий?
    Например: датчик выдает значение 10, и только после 5 секунд выполнения условия <= 10 к примеру ставится флаг On, ну и дальше по циклу через if (On) что-то там выполняется.
    Можно было бы через delay сделать, но мне нужно чтобы скетч продолжал обрабатываться.
     
  2. Unixon

    Unixon Оракул Модератор

    Код (C++):

    #define SENSOR_THRESHOLD 10
    #define DELAY_SENSOR_US 5000

    #define STATE_IDLE 0
    #define STATE_WAITING 1
    #define STATE_WORKING 2

    long t0 = 0;
    int state = STATE_IDLE;

    void loop()
    {
      int x = analogRead(PIN_SENSOR);
      long t = millis();
      //
      switch (state)
      {
        case STATE_IDLE:
          {
            if (x < SENSOR_THRESHOLD)
            {
              t0 = t;
              state = STATE_WAITING;
            }
            break;
          }
        case STATE_WAITING:
          {
            if (x < SENSOR_THRESHOLD)
            {
              if ((t - t0) > DELAY_SENSOR_US)
              {
                state = STATE_WORKING
              }
            }
            else
            {
              state = STATE_IDLE;
            }
            break;
          }
        case STATE_WORKING:
          {
            // do something
            state = STATE_IDLE;
            break;
          }
      }
    }
     
     
    FlameWind и arkadyf нравится это.
  3. DetSimen

    DetSimen Guest

    Код (C++):
    #include "Arduino.h"
    #include "uTimerList.h"

    #define MEASUREVALUE 10;

    extern TTimerList TimerList;

    THandle VerifyTimer;

    volatile bool StartNow = false;

    int ReadSensor(void)
    {
        //...
    }

    void VerifySensor(void)
    {
        StartNow = (ReadSensor()>MEASUREVALUE);
        TimerList.TimerStop(VerifyTimer);
    }

    void setup()
    {
        VerifyTimer=TimerList.AddSeconds(VerifySensor, 5);  //  таймер на 5 секунд
        TimerList.TimerStop(VerifyTimer);                   // пока останавливаем
     
    }

    void loop()
    {
        if ((ReadSensor() > MEASUREVALUE) && (!TimerList.TimerActive(VerifyTimer))) TimerList.TimerStart(VerifyTimer); // если намерили больше, стартуем таймер

        if (StartNow)    // если и через 5 секунд то же значение - делаем чонить.
        {
            //.....DoSomething
        }

     
    }
     
    FlameWind нравится это.
  4. FlameWind

    FlameWind Нерд

    Тоесть мой подход неправильный?
    Нужно было сразу рассказать что хочу получить. Есть ультразвуковой датчик расстояния. Светодиодная лента подключенная через MosFET на pin 12. Раз в секунду опрашивается датчик. Если я прохожу мимо быстро, ничего не происходит. Если я подошел, датчик "видит" что я стою более 3 секунд к примеру, подает сигнал на включение. Пока я рядом он не должен отключаться, и если я вышел из поля действия держится включенным еще 17 секунд. При этом если я вернулся в момент обратного отсчета до выключения, просто переходит в режим включено, и новый отсчет пойдет когда я отойду.
    И чем в цикле for можно заменить delay? К примеру свет начал гаснуть уже, а я взял и подошел снова. И чтобы он не заканчивал цикл, а среагировал, и включился обратно.

    Код (C++):
    #include <Ultrasonic.h>
    Ultrasonic ultrasonic(10, 11);

    #define LL 13 // L-LED
    #define Sig 12 // MosFET Signal

    uint16_t prevRead, prevOnTimer = 0;
    uint16_t curOnTimer;
    uint32_t prevOffTimer = 0;
    uint32_t curOffTimer;
    byte cm;
    boolean Light, On = false;

    void setup() {
      pinMode(LL, OUTPUT);
      pinMode(Sig, OUTPUT);
      cm = ultrasonic.distanceRead();
    }
    void loop() {
    uint32_t curTimer = millis();
    if (curTimer - prevRead >= 1000) { // Чтобы сенсор меньше работал и больше простаивал
      prevRead = curTimer;
      cm = ultrasonic.distanceRead();
       if (cm < 10) {
         digitalWrite(LL, HIGH);
         On = true; }
        else {
         On = false;
         digitalWrite(LL, LOW); }
    }

    if ((curTimer - prevOnTimer >= 3000) and (On)) {
          prevOnTimer = curTimer;
        if (!Light) FaderUp(13);
    }

    if ((curTimer - prevOffTimer >= 17000) and (!On)) {
      prevOffTimer = curTimer;
      if (Light) FaderDown(13);
    }

    }

    void FaderUp(byte FadeDelay) {
     for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
        analogWrite(Sig, fadeValue);
        delay(FadeDelay);
      }
      digitalWrite(Sig, HIGH);
      Light = true;
    }

    void FaderDown(byte FadeDelay) {
     for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
        analogWrite(Sig, fadeValue);
        delay(FadeDelay);
      }
      digitalWrite(Sig, LOW);
      Light = false;
    }
     
    Последнее редактирование: 21 апр 2017
  5. DetSimen

    DetSimen Guest

    Нуууу... Это целый лагаритм писать надо...
     
  6. DetSimen

    DetSimen Guest

    Код (C++):
    #include <Ultrasonic.h>
    #include "uTimerList.h"
    Ultrasonic ultrasonic(10, 11);

    #define LL 13 // L-LED
    #define Sig 12 // MosFET Signal

    /*uint16_t prevRead, prevOnTimer = 0;
    uint16_t curOnTimer;
    uint32_t prevOffTimer = 0;
    uint32_t curOffTimer;
    byte cm;
    boolean Light, On = false;*/


    extern TTimerList TimerList;


    THandle HReadUltra;            // таймер опроса ультрасоника 1 раз в секунду
    THandle HWaitOff;              // таймер ожидания выключения раз в 17 секунд

    void ReadUltrasonic(void)
    {
        static byte seconds = 0;
        static int cm = ultrasonic.distanceRead();
        if (cm < 10) seconds++; else seconds = 0;
        if (seconds > 3)
        {
            LightOn();
        }
    }

    void LightOn()
    {
        digitalWrite(Sig, HIGH); //
        TimerList.TimerStop(HReadUltra);
        TimerList.TimerStart(HWaitOff);
    }

    void WaitOff(void)
    {
        static byte seconds = 0;
        int cm = ultrasonic.distanceRead();
        if (cm < 10) seconds = 0; else seconds++;
        if (seconds > 16) LightOff();

    }


    void LightOff()
    {
        digitalWrite(Sig, LOW); //
        TimerList.TimerStop(HWaitOff);
        TimerList.TimerStart(HReadUltra);
    }


    void setup() {
        pinMode(LL, OUTPUT);
        pinMode(Sig, OUTPUT);
        HReadUltra = TimerList.AddSeconds(ReadUltrasonic, 1); // раз в секунду чтение ультрасоника
        HWaitOff = TimerList.AddSeconds(WaitOff, 17);
        TimerList.TimerStop(HWaitOff);
    }




    void loop()
    {
    }
     
    попробуйте пока так, без фэйдера
     
    FlameWind нравится это.
  7. FlameWind

    FlameWind Нерд

    Не фурычит. А в Loop-то чего-нибудь должно быть?
     
  8. DetSimen

    DetSimen Guest

    в Loop ничего не надо. Ладно, приехаю с дачи, буду разбираца в понедельник
     
  9. FlameWind

    FlameWind Нерд

    Спасибо за желание помочь.
    Добавил включение LL чтобы видеть реагирует ли сенсор:
    Код (C++):
        if (cm < 10) {
          seconds++;
          digitalWrite(LL, HIGH); }
        else {
          seconds = 0;
          digitalWrite(LL, LOW); }
    Не реагирует.
     
  10. FlameWind

    FlameWind Нерд

    Починил. И что самое главное практически понял как оно работает =)
    Ошибка была в таймере HWaitOff, его тоже нужно на 1 секунду, и внутри уже отсчетом обрабатывать, иначе он каждый отсчет по 17 секунд делает.

    Почему-то перестали работать delay внутри void Fader. Есть идеи как красиво Faderы сделать?

    Код (C++):

    #include "uTimerList.h"
    #include <Ultrasonic.h>
    Ultrasonic ultrasonic(10, 11);

    #define LL 13   // L-LED
    #define Sig 12  // MosFET Signal

    byte cm;
    byte FadeUpDelay = 37;
    byte FadeDownDelay = 73;
    boolean Light = false;
    boolean FdUp, FdDown = false;
    boolean Debug = false;

    extern TTimerList TimerList;

    THandle HReadUltra;          // таймер опроса ультрасоника
    THandle HWaitOff;              // таймер ожидания выключения

    void ReadUltrasonic(void) {
        static byte seconds = 0;
        cm = ultrasonic.distanceRead();
        if (cm < 10) {
          seconds++;
          digitalWrite(LL, HIGH); }
        else {
          seconds = 0;
          digitalWrite(LL, LOW); }
        if (seconds > 2) { LightOn(); }
    }

    void LightOn() {
        if (!Light) FaderUp(37);
        TimerList.TimerStop(HReadUltra);
        TimerList.TimerStart(HWaitOff);
    }

    void WaitOff(void) {
        static byte seconds = 0;
        cm = ultrasonic.distanceRead();
        if (cm < 10) { seconds = 0; digitalWrite(LL, HIGH); } else { seconds++; digitalWrite(LL, LOW); }
        if (seconds >= 17) LightOff();
    }

    void LightOff() {
        if (Light) FaderDown(73);
        TimerList.TimerStop(HWaitOff);
        TimerList.TimerStart(HReadUltra);
    }

    void setup() {
        if (Debug) Serial.begin(9600);
        pinMode(LL, OUTPUT);
        pinMode(Sig, OUTPUT);
        HReadUltra = TimerList.AddSeconds(ReadUltrasonic, 1);
        HWaitOff = TimerList.AddSeconds(WaitOff, 1);
        TimerList.TimerStop(HWaitOff);
    }

    void loop() {
      if (Debug) { Serial.println(cm); delay(1000); }
    }

    void FaderUp(byte FadeDelay) {
      for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
        analogWrite(Sig, fadeValue);
        delay(FadeDelay);
      }
      digitalWrite(Sig, HIGH);
      Light = true;
    }

    void FaderDown(byte FadeDelay) {
      for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
        analogWrite(Sig, fadeValue);
        delay(FadeDelay);
      }
      digitalWrite(Sig, LOW);
      Light = false;
    }
     
     
  11. DetSimen

    DetSimen Guest

    Идеи есть. Так же, через таймеры. Только мне с дачи писАть неудобна.
     
  12. FlameWind

    FlameWind Нерд

    Я тоже подумал что через таймеры. Уже пытаюсь код написать. Хорошего отдыха на даче.
     
  13. DetSimen

    DetSimen Guest

    Таймеры можно останавливать, запускать, менять интервал срабатывания. В uTimerList.h есть комментарии. Пока почитай, пропробуй, а я в даче наотды.уярюсь. До понедельника.
     
  14. DetSimen

    DetSimen Guest

    пока не в состоянии помочь, навалили работы. :(
     
  15. FlameWind

    FlameWind Нерд

    Сделал вот такой вариант. Понимаю что криво, но работает.
    Обнаружился косяк небольшой: если отойти в момент включения, то таймер WaitOff не срабатывает, но включение происходит, и не выключается. Если постоять более 3 секунд, потом выключиться.
    Кстати, уже все собрал и установил. Задумка оказалась очень полезная.
    Код (C++):

    #include "uTimerList.h"
    #include <Ultrasonic.h>
    Ultrasonic ultrasonic(6, 7);

    #define LL 13   // L-LED
    #define Sig 11  // MosFET Signal

    byte cm;
    byte fadeValue = 0;
    byte FadeUpDelay = 7;       // Включаем быстрее
    byte FadeDownDelay = 13; // Выключаем медленнее
    boolean Light = false;
    boolean Debug = false;

    extern TTimerList TimerList;

    THandle HReadUltra; // таймер опроса сенсора
    THandle HWaitOff;   // таймер ожидания выключения
    THandle TFadeUp;
    THandle TFadeDown;

    void ReadUltrasonic(void) {
        static byte seconds = 0;
        cm = ultrasonic.distanceRead();
        if (cm < 90) {
          seconds++;
          digitalWrite(LL, HIGH); }
        else {
          seconds = 0;
          digitalWrite(LL, LOW); }
        if (seconds > 2) { LightOn(); }
    }

    void LightOn() {
        if (!Light) { TimerList.TimerStart(TFadeUp); fadeValue = 0; FaderUp(); }
        TimerList.TimerStop(HReadUltra);
        TimerList.TimerStart(HWaitOff);
    }

    void WaitOff(void) {
        static byte seconds = 0;
        cm = ultrasonic.distanceRead();
        if (cm < 90) { seconds = 0; digitalWrite(LL, HIGH); } else { seconds++; digitalWrite(LL, LOW); }
        if (seconds >= 17) LightOff();
    }

    void LightOff() {
        if (Light) { TimerList.TimerStart(TFadeDown); fadeValue = 255; FaderDown(); }
        TimerList.TimerStop(HWaitOff);
        TimerList.TimerStart(HReadUltra);
    }

    void setup() {
        if (Debug) Serial.begin(9600);
        pinMode(LL, OUTPUT);
        pinMode(Sig, OUTPUT);
        HReadUltra = TimerList.AddSeconds(ReadUltrasonic, 1); // раз в секунду чтение сенсора
        HWaitOff = TimerList.AddSeconds(WaitOff, 1);
        TimerList.TimerStop(HWaitOff);
        TFadeUp = TimerList.Add(FaderUp, FadeUpDelay);
        TFadeDown = TimerList.Add(FaderDown, FadeDownDelay);
        TimerList.TimerStop(TFadeUp);
        TimerList.TimerStop(TFadeDown);
        cm = ultrasonic.distanceRead();
    }

    void loop() {
      if (Debug) { Serial.println(cm); delay(1000); }
    }

    void FaderUp(void) {
      fadeValue += 1;
      analogWrite(Sig, fadeValue);
      if (fadeValue >= 255) { TimerList.TimerStop(TFadeUp); Light = true; }
    }

    void FaderDown(void) {
      fadeValue -= 1;
      analogWrite(Sig, fadeValue);
      if (fadeValue <= 0) { TimerList.TimerStop(TFadeDown); Light = false; }
    }
     
  16. DetSimen

    DetSimen Guest

    Попробуй логику переставь
    Код (C++):
    void LightOn() {
        TimerList.TimerStop(HReadUltra);
        TimerList.TimerStart(HWaitOff);
        if (!Light) { TimerList.TimerStart(TFadeUp); fadeValue = 0; FaderUp(); }
    }
     
  17. FlameWind

    FlameWind Нерд

    Попробую. Как бы фейдеры красиво сделать? Чтобы функция "понимала" текущее состояние PWM, и в зависимости от того что нужно сделать, плавно включала или выключала.
     
  18. DetSimen

    DetSimen Guest

    Сделал, или помогать опять? пока я посвободнее
     
  19. FlameWind

    FlameWind Нерд

    Помогать =)
     
  20. DetSimen

    DetSimen Guest

    направление дам
    создаем тип enum TLightDirection {ldNone=0,ldUp,ldDown};
    потом описываем глобальную переменную этого типа
    TLightDirection LightDirection = ldNone;

    в сетапе создаем таймер на скокото миллисекунд, который будет вызывать функцию света
    THandler hLightTimer = TimerList.Add(LightFunction, ms=скоко надо миллисекунд);
    TimerList.TimerStop(hLightTimer) // и пока останавливаем его, события еще не было.

    где-то, где по логике надо ВЫКЛЮЧИТЬ свет, пишем
    LightDirection = ldDown;
    TimerList.TimerStart(hLightTimer)

    а где надо ВКЛЮЧИТЬ
    LightDirection = ldUp;
    TimerList.TimerStart(hLightTimer)

    и сопсно функция света: примерно такая по логике

    void LightFunction(void)
    {
    switch (LightDirection)
    {
    case ldNone: break;
    case ldUp: if (Свет<MAX) Свет+=дельта; else TimerList.TimerStop(hLightTimer);
    break; //логика вывода света
    case ldDown:if (Свет>0) Свет-=дельта; else TimerList.TimerStop(hLightTimer);
    break;
    }
    }

    примерно так. Только помни, что таймер1 портит ШИМ на каких-то ногах (не помню, почитай), не используй эти ноги для включения\выключения. Чонепонятного будет - после празьников обращайся.
     
    FlameWind нравится это.