Управление режимами одной кнопкой

Тема в разделе "Arduino & Shields", создана пользователем Old_School, 27 авг 2021.

  1. Old_School

    Old_School Нуб

    Здравствуйте! Мне понадобилось запустить моторчик от cd дисковода, для этого купил драйвер a4988 и ардуино нано. Поскольку я сам не особо разбираюсь в программировании, посмотрел несколько статьей в интернете и написал такой код:
    Код (C++):
       int step = 4;
      int dir = 5;
      int en = 6;
     
      int wait;
     
      int val;
      int c;
      int state;

      boolean down = true;
      boolean up = true;


    void setup() {
      pinMode(step, OUTPUT);
      pinMode(dir, OUTPUT);
      pinMode(en, OUTPUT);
      pinMode(7, INPUT_PULLUP);

      digitalWrite(en, HIGH);
    }




    void loop() {
    wait=20;

       state = digitalRead(7);

       if (digitalRead(state) == HIGH && c == 0) {
        c = 1;
       }
       if (digitalRead(state) == LOW && c == 1)
       {
          val == ++val;
          if (val == 2)
          {
            val = 0;
          }
          c = 0;
       }
       if (val == 0)
       {
        digitalWrite(en, HIGH);
       }
       if (val == 1)
       {
        digitalWrite(en, LOW);
        digitalWrite(dir, LOW);
        for(int i=0; i<2600; i++){
          digitalWrite(step, HIGH);
          delayMicroseconds(wait);
          digitalWrite(step, LOW);
          delayMicroseconds(wait);
          }
        digitalWrite(en, HIGH);
       }

     
       if (val == 2)
       {
       digitalWrite(en, LOW);
       digitalWrite(dir, HIGH);
       for(int i=0; i<2800; i++){
          digitalWrite(step, HIGH);
          delayMicroseconds(wait);
          digitalWrite(step, LOW);
          delayMicroseconds(wait);
          }
        digitalWrite(en, HIGH);
       }
    }
    Смысл заключается в том что когда схема просто запитана то на выход en подаётся 1 дабы отключить выходные масфеты драйвера, что бы просто так не грел мотор блокировкой. После того как будет нажата первый раз кнопка он должен подать 0 на en и 0 на dir, потом сделать 2600 импульсов со скоростью 10мс на step, после чего опять подать 1 на en. Когда кнопка будет нажата 2 раз: на en 0 а на dir 1 и потом 2800 импульсов.
    Проблема заключается в том что почему-то после 2600 импульсов он запускает этот же цикл заново и как я понимаю, из-за этого он не переключается на 3 режим.
    Есть какие нибудь мысли почему так происходит и как от это решить?
     
  2. Asper Daffy

    Asper Daffy Иксперд

    lool вызывается постоянно. Как только закончится, вызывается снова. Вот он отработал, val осталось 1, он вызывается снова и, поскольку val равно 1 снова отрабатывает то же самое и так бесконечно.
     
  3. Old_School

    Old_School Нуб

    И как в такой ситуации быть?
     
  4. Asper Daffy

    Asper Daffy Иксперд

    Правильно писать.

    Вы попытались реализовать автомат с состояниями "начальное (val==0)", "делаем 2600 шагов (val==1)" и "делаем 2800 шагов (val==2)". Но у Вас нет состояния "ждём нажатия кнопки". Оно бы выручило.

    Ну, кроме того, специфика модели программирования с функциями setup / loop не предполагает наличия каких-либо циклов в самом loop (а у Вас их два). Как только Вы пихаете цикл внутрь loop, знайте, Вы что-то делаете неправильно и это будет потом источником проблем.

    Каких проблем? Ну, например, Вы подумаете и решите развить свою задачу так: если в процессе "2600 шагов" поступило новое нажатие кнопки, бросаем этот режим (не доходя до конца) и сразу переключаемся на режим "2800 шагов". Если бы программа была сделана правильно (без циклов в loop) сделать такую модификацию было бы легко, а так - гороху наедитесь добавляя проверку нажатия кнопки внутрь цикла.

    В общем, это не так пишется.
     
  5. SergeiL

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

    У вас в коде есть есть такие строчки:
    Код (C++):
         val == ++val;
          if (val == 2)
          {
            val = 0;
          }
    а дальше:
    Код (C++):
       if (val == 2)
       {
       digitalWrite(en, LOW);
       digitalWrite(dir, HIGH);
       for(int i=0; i<2800; i++){
    ............................
    То есть, вы увеличиваете val проверяете, если она равна "2" то сразу скидываете ее в 0, а дальше ниже еще раз проверяете не равна ли она "2".
    А она уже сброшена в "0"
    По этой причине вы в это условие уже не попадаете.
    Уберите первую проверку val совсем, а val = 0; перенесите во вторую.

    Строчка val == ++val; у вас работает, но не так как вы думаете.
    Да, val увеличивается на 1,
    но первая часть "val ==" не имеет смысла. "==" - это оператор сравнения.

    Вместо val == ++val; нужно:
    Код (C++):
    ++val;
    или
    val++;
    или
    val=val+1;
    Ну и инициализация переменных.
    Всегда инициализируйте переменные независимо от их типа и места хранения, это поможет избежать мучительного поиска ошибок в случае их изменения.
    Сделали вы переменную вместо глобальной - локальной, а проинициализировать забыли. И все, ищите, что происходит, почему она не "0".