Оброботка кнопки .

Тема в разделе "Arduino & Shields", создана пользователем &Anton, 29 ноя 2014.

  1. &Anton

    &Anton Нерд

    Всем привет есть у меня програмка с тремя меню , разница только во времени , а выбрать можно тремя кнопками .Обьясните как тоже самое сделать одной кнопкой , тоесть при одном нажатии выберался первый режим при повторном втором ,третим и назад на первый.
    Код (Text):

    const int moveUp = 7;
    const int moveDown = 5;
    const int sensUp =  3;
    const int sensDown =  4;
    const int sensStart =  13;



    int buttonStateUp = 0;
    int buttonStateDown = 0;



    byte key(){
      int val = analogRead(0);
        if (val < 50) return 5;
        else if (val < 150) return 3;
        else if (val < 350) return 4;
        else if (val < 500) return 2;
        else if (val < 800) return 1;
        else return 0;
    }



    void setup() {
     
      pinMode(moveUp, OUTPUT);
      pinMode(moveDown, OUTPUT);
      pinMode(sensUp, INPUT);
      pinMode(sensDown, INPUT);
      pinMode(sensStart, INPUT);

     
    }
    void loop(){
     
      byte KEY = key(); // читаем состояние кнопок
     
      if (key() == 1) regime5();
      else if (key() == 2) regime10();
      else if (key() == 3) regime15();
      }
     



    void regime5(){
     
     
      int looptime = 300000;
      int i; // counter
      for (i = 0; i < looptime; i++)
     
      {
     
     

      buttonStateUp = digitalRead(sensStart);
      buttonStateUp = digitalRead(sensUp);
      buttonStateDown = digitalRead(sensDown);
     
     
     
      if (buttonStateUp != buttonStateDown){
      digitalWrite(moveUp, buttonStateUp);
      digitalWrite(moveDown, buttonStateDown);
      }
      loop();
    }
    }

    void regime10(){
     
      int looptime = 600000; // loop runs
      int i; // counter
      for (i = 0; i < looptime; i++)
     

      {
     
     

      buttonStateUp = digitalRead(sensStart);
      buttonStateUp = digitalRead(sensUp);
      buttonStateDown = digitalRead(sensDown);
     
     
     
      if (buttonStateUp != buttonStateDown){
      digitalWrite(moveUp, buttonStateUp);
      digitalWrite(moveDown, buttonStateDown);
      }
      loop();
    }
    }
    void regime15(){
     
     
      int looptime = 900000; // loop runs
      int i; // counter
      for (i = 0; i < looptime; i++)
     
      {
     
     

      buttonStateUp = digitalRead(sensStart);
      buttonStateUp = digitalRead(sensUp);
      buttonStateDown = digitalRead(sensDown);
     
     
     
      if (buttonStateUp != buttonStateDown){
      digitalWrite(moveUp, buttonStateUp);
      digitalWrite(moveDown, buttonStateDown);
      }
      loop();
    }
    }
     
     
     
     
     
     
     
     
     
     
  2. Megakoteyka

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

    Код (Text):
    int menu = 0;
    ...
    if(buttonPressed)
    {
      menu++;
      if(menu >= 3)
        menu = 0;
    }
     
  3. Alex19

    Alex19 Гуру

    У меня вопрос к Megakoteyka.

    Просто из любопытства, зачем вообще может понадобится, вызывать loop в каждой из функций regime5() и т.д.?

    Я бы убрал, из этих функций, так как она и так будет вызвана.
    А вызывая каждый раз loop, на сколько я понимаю, могут быть проблемы, если в loop будет добавлена обработка чего-то еще в конец функции loop.

    Поправьте меня, если я ошибаюсь.

    UPD. Проверил, мыслю правильно. Вот пример

    Код (Text):

    void setup()
    {
      Serial.begin(9600);
    }

    void loop()
    {
      Serial.println("1");
      delay(100);
      test();
     
      Serial.println("3");
    }

    void test()
    {
      loop();
    }
     
    Так вот Serial.println("3"); ни когда не будет выполнен.
     
    Последнее редактирование: 29 ноя 2014
    Megakoteyka нравится это.
  4. geher

    geher Гуру

    Может быть я не прав, но этот вызов loop вообще может кончиться переполнением стека при зажатой кнопке, ибо рекурсия получается.
    analogRead будет возвращать одно и то же значение, loop будет вызывать соответствующий regime, который будет вызывать loop.
    На этом фоне дополнительная нагрузка в виде чего-то в конце loop будет сущей мелочью. Более того, вызов этого чего-то может быть полезен для сохранения фонового выполнения этого чего-то во время исполнения regime.
     
    Alex19 нравится это.
  5. Alex19

    Alex19 Гуру

    Возможно, именно рекурсия.

    Код по меньшей мере странный. Вызов loop, for, присвоение к buttonStateUp.

    UPD.
    Не понимаю, что он читает analogRead, поэтому не уверен.

    Не понял, оно просто не будет выполнено, так как не попадет туда.
     
    Последнее редактирование: 29 ноя 2014
  6. Megakoteyka

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

    Я не настолько внимательно код читал, в глаза не бросилось.
    Все верно, так делать не нужно. И переполнение стека может случиться, и логика корявая получается.
     
    Alex19 нравится это.
  7. Megakoteyka

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

    Вот это тоже ересь:
    Код (Text):
    int looptime = 300000;
    int looptime = 600000;
    int looptime = 900000;
    &Anton, попробуйте вывести значение переменной в Serial и посмотрите на результат. А потом почитайте о типах данных (чем int отличается от long).
     
    Alex19 нравится это.
  8. geher

    geher Гуру

    Учитывая, что по градации значений из analogRead принимаются решения, а разговор идет о кнопках, то логично предположить, что это клавиатура, подключенная к аналоговому входу, для которой каждой кнопке соответствует свой уровень на этом входе.
    Соответственно, если кнопку зажать, на входе будет все время один и тот же уровень.
    Я имел ввиду следующее.
    Если в конец loop добавить какую-то обработку, то на время выполнения длительных процедур, вызванных из loop, этот код будет недоступен. Чтобы этот код все-таки выполнялся, нужно вызвать loop.
    Логика, конечно, корявая и чреватая ошибками, но какая-то тем не менее есть.
    Естественно, чтобы означенный код (добавленный в конец loop) все-таки гарантированно выполнился, а также чтобы предотвратить рекурсию, следует вывешивать какой-то флаг, запрещающий опрос клавиатуры и вызов функций режима. При этом, конечно, теряется возможность досрочного переключения на другой режим, но если это оставить, это переключение будет происходить весьма странным образом (не говоря уже об угрозе переполнения стека).
    PS. Естественно, по хорошему логику программы следует серьезно изменить.
    От принудительного вызова loop следует избавиться вообще в любом случае.
    Если так нужно досрочное переключение режима и выполнение "кода в конце loop", то лучше подумать о другой логике работы программы.
     
    Последнее редактирование: 29 ноя 2014
    Alex19 нравится это.
  9. Alex19

    Alex19 Гуру

    Спасибо geher, Megakoteyka, за разъяснение. Мне надо глубже изучать мат. часть, чтобы лучше понимать нюансы.

    UPD. Боюсь, что я напугал &Anton, своим любопытством. Если Вы &Anton, что-то не понимаете спрашивайте.
     
    Последнее редактирование: 29 ноя 2014
  10. &Anton

    &Anton Нерд

    да мне кажется я ничего не понимаю ,
    решил переделать схемку ,сделал с 2-мя кнопками и не стал замарачиваться с аналоговым входом (пока еще трудно для меня ) . Нашел пример с меню но ничего не получилось
    Код (Text):
    const int moveUp = 7;
    const int moveDown = 5;
    const int sensUp =  3;
    const int sensDown =  4;
    const int sensStartUp =  8;
    const int buttonMenu = 6 ;





    int regim=1;
    int flag=0;
    int buttonStateUp = 0;
    int buttonStateDown = 0;

    unsigned long regim1WorkTime = 300000;
    unsigned long regime2WorkTime = 600000;
    unsigned long regime3WorkTime = 900000;



    void setup()
                      {
                          pinMode(moveUp, OUTPUT);
                          pinMode(moveDown, OUTPUT);
                          pinMode(sensUp, INPUT);
                          pinMode(sensDown, INPUT);
                          pinMode(sensStartUp, INPUT);
                          pinMode(buttonMenu, INPUT);

                      }

    void loop()

        {
         
                if(buttonMenu==HIGH&&flag==0)//если кнопка нажата  и перемення flag равна 0 , то ...
       
                      {
                          regim++;  //это нужно для того что бы с каждым нажатием кнопки
                          flag=1;    //происходило только одно действие
                                      // плюс защита от "дребезга"  100%
         
             
                          if(regim>3)//ограничим количество режимов
                                {
                                      regim=1;//так как мы используем только одну кнопку, то переключать режимы будем циклично
                       
         
                                }
         
                        if(digitalRead(14)==LOW&&flag==1)//если кнопка НЕ нажата  и переменная flag равна - 1 ,то ...
       
                                {
             
                                      flag=0;//обнуляем переменную "knopka"
                                  }
                      }
         
         
                                          if(regim==1)//первый режим
                                                      {
                                                          if (millis() > regim1WorkTime)
                                                             
                                                                {
                                                           
                                                                  flag=0;
                                                                }
                                                           
                                                                  buttonStateUp = digitalRead(sensStartUp);
                                                                  buttonStateUp = digitalRead(sensUp);
                                                                  buttonStateDown = digitalRead(sensDown);
                                                                  if (buttonStateUp != buttonStateDown){
                                                                  digitalWrite(moveUp, buttonStateUp);
                                                                  digitalWrite(moveDown, buttonStateDown);
                                                                }
           
         
                                                      }
                                          if(regim==2)//второй режим
                                                      {
                                                        if (millis() > regim1WorkTime)
                                                             
                                                                {
                                                           
                                                                  flag=0;
                                                                }
                                                       
                                                                  buttonStateUp = digitalRead(sensStartUp);
                                                                  buttonStateUp = digitalRead(sensUp);
                                                                  buttonStateDown = digitalRead(sensDown);
                                                                  if (buttonStateUp != buttonStateDown){
                                                                  digitalWrite(moveUp, buttonStateUp);
                                                                  digitalWrite(moveDown, buttonStateDown);
                                                                }
           
         
                                                      }
         
                                        if(regim==3)//третий режим
                                                      {
                                                        if (millis() > regim1WorkTime)
                                                             
                                                                {
                                                           
                                                                  flag=0;
                                                                }
                                                                  buttonStateUp = digitalRead(sensStartUp);
                                                                  buttonStateUp = digitalRead(sensUp);
                                                                  buttonStateDown = digitalRead(sensDown);
                                                                  if (buttonStateUp != buttonStateDown){
                                                                  digitalWrite(moveUp, buttonStateUp);
                                                                  digitalWrite(moveDown, buttonStateDown);
                                                              }
           
         
                                                      }
         
                                     
    }
    Ну тоесть вверх-вниз моторчик двигается но не срабатывает вот эта часть кода
    Код (Text):
    buttonStateUp = digitalRead(sensStartUp);
    То есть при нажатии кнопки старт мотор не включается , а только после того как я кратковременно замыкаю один из контактов

    Код (Text):
    const int sensUp =  3;
    const int sensDown =  4;
     
  11. Alex19

    Alex19 Гуру

    Все мы учимся... Пока просто запомните, что вызывать loop не стоит. Не из других функций, никак.

    Попробую быстро пояснить. При запуске ардуины, стартует функция setup, после нее запускается loop. Особенность loop, заключается в том, что после того как в ней все выполнено, она запускается снова. По сути, функция loop крутится в бесконечном цикле. Это 2 обязательные функции.

    Если Вы будете вызывать функцию loop, в другой функции, кроме проблем с переполнением стека. О которой досконально еще не знаю, говорить не буду. Вы еще получите код, с блоками, которые ни когда не будут выполнены. Пример выше http://forum.amperka.ru/threads/Оброботка-кнопки.3983/#post-31448 смотрите после UPD.

    Если коротко получите не стабильную работу, да еще и с местами кода, которые ни когда не будут выполнены.

    По поводу
    int не может содержать значения больше 32767.

    Теперь по новому коду, разумеется он не работает
    Код (Text):
     if(buttonMenu==HIGH&&flag==0)
    Вы понимаете, что сравниваете константу buttonMenu равную 8 с HIGH.
    Это условие ни когда не будет выполнено.

    Если нужно проверить кнопку, которая подключена к пину (ножке) 8, которую мы записали в константу buttonMenu, то условие должно выглядеть так
    Код (Text):
    if(digitalRead(buttonMenu)==HIGH&&flag==0)
    Для чего вообще мы используем константы, что бы просто при необходимости при изменении пина (ножки), поменять номер в одном месте. Поэтому if(digitalRead(14)==LOW&&flag==1), лучше добавить константу вверху.

    Судя по всему if(digitalRead(14)==LOW&&flag==1) должна определять,
    если кнопка уже не нажата, после того как был установлен флаг. Поэтому этому блоку там не место, как и цифре 14
    Код (Text):

        if(digitalRead(buttonMenu)==HIGH&&flag==0)//если кнопка нажата  и перемення flag равна 0 , то ...
        {
            regim++;  //это нужно для того что бы с каждым нажатием кнопки
            flag=1;    //происходило только одно действие
            // плюс защита от "дребезга"  100%


            if(regim>3)//ограничим количество режимов
            {
                regim=1;//так как мы используем только одну кнопку, то переключать режимы будем циклично
            }
        }

        if(digitalRead(buttonMenu)==LOW&&flag==1)//если кнопка НЕ нажата  и переменная flag равна - 1 ,то ...
        {
            flag=0;//обнуляем переменную "knopka"
        }
    Теперь про это блок кода

    Код (Text):

            if (millis() > regim1WorkTime)
            {
                flag=0;
            }
    millis() - Возвращает количество миллисекунд (0,001с) с момента начала выполнения текущей программы на плате Arduino. Это количество сбрасывается на ноль, в следствие переполнения значения, приблизительно через 50 дней.

    То есть, после определенного времени, эта проверка if (millis() > regim1WorkTime) будет бессмысленна, в данном случае после 300 секунд со времени старта, regim1WorkTime равна 300000.

    Дальше не смотрел. При всем уважении, Вы пытаетесь без базовых знаний взять код и модернизировать его под себя. Увы, так не получится, разбираться в чужом коде сложнее, чем писать с нуля.

    Может получится, только если найденный пример будет точно соответствовать Вашим требованиям.
    Поэтому рекомендую начать с азов http://wiki.amperka.ru/, посмотреть переведенную документацию http://arduino.ru/Reference. Может, кто нибудь порекомендует хорошую книгу.
    Начинал уже со знанием программирования (писал для себя), поэтому, могу ошибиться с книгой для начинающих.

    Удачи в изучении!
    Там все намного проще, чем Вы думаете.
    Но как и везде, надо идти шаг за шагом.
     
    Последнее редактирование: 29 ноя 2014
    &Anton и Megakoteyka нравится это.
  12. &Anton

    &Anton Нерд

    Большое всем спасибо за объяснение , много нового для себя узнал .
    Буду начинать с азов .Единственное вы часто напоминаете о переполнение стека , подскажите где можно
    " разжованно " почитать .
     
  13. Megakoteyka

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