Мой код Arduino не работает... и я просто не вижу никаких проблем... мысли?

Там Последнее обновление!

Так что я работаю над прилавком просто для удовольствия. Как это работает, когда вы нажимаете кнопку 1, светодиод загорается красным, раздается звуковой сигнал, и переменная "счетчик" добавляет одну к себе; После подсчета вы можете нажать кнопку 2, затем сначала отобразится анимация перехода, затем мигнет и подаст звуковой сигнал, убирая значение "счетчик". После того, как значение "счетчик" станет меньше 1, все начнется с самого начала.

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


Обратите внимание, что я использую обычный анодный RGB-светодиод, поэтому контакт анода всегда ВЫСОКИЙ, но чтобы осветить отдельные цвета, мне придется опустить контакты катода (помните, как текут электроны?)

Обновить Последний ответ @Тома Карпентера все еще не решил проблему. Я обнаружил, что функция "еще" внутри "если" вообще не работала. Поэтому, если я помещу код счетчика в функцию "еще", результат будет нулевым. Но если я помещу код счетчика в "если" внутри основного "если", он снова будет считать с тактовой частотой, что приведет к вечному миганию! Так есть ли в любом случае возможность, чтобы код учитывался только один раз за цикл печати и выпуска без потерь?

Последний код:


#define RLED 10
#define GLED 11
#define BLED 12

#define B1 4
#define B2 5

#define BZZ 3

boolean OB1V;

int counter;

void setup() {

  pinMode(RLED, OUTPUT);
  pinMode(GLED, OUTPUT);
  pinMode(BLED, OUTPUT);

  pinMode(B1, INPUT);
  pinMode(B2, INPUT);

  pinMode(BZZ, OUTPUT);

  OB1V = digitalRead(B1);
  
}

void loop() {

  digitalWrite(RLED, HIGH);
  digitalWrite(GLED, HIGH);
  digitalWrite(BLED, HIGH);

  boolean NB1V = digitalRead(B1);

  if (NB1V != OB1V)
    {
      digitalWrite(RLED, LOW);
      digitalWrite(BZZ, HIGH);
      counter = 0;
    }
  else
    {
      digitalWrite(RLED, HIGH);
      digitalWrite(BZZ, LOW);
      counter = counter +1;
    }
    
  if ( digitalRead(B2) == HIGH )
    {
      digitalWrite(GLED, LOW);
      delay(300);
      digitalWrite(GLED, HIGH);
      digitalWrite(RLED, LOW);
      delay(300);
      digitalWrite(RLED, HIGH);
      digitalWrite(GLED, LOW);
      delay(300);
      digitalWrite(GLED, HIGH);
      digitalWrite(BLED, LOW);
      delay(100);
      digitalWrite(BLED, HIGH);
      delay(300);

      for ( counter; counter >= 1; counter -- )
        {
          digitalWrite(GLED, LOW);
          digitalWrite(BZZ, HIGH);
          delay(200);
          digitalWrite(GLED, HIGH);
          digitalWrite(BZZ, LOW);
          delay(200);
        }
    }
}

, 👍-1

Обсуждение

Как подключены ваши кнопки? Обычно вы используете резистор и кнопку, переключающуюся на заземление, поэтому нажатие "низкое". Также ваш случай счетчика без задержки, вероятно, будет подвержен **отказу от контакта**, за исключением того факта, что "счетчик +1" на самом деле не учитывается, поскольку он не сохраняет результат добавления. Ваш другой путь с задержками может быть несколько невосприимчив к отскоку при нажатии, но может пострадать при отпускании, если пользователь не отпустит кнопку достаточно до окончания последовательности операций там., @Chris Stratton

`счетчик +1; " ничего не делает, как говорит Крис. В результате значение "счетчик" всегда равно 0, и поэтому цикл for никогда ничего не сделает (и, вероятно, будет удален компилятором как мертвый код). Если исправление строки приводит к нарушению чего-то еще, это означает, что что-то еще в коде нарушено., @Tom Carpenter

Попробуйте добавить "Serial.println(счетчик);" внутри операторов if, чтобы узнать значение счетчика при нажатии кнопок (также добавьте "Serial.begin (...)" в " setup ()", если вы добавляете операторы печати.)., @Tom Carpenter

Итак, как мне изменить значение "счетчик"? если я изменю "счетчик+1" выше на "счетчик = счетчик+1", в результате зеленый светодиод будет продолжать мигать, @Samm

Вы меняете его на " счетчик = счетчик + 1`, что необходимо для изменения значения счетчика. Затем вам нужно выяснить, что на самом деле заставляет зеленый светодиод продолжать мигать - печать отладочной информации на последовательный порт поможет вам в этом., @Tom Carpenter

