Помогите с скетчем 2 светодиода одна кнопка

Тема в разделе "Arduino & Shields", создана пользователем KiVor, 5 окт 2015.

  1. KiVor

    KiVor Нерд

    Всем привет! Изучаю Ардуино и программирование только месяц.

    Прошу помощи... есть скетч работы таймера по принципу: "нажал, светик горит, таймер пошел, отсчитался и выключилось". Отличное применение если делать проходной выключатель. А вот у меня появилась идея применить это к рольставням.

    Дано: 2 светодиода, одна кнопка.

    Логика: нажимаем, горит первый светик, пошел отсчет к приммеру 10 сек. По истечению гаснит. Но если нажал досрочно, светик потух досрочно. Ещё нажатие, загорается уже второй светик. И так же что бы можно было досрочно выключить. и Циклично все это.

    Помогите пожалуйста как можно это сделать?

    Код (C++):
    long previousMillis = 0;
    int val=0;

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

    void loop()

    {
         if(digitalRead(14)==HIGH)//если кнопка нажата ...
         {
           
          if (millis() -previousMillis >500)  
         {
            previousMillis = millis();  
            val++;
         }
         }
         else
         {
           val=0;
         }
         
         if(val>=5)
         {
           digitalWrite(13,!digitalRead(13));//инвертируем состояние пина
           val=0;
         }
         
         
    }
     
     
    Последнее редактирование: 7 окт 2015
  2. Tomasina

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

    "В предыдущем посту" - это где?
     
  3. KiVor

    KiVor Нерд

    Сорри, читал тему просто другую, разговаривал сам с собой)
    Прикрепил к первому посту
     
  4. vvr

    vvr Инженерище

    Код (C++):
    long previousMillis = 0;
    int val = 0;
    int state = 0;

    void setup()
    {
      pinMode(13, OUTPUT);
      pinMode(14, INPUT);
    }

    void loop()
    {
      if(digitalRead(14) == HIGH && state == 0)
      {
        state = 1;
        digitalWrite(13, HIGH);
        if (millis() - previousMillis > 500)
        {
          previousMillis = millis();  
          val++;
        }
      }
      if(val >= 20)
      {
        digitalWrite(13, LOW);
        val = 0;
        state = 0;
      }
      if(digitalRead(14) == HIGH && state == 1)
      {
        digitalWrite(13, LOW);
        val = 0;
        state = 0;
      }
    }
     
    Только антидребезг кнопки сделать нужно
     
    egordorichev нравится это.
  5. KiVor

    KiVor Нерд

    ммм, я не силен в программировании, но по-моему ваш код это простейшее включение и выключение светика с "фиксацией". Либо у меня что-то не так работает...
     
  6. Mestniy

    Mestniy Гуру

    Нет вам тут не просто вкл выкл. А пауза в 0,5 сек...
     
  7. Mestniy

    Mestniy Гуру

    А что кстати у Вас не так работает?
     
  8. KiVor

    KiVor Нерд

    Вот паузы я что-то не наблюдаю. В коде я ее вижу, как работает это на деле: Нажимаешь - загорается, нажимаешь еще раз - тухнет. и все.
     
  9. vvr

    vvr Инженерище

    Код (C++):
    long previousMillis = 0;
    int val = 0;
    int state = 0;

    void setup()
    {
      pinMode(13, OUTPUT);
      pinMode(14, INPUT);
    }

    void loop()
    {
      if(digitalRead(14) == HIGH && state == 0)
      {
        state = 1;
      }  
      if(state == 1)
      {
        digitalWrite(13, HIGH);
        if (millis() - previousMillis > 500)
        {
          previousMillis = millis();
          val++;
          Serial.println(val);
        }  
        if(val >= 20)
        {
          digitalWrite(13, LOW);
          val = 0;
          state = 0;
        }
      }
      if(digitalRead(14) == HIGH && state == 1)
      {
        digitalWrite(13, LOW);
        val = 0;
        state = 0;
      }
    }

     
     
  10. Salk

    Salk Гик

    Все гениальное просто. Лови - поочередное включение двух светодиодов одной кнопкой с возможностью их досрочного погашения.
    Код (C++):
    // Таймер
    #define TIME_LED_OFF 3000    // 3 сек
    unsigned long int time_led_off;

    int state;

    void setup()
    {
      pinMode(12, OUTPUT); // светодиод 1
      pinMode(13, OUTPUT); // светодиод 2
      pinMode(11, INPUT);  // кнопка
    }

    void loop()
    {
      delay(150);
      // Нажимаем кнопку
      if (digitalRead(11) == HIGH)
      {
        state += 1;
        time_led_off = millis();
      }
      // первое нажатие включает светодиод 1
      if (state == 1)
      {
        digitalWrite(12, HIGH);
        // выключает по таймеру
        if (millis() - time_led_off > TIME_LED_OFF)
        {
          digitalWrite(12, LOW);
          state = 2;
        }
      }
      // второе нажатие - досрочно выключает первый светодиод
      if (state == 2)
      {
        digitalWrite(12, LOW);
      }
      // третье нажатие включает второй светик
      if (state == 3)
      {
        digitalWrite(13, HIGH);
        // отключает его по таймеру
        if (millis() - time_led_off > TIME_LED_OFF)
        {
          digitalWrite(13, LOW);
          state = 0;
        }
      }
      // четвертое нажатие отключает светик досрочно
      if (state == 4)
      {
        digitalWrite(13, LOW);
        state = 0; // возвращаемся в начало
      }
    }
     
    Belonenko и KiVor нравится это.
  11. Mestniy

    Mestniy Гуру

    Ну я думаю помогли, лучше некуда! Попробуй похимичить со скетчем, быстро сам допетришь. А потом будешь вспоминать, какой же я был дуб!)))
     
  12. KiVor

    KiVor Нерд

    Оболдеть!!! Действительно все просто...
    Спасибо Вам огромное!!!
    Сейчас только подниму внутреннюю подтяжку и попробую это все засунуть в свой большой скетч.
     
  13. KiVor

    KiVor Нерд

    Я немного еще по-надоедаю Вам, можно? Чтобы не плодить темы.
    С этим скетчем я почти разобрался, есть пара моментов конечно до которых я не допер, но это все из-за отсутствия знаний и опыта. Я попытался вклеять этот скетч в свой более крупный, который я собирал по крупинкам со всего инета, но который даже работает)
    Но у меня этого не вышло. Дело в том, что у меня там уже присутствует "delay(5000);" и когда я удалил "delay(150);" из последнего кода, я обнаружил что 2 реле начинают переключаться с бешеной скоростью.
    С попыткой соединить 2 скетча пока отложено, решил разобраться что не так. Дело в этом скетче, что мне предложил Salk. Да, он работает, но если зажать кнопку, то реле начинают переключаться, т.е. выполнять весь цикл без остановок.
    Сижу ковыряю пытаюсь подогнать, сделать по аналогии с кодом, который у меня уже есть, который просто вкл/выкл светодиод от каждого нажатия, но что-то не выходить.
    Подскажите, куда обратить внимание мне нужно. Готовые решения конечно хорошо, но хочется и самому додумать...
     
  14. Salk

    Salk Гик

    Старайтесь полностью избавиться от delay. Т.к. они тормозят весь цикл. И опрос кнопок, пока идет ожидание (delay) не возможна. Я могу предположить, что быстрое переключение реле, из-за того что очень часто опрашивается кнопка и переменная state очень быстро изменяется, что приводит к прохождению всех этапов (state 1, 2, 3 и т.д.) за очень короткое время.
    Копать нужно в этом направлении, нужно заставить обрабатывать состояние кнопки, либо один раз за нажатие, т.е. засчитывать нажатие кнопки после её отпускания, тогда не будет циклического повторения действий совсем, либо раз в некоторое время. Тогда при зажатой кнопке цикл будет повторятся, но с некой задержкой, как было в моем примере с delay().
    Вот пример кода с задержкой обработки кнопки раз в 500 мс, но с применением millis(), которая не тормозит весь остальной код. Времени (500 мс) достаточно, чтобы один раз нажать кнопку и отпустить для выполнения однократного действия. Задержку можно менять.
    Код (C++):
    // Таймер
    #define TIME_LED_OFF 3000    // 3 сек
    unsigned long int time_led_off;
    // Таймер для обработки кнопки
    #define TIME_BUTTON 500    // 500 мс
    unsigned long int time_button;

    int state;

    void setup()
    {
      pinMode(12, OUTPUT); // светодиод 1
      pinMode(13, OUTPUT); // светодиод 2
      pinMode(11, INPUT);  // кнопка
    }

    void loop()
    {
      // Нажимаем кнопку, опрос кнопки будет происходить раз в 500 мс
      if (millis() - time_button > TIME_BUTTON)
      {
        if (digitalRead(11) == HIGH)
        {
          state += 1;
          // сбрасываем таймеры
          time_led_off = millis();
          time_button = millis();
        }
      }
      // первое нажатие включает светодиод 1
      if (state == 1)
      {
        digitalWrite(12, HIGH);
        // выключает по таймеру
        if (millis() - time_led_off > TIME_LED_OFF)
        {
          digitalWrite(12, LOW);
          state = 2;
        }
      }
      // второе нажатие - досрочно выключает первый светодиод
      if (state == 2)
      {
        digitalWrite(12, LOW);
      }
      // третье нажатие включает второй светик
      if (state == 3)
      {
        digitalWrite(13, HIGH);
        // отключает его по таймеру
        if (millis() - time_led_off > TIME_LED_OFF)
        {
          digitalWrite(13, LOW);
          state = 0;
        }
      }
      // четвертое нажатие отключает светик досрочно
      if (state == 4)
      {
        digitalWrite(13, LOW);
        state = 0; // возвращаемся в начало
      }
    }
    А я вам и не предлагаю готовых решений, предлагаю лишь пример, точно такие же, которые вы находили в интернете. Изменять и добавлять под свои нужды, Вы уже будете сами :)
     
    Последнее редактирование: 7 окт 2015
  15. KiVor

    KiVor Нерд

    А третьего варианта нет для такой задачи, как моя? Все-таки пользоваться этим будет вся семья и хотелось бы чтобы все было четко.
    А так спасибо за пример!

    У меня есть вот такой кусочек кода:
    Код (C++):
      if (lastDebounceTime1 > millis()) lastDebounceTime1 = 0;
    boolean reading1 = digitalRead(pin7);
      if (reading1 != last_pin7_state) lastDebounceTime1 = millis();
      if ((millis() - lastDebounceTime1) > 30) {
        if (reading1 != pin7_state) {
          pin7_state = reading1;
          if (pin7_state == LOW) {
            digitalWrite(pin2, !digitalRead(pin2));
            if (digitalRead(pin2)) client.publish("/myhome/out/rele1", "OFF");
            else client.publish("/myhome/out/rele1", "ON");
          }
        }
      }
      last_pin7_state = reading1;
    Это просто вкл/выкл по каждому нажатию (если не обращать внимание на концовку, где публикация), а last_pin7_state введена для удобства, т.к. реле у меня есть с подтяжкой на + и на - не знаю как правильно называются, плюс подтяжка на самой ардуино. Там состояние LOW).
    Ведь здесь реле отрабатывает при нажатии, а не отпускании, но при этом цикл не крутиться, если зажать. Если честно, данный код я слабо понимаю, буду признателен, если растолкуете.
     
  16. Salk

    Salk Гик

    Так, уточняйте тогда, что вам нужно от кнопки :) Есть и третье решение. Я подредактировал свой код, но дописал комментарии, он по механике схож с тем, что вы предоставили. Теперь не зависимо, удерживаем мы кнопку или нет выполнится только одно действие сразу же после нажатия, но также как и раньше имеем досрочное погашение и переключение между реле светодиодами.
    Изучайте, попытайтесь понять логику. Грубо говоря, мы позволяем программе считывать повторное нажатие кнопки, только после того, как эту же кнопку мы отпустили. Плюс небольшое время для нейтрализации дребезга и вуаля :)
    Код (C++):
    // Таймер после которого светодиоды гаснут
    #define TIME_LED_OFF 3000    // 3 сек
    unsigned long int time_led_off;
    // Таймер для антидребезга кнопки, его можно поставить меньше, но не суть
    #define TIME_BUTTON 100    // 100 мс
    unsigned long int time_button;

    int state;
    int val; // флаг для однократного выполнения действия

    void setup()
    {
      pinMode(12, OUTPUT); // светодиод 1
      pinMode(13, OUTPUT); // светодиод 2
      pinMode(11, INPUT);  // кнопка
    }

    void loop()
    {
      // Нажимаем кнопку и считываем состояние кнопки только после 100 мс, когда дребезг контактов кнопки устаканился
      if (millis() - time_button > TIME_BUTTON)
      {
        // Нажимаем кнопку
        if (digitalRead(11) == HIGH)
        {
          // Если нажали кнопку, то выполним только одно действие
          if (val != 1) // если val НЕ равна 1, а изначально она 0, то
          {
            state += 1; // выполняем какие-то действия
            // сбрасываем таймер для светодиодов
            time_led_off = millis();
            val = 1; // присваиваем переменной val =1, что не даст циклу выполнится многократно
          }
        }
        else
        {
          // выполнять другие действия мы можем, только после того,
          // как кнопка была отпущена (digitalRead(11) == LOW)
          val = 0;
          time_button = millis(); // сбросим таймер антидребезга кнопки
        }
      }
      // дальше по порядку
      // первое нажатие включает светодиод 1
      if (state == 1)
      {
        digitalWrite(12, HIGH);
        // выключает по таймеру
        if (millis() - time_led_off > TIME_LED_OFF)
        {
          digitalWrite(12, LOW);
          state = 2;
        }
      }
      // второе нажатие - досрочно выключает первый светодиод
      if (state == 2)
      {
        digitalWrite(12, LOW);
      }
      // третье нажатие включает второй светик
      if (state == 3)
      {
        digitalWrite(13, HIGH);
        // отключает его по таймеру
        if (millis() - time_led_off > TIME_LED_OFF)
        {
          digitalWrite(13, LOW);
          state = 0;
        }
      }
      // четвертое нажатие отключает светик досрочно
      if (state == 4)
      {
        digitalWrite(13, LOW);
        state = 0; // возвращаемся в начало
      }
    }
     
    Последнее редактирование: 7 окт 2015
  17. KiVor

    KiVor Нерд

    Огромнейшее спасибо за подробные комментарии! Сейчас буду разбираться!
     
  18. Адам

    Адам Нерд

    кто ни будь смог бы помочь написать скетч по моему поводу
     
  19. vvr

    vvr Инженерище

    по какому?
     
  20. Адам

    Адам Нерд

    // Таймер для антидребезга кнопки, его можно поставить меньше, но не суть
    #define ret 100 // 100 мс
    unsigned long int dreb;
    int state;
    int val; // флаг для однократного выполнения действия

    void setup()
    {
    pinMode(10, OUTPUT); // МИГАЛКА
    pinMode(12, OUTPUT); // светодиод 1
    pinMode(13, OUTPUT); // светодиод 2
    pinMode(11, INPUT); // кнопка
    }

    void loop()
    {
    // Нажимаем кнопку и считываем состояние кнопки только после 100 мс, когда дребезг контактов кнопки устаканился
    if (millis() - dreb> 100)
    {
    // Нажимаем кнопку
    if (digitalRead(11) == HIGH)
    {
    // Если нажали кнопку, то выполним только одно действие
    if (val != 1) // если val НЕ равна 1, а изначально она 0, то
    {
    state += 1; // выполняем какие-то действия


    val = 1; // присваиваем переменной val =1, что не даст циклу выполнится многократно
    }
    }
    else
    {
    // выполнять другие действия мы можем, только после того,
    // как кнопка была отпущена (digitalRead(11) == LOW)
    val = 0;

    }
    }
    // дальше по порядку
    // первое нажатие включает светодиод 1
    if (state == 1)
    {
    digitalWrite(12, HIGH);
    // выключает по таймеру



    }
    // второе нажатие - досрочно выключает первый светодиод
    if (state == 2)
    {
    digitalWrite(12, LOW);
    }
    // третье нажатие включает второй светик
    if (state == 3)
    {
    digitalWrite(13, HIGH);
    // отключает его по таймеру


    }
    // четвертое нажатие отключает светик досрочно
    if (state == 4)
    {
    digitalWrite(13, LOW);
    state = 0; // возвращаемся в начало
    }
    }