Почему не работает код?

Тема в разделе "Arduino & Shields", создана пользователем Vittorio, 28 май 2016.

  1. Vittorio

    Vittorio Нуб

    Каждые 10 сек включить светодиод на 3 сек.
    Код (C++):
    #define LED_PIN    13
    unsigned long x = 10000;
    unsigned long y =  3000;

    void setup()
    {
      pinMode(LED_PIN, OUTPUT);
    }

    void loop()
    {
      static unsigned long OnTime = millis();
      static unsigned long OffTime = 0;

      if (millis() - OnTime > x) // каждые X сек включаем
      {
        OnTime = millis();
        OffTime = millis() + y; // задаем время отключения
        digitalWrite(LED_PIN, HIGH);
      }

      if (millis() > OffTime)    // по прошествии Y сек отключаем
      {
        OnTime = millis();        // сбрасываем счетчик
        OffTime = millis() + x;
        digitalWrite(LED_PIN, LOW);
      }
    }
     
    Однако включается и не отключается.
    Что не так?
     
  2. AlexU

    AlexU Гуру

    Код почти правильный (светодиод должен моргать), вот только период будет увеличиваться с каждой итерацией на 3 секунды.
    Что бы период был точно 10 сек, нужно исправить функцию 'loop()':
    Код (C++):
    void loop()
    {
      static unsigned long OnTime = millis();
      static unsigned long OffTime = OnTime + y;

      if (millis() - OnTime > x) // каждые X сек включаем
      {
        OnTime = millis();
        OffTime = millis() + y; // задаем время отключения
        digitalWrite(LED_PIN, HIGH);
      }

      if (millis() > OffTime)    // по прошествии Y сек отключаем
      {
        digitalWrite(LED_PIN, LOW);
      }
    }
    Если у вас не моргает, то проблема скорее в схеме, в плате Arduino или в компиляторе....
     
  3. Vittorio

    Vittorio Нуб

    СПАСИБО!
    Все работает, как и задумано.
     
  4. joman

    joman Гик

    Не могли бы вы Объяснить подробно эту конструкцию:
    Код (C++):
    static unsigned long OnTime = millis();
    Для каких целей тут слово static и что оно делает?
     
  5. ostrov

    ostrov Гуру

    Какой вычурный код у вас получился! А вообще, если программа ичего больше не делает то сойдет и такое:
    Код (C++):
    #define LED_PIN    13
    unsigned long x = 10000;
    unsigned long y =  3000;

    void setup()
    {
      pinMode(LED_PIN, OUTPUT);
      digitalWrite(LED_PIN, LOW);
    }

    void loop() {
      delay(10000);
      digitalWrite(LED_PIN, HIGH);
      delay(3000);
      digitalWrite(LED_PIN, LOW);
    }
    Это же блинк обычный с несимметричными паузами. Да и через millis() можно было как то проще сделать.
     
  6. Tomasina

    Tomasina Сушитель лампочек Модератор

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

    Флаг static запрещает компилятору очищать память, зарезервированную для переменной OnTime, при выходе из функции.
    При первом заходе в эту функцию значение переменной OnTime будет выставлено равным текущему значению millis() - допустим, 1234.
    При выходе из функции значение этой переменной останется в памяти (если бы не было static, то пропало бы) и может быть использовать при последующих проходах этой функции (но только внутри этой функции, т.к. это локальная переменная).
    Можно считать этот метод как безопасную (и рекомендуемую) замену глобальных переменных.
     
    joman нравится это.
  7. joman

    joman Гик

    А почему не вынести в глобальные переменные, тем более, если автору надо будет изменить из другой функции период, он сможет это сделать без проблем.
     
  8. Tomasina

    Tomasina Сушитель лампочек Модератор

    потому что глобальные переменные - это плохо. Что-то изменить извне можно, если предусмотреть для этой функции входные параметры.
     
  9. ostrov

    ostrov Гуру

    Нате вам такой вариант еще:
    Код (C++):
    #define LED_PIN    13
    unsigned int x = 10000;
    unsigned int y =  3000;
    unsigned long timerXY;
    bool v = 0;

    void setup()
    {
      pinMode(LED_PIN, OUTPUT);
      digitalWrite(LED_PIN, LOW);
      timerXY = millis() + x;
    }

    void loop() {
      if (millis() > timerXY) {
        v = !v;
        digitalWrite(LED_PIN, v);
        timerXY = millis() + (v ? y : x);
      }
    }
    По мне так ничего плохого в глобальных переменных нет. Если не путаться в них, конечно.
     
    Tomasina и joman нравится это.
  10. Tomasina

    Tomasina Сушитель лампочек Модератор

    вот это уже красиво. Но bool v =0; надо внести внутрь, т.к. она больше нигде не используется.
     
  11. joman

    joman Гик

    Плохо не понимать, что делаешь. А в глобальных переменных особо плохого нету.
    Ну и из опыта:
    Код (C++):
    if (millis() - OnTime > x)
    после, по моему, 52 дней работы, этот код перестанет работать и придется либо перезагрузить ардуину, либо переделывать код.
     
  12. ostrov

    ostrov Гуру

    Так она сбрасываться будет каждую итерацию loop().
     
  13. ostrov

    ostrov Гуру

    Один раз в месяц глюкнет мигалка, или темно будет не 10 сек или светло не 3 сек, а меньше. Вот и все.
     
  14. Tomasina

    Tomasina Сушитель лампочек Модератор

    если ее описать как static, то не будет.
     
  15. joman

    joman Гик

    В вашем случае(коде) - да.
    А в случае нахождения разности, она в if вообще перестанет попадать после срока достижения максимального значения, и, соответственно, перестанет устанавливать OnTime, который будет огромный, а milis() будет мал.
     
  16. ostrov

    ostrov Гуру

    Ну я все же предпочитаю глобальные флаги в таких случаях. )
     
    joman нравится это.
  17. ostrov

    ostrov Гуру

    А еще мой вариант экономит машинное время, вычисляя разницу один раз за период, а не каждый раз. )

    Насчет зависания даже сразу не соображу, разница в примере будет огромным минусом и она будет меньше х. Что это значит?
     
  18. Tomasina

    Tomasina Сушитель лампочек Модератор

    на форуме arduino.ru была целая баталия по поводу переполнения.
    Вкратце:
    Код (C++):

    unsigned long timeoff = millis(); // засекаем время // важно, чтобы именно unsigned
    // ...
    if (millis() - timeoff >= INTERVAL)  // это правильная запись, переполнение не влияет на результат
    if (millis() > timeoff + INTERVAL)  // это неправильно, никогда не пишите так.
     
  19. ostrov

    ostrov Гуру

    Я так делаю:

    Код (C++):
    timeoff = millis() + INTRVAL;
    ...
    if (millis() > timeoff) {
    ..
    }
     
    Работает и правильно и быстро.
     
  20. joman

    joman Гик

    В общем, там что то с переполнением.
    Правда я сейчас подумал, какая разница, когда оно будет происходить при вычитании, или при сложении.
    Одно точно: при сложении оно произойдёт один раз и пока milis() не переполнится, программа попадёт в цикл.
    А вот при вычитании поведение программы менее очевидно.