Зеленый светодиод не является индикатором включения board..it это мой пользовательский индикатор и не показывает никакого состояния чипа. Поэтому я думаю, что проблема все равно будет заключаться в логике программы., @Samm

Что это делает? для ( счетчик; счетчик >= 1; счетчик--) "- имеет больше смысла инициализировать "счетчик" для чего-либо (первый элемент в цикле *для*). Например, для ( счетчик = 10; счетчик >= 1; счетчик -- )`, @Nick Gammon

Счетчик @Nick Gammon уже имеет значение раньше : - ) Посмотрите на первый прослушиватель кнопок., @Samm

В этом случае вы можете написать: "для ( ; счетчик >= 1; счетчик--)" - просто использование "счетчика" само по себе выглядит так, как будто вы что-то забыли, @Nick Gammon


2 ответа


1

С вашим кодом существует ряд проблем. Ваш код не связан с отпусканием кнопки. Как только вы нажмете B1 (при условии, что нажатие B1 приведет к увеличению ввода), счетчик (если он правильно реализован (то есть он должен быть counter++)) будет считать до 32 КБ, затем начнет с нуля и снова будет считать. Останавливается только тогда, когда вы отпускаете B1. Значение счетчика может быть любым числом от 0 до 32 КБ.

Работать с кнопками сложно. И конденсатор 100 Нф мало чем поможет. Было бы лучше, если бы вы научились отключать кнопки и относиться одинаково важно как к нажатию, так и к выпуску.

Существует библиотека Arduino под названием Bounce, которая сделает кое-что из этого за вас. Это не поможет с вашими логическими ошибками. Вам все равно нужно относиться к нажатию и отпусканию кнопки с одинаковой важностью. Но это поможет отменить нажатия кнопок, чтобы ваши результаты более точно соответствовали вашим ожиданиям.

добавлено позже...

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

,

колпачок действительно помогает, потому что я пытался печатать сообщения на последовательном мониторе с помощью кнопок "с колпачком" - идеально один результат при каждом нажатии. Также, чтобы справиться с освобождением, я поставил в конце функцию "еще", которая выключает светодиод и зуммер. Таким образом, он должен вызывать счетчик +1 (или счетчик ++, если хотите) каждый раз, когда я нажимаю кнопку, @Samm

@user56336 помните, что он находится в цикле. Вся функция loop() будет выполняться тысячи раз в секунду, поэтому, если вы не отпустите кнопку менее чем за миллисекунду, она будет повторно добавлять 1 к счетчику, пока кнопка не будет отпущена. Попробуйте добавить инструкцию по печати, которую я предложил, и вы это увидите., @Tom Carpenter

В большинстве случаев при использовании кнопки программное обеспечение отслеживает 4 состояния. 1) Кнопка отпущена и действие уже предпринято, 2) Кнопка нажата и действие еще не предпринято, 3) Кнопка нажата и действие уже предпринято и 4) Кнопка отпущена и действие еще не предпринято. Вам нужно отслеживать эти 4 состояния, если вы хотите подсчитывать по одному для каждого нажатия кнопки., @st2000

ну, что делает мой код, так это просто добавляет 1 к значению "счетчик" каждый раз, когда появляется ВЫСОКИЙ сигнал от контакта кнопки, пока не будет нажата вторая кнопка, он покажет результаты. Так что я не думаю, что мне придется выслушивать все четыре статуса. Проблема теперь в том, что после того, как я изменил "счетчик +1" выше на "счетчик = счетчик +1", чтобы сохранить результат, как указано выше, светодиод продолжает мигать, когда должен показывать результат. Так что, должно быть, что-то не так с добавлением или уменьшением., @Samm

Возможно, это было бы более очевидно в реальной среде C-кода, а не в среде Arduino. В реальном C вам пришлось бы нажать кнопку внутри бесконечного цикла. Потому что вы хотели бы использовать свою кнопку снова и снова. И не один раз. Находясь в бесконечном цикле, вы увидите, что при нажатии кнопки компьютер будет просто добавлять 1 к счетчику снова и снова так быстро, как только сможет. Сделайте это, добавив 1 к счетчику, распечатайте значение счетчика. Я думаю, что вы увидите, когда нажмете на кнопку, бесконечный поток "1", "2", "3", ..., @st2000

@ Том Карпентер, я думаю, ты прав. дай мне попробовать разобраться в этом, @Samm


1

Ваши проблемы сводятся к тому, что в первом коде вы пытаетесь делать что-то на уровне чувствительности, а не на уровне чувствительности.

Чтобы попытаться понять разницу, приведем несколько примеров. Чувствительность уровня эффективно:

Делай "x", пока "y"

Другими словами, если " y "истинно (например, входные данные высоки), продолжайте делать" x " (например, добавляя в счетчик). Это то, что ваш код делает в данный момент, но не то, что вы хотите, чтобы он делал.

С другой стороны, чувствительность к краям такова:

Сделайте "x", когда "y изменился"

Другими словами, когда состояние " y "меняется (например, с истинного на ложное), затем выполните "x" один раз.

Ключевое различие между ними заключается в различии между "пока" и "когда".


Итак, как вы повышаете чувствительность кода к краям?

То, как вы это сделали, требует, чтобы кнопка была высокой, а затем низкой в нужный момент, чтобы код поймал ее. Что произойдет, если кнопка опустится в конце цикла? Ваш код пропустит край, потому что в начале следующего цикла он невысок, поэтому не попадает в первый оператор if.

Давайте подумаем о том, что значит "изменения". Это означает, что текущее значение отличается от предыдущего значения. Это означает, что нам нужно отслеживать, каково предыдущее значение, чтобы сравнить его с текущим значением. На самом деле это именно то, что мы делаем:

boolean oldButtonValue; //Было бы лучше использовать статическую переменную в цикле, но для простоты примера давайте использовать глобальную.

void setup() {
    oldButtonValue = digitalRead(buttonPin); //Эта строка выполняется один раз для инициализации переменной.
}

void loop() {

    //Каждый цикл мы считываем наше текущее значение
    boolean newButtonValue = digitalRead(buttonPin);

    //Изменилось ли это?
    if (newButtonValue != oldButtonValue) {

        //Do something on edge.

    }

    //Обновить старое значение кнопки, чтобы оно соответствовало новому (чтобы мы могли проверить его снова в следующем цикле
    oldButtonValue = newButtonValue;
}

Что это делает, так это то, что каждый цикл сравнивает текущее состояние кнопки с ее состоянием из предыдущего цикла. Если значение меняется, оно что-то делает.


Теперь проблема с этим кодом в том, что он выполняется на любом краю. Это означает, что каждый раз, когда вы нажимаете кнопку, она будет запускаться дважды: один раз при нажатии и еще раз при отпускании. Поэтому давайте немного изменим его:

    ...

    //Изменилось ли это?
    if (newButtonValue != oldButtonValue) {

        //Was it a rising edge?
        if (newButtonValue) {
            //Если значение кнопки сейчас высокое, это, должно быть, был восходящий край
        } else {
            //В противном случае это был падающий край

        }
    }

    ...

Дополнительное сравнение позволяет нам определить, был ли это восходящий край или падающий край. Таким образом, теперь вы можете что-то делать либо при нажатии кнопки, либо при ее отпускании (или и то, и другое, если хотите).


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

,

я изменил свой код на этот: [ссылка](https://gist.github.com/MuSamDu/1873067bde0262359582eba5a686a995) Поскольку кнопка sencond всегда работает нормально, я не трогал этот фрагмент кода. Но то, что происходит сейчас, когда он должен был показать результаты, он ничего не показал! Что сейчас не так?, @Samm

@user56336 Попробуйте, и если это сработает, вот и все. Это выглядит в основном так же, как то, что я написал, только с гораздо более сложными именами переменных. За исключением того, что вам не хватает бита, в котором вы установили OB1V = NB1V; в конце цикла, что является несколько критической частью. И действительно, вы должны сделать то же самое с обеими кнопками, иначе у вас возникнет та же проблема со второй - она выполнит код несколько раз, если вы будете удерживать кнопку нажатой., @Tom Carpenter