Скрипт должен ждать второго нажатия кнопки

СергМен

✩✩✩✩✩✩✩
16 Мар 2021
2
0
Доброго времени суток, уважаемые форумчане. Прошу помощи с решением задачи.
Алгоритм скрипта ниже задумывался таким:
1. на проходе цикла n-раз, сгенерировать переменную.
1.1 поместить ее в массив
1.2 подать высокий сигнал на соответствующий пин.
2. считать нажатие кнопки
2.1 если номер кнопки соответствует цифре в массиве, увеличить n на 1 и т.д.
2.2 если n больше 2, после нажатия 1й кнопки и верного сравнения с записью в массиве, ждать нажатие второй кнопки и сравнить её с соответствующей ячейкой в массиве, после чего увеличить n на 1.
На деле выходит, что после первого нажатия кнопки, скрипт не ждет второго нажатия а сразу считает что была нажата эта же кнопка, что автоматически сбрасывает n на 1
в Wokwi скрипт работает как надо, там и писался, на плате, увы нет.
C++:
int lastButton = 0;
int key() {
  int val = analogRead(5);
  if (val != lastButton) {
    delay(10);  // Ждем пока состояние стабилизируется - игнорируем дребезг
    int val = analogRead(5);
  }
  if (val < 50) return 3;
  else if (val < 513) return 4;
  else if (val < 683) return 5;
  else if (val < 768) return 6;
  else if (val < 819) return 7;
  else if (val < 853) return 8;
  else if (val < 878) return 9;
  else if (val < 896) return 10;
  else if (val < 910) return 11;
  else if (val < 922) return 12;
  else if (val < 931) return 13;
  else if (val < 939) return 14;
  else return 0;
}  //int key()
int r, c, n, i, j, q, w, u, l, t, ww;
int arr[50];
long randNumber;
int game2() {
labelNO:
  for (q = 0; q < 10; q++) {  // Цикл1 Большой цикл
    n++;
    t = t - ((t / 100) * 5);  // t + 5%
    Serial.print("----------");
    Serial.print("n:");
    Serial.println(n);
    for (i = 0; i < n; i++) {  // Цикл2 Малый цикл
label:
      randNumber = random(3, 14);
      if (r == randNumber) {
        goto label;
      }
      r = randNumber;
      arr[i] = randNumber;
      digitalWrite(randNumber, HIGH);
      delay(t);
      digitalWrite(randNumber, LOW);
      Serial.print("randNumber:");
      Serial.println(randNumber);
    }
label2:
    for (w = 0; w < n; w++) {
      int k = arr[w];
      for (ww = 0; ww < 55555; ww++) {  // Цикл таймер
        if (k == key()) {
          Serial.println("OK");
          Serial.print("arr[w]: ");
          Serial.println(k);
          Serial.print("key(): ");
          Serial.println(key());
          digitalWrite(key(), HIGH);
          delay(50);
          digitalWrite(key(), LOW);
          break;
        } else if (key() != 0 && k != key()) {
          Serial.println("NO");
          Serial.print("arr[w]: ");
          Serial.println(k);
          Serial.print("key(): ");
          Serial.println(key());
          digitalWrite(key(), HIGH);
          delay(50);
          digitalWrite(key(), LOW);
          Serial.println(analogRead(0));
          n = 0;
          goto labelNO;
        }
      }  //for (ww
    }    //for (w
  }      //Цикл1 Большой цикл
}

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(17));
  n = 0;
  t = 500;
}
void loop() {
  game2();
}  //void loop()
 

bort707

★★★★★★✩
21 Сен 2020
3,040
908
Вот это вот - не антидребезг, а полная фигня.
C++:
if (val != lastButton) { 
  delay(10); // Ждем пока состояние стабилизируется - игнорируем дребезг
  int val = analogRead(5);
 }
Во-первых, оно не предотвращает чтение одной и той же кнопки несколько раз подряд(из-за чего у вас проблемы в коде)
А во-вторых, если кнопка сменилась - этот код ее не будет читать, пока не вылезет прежнее значение
 

VAF

✩✩✩✩✩✩✩
15 Июл 2023
48
1
Москва
Не увидел присвоение lastButton значения после нажатия на кнопку первый раз.
 

СергМен

✩✩✩✩✩✩✩
16 Мар 2021
2
0
@bort707,
"Во-первых, оно не предотвращает чтение одной и той же кнопки несколько раз подряд" - расскажите об этом подробнее пожалуйста или хотя бы ключи для поиска в Гугл накидайте плиз
"пока не вылезет прежнее значение" - это тоже
 

VAF

✩✩✩✩✩✩✩
15 Июл 2023
48
1
Москва
Проблема второго чтения кнопки при первом нажатии решается установкой паузы delay() или отслеживанием времени назначается переменная last, которой присваивается значение last=millis() при нажатии, а затем только if(millis()-last> задержки) можно проверять кнопку.
 

Nitrogenium

✩✩✩✩✩✩✩
25 Ноя 2022
27
2
Ну смотри...

Во-первых СергМен, тебе дяди с большими ушами не объясняли, что не нужно без самой крайней надобности использовать безусловны переход GOTO?
Если немного подумать,в 99% случаев можно обойтись без него.

Далее... Командой AnalogRead ты считываешь с 5 пина с помощью Аналагово-Цифрового преобразователя некоторое значение напряжения на данном пине.
Я сперва подумал у тебя там какой-то тензо датчик и типа от силы нажатия, делается return 6,7 и пр.
Если у тебя там тупо кнопка на 5 пине, то у тебя будет прилетать стабильно 1023

ватыкни в код, даже в пустой. Serial.println(analogRead(5)); и убедись в этом.

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

Либо используй уже готовые решения.
 
Изменено:

Сузунец

✩✩✩✩✩✩✩
19 Июн 2024
18
8
42
Сузун
Не стал разбираться во всех тонкостях исходника, не люблю я в чужом коде ковыряться...
Вот функция обработки нажатия кнопки, принимает в качестве аргумента номер пина, возвращает TRUE при нажатии:
C++:
#define BTN 2        // Кнопка

void setup() {
    pinMode(BTN, INPUT_PULLUP);
}

void loop() {
    static uint8_t state = 0;
    if (onClick(BTN)) state++;
    switch(state)
        {
        case 0:
            // что-то делаем (условие выполняется сразу т.к. state==0)
        break;
        case 1:
            // что-то делаем при нажатии кнопки
        break;
        case 2:
            // ...следующий режим (пауза)
            while(true) {
                if (onClick(BTN)) {
                    state++;
                    break;
                    }
                }
        break;
        case 3:
            // ...следующий режим
        break;
        default:
            state = 0; // ...начинаем с начала
        break;
        }
}
//---------------------------------------------------------------------------
// Функция обработки нажатия кнопок
bool onClick(uint8_t _pin) {
    static bool _flag;
    static uint32_t _tmr;
    bool btnState = digitalRead(_pin);

    // Программное устранение дребезга контактов
    if (!btnState && !_flag && millis() - _tmr >= 100) {
        _flag = true;
        _tmr = millis();
        return true;
        }
    if (btnState && _flag) {
        _flag = false;
        _tmr = millis();
        }
    return false;
};
...да, и пример использования для выполнения каких-то действий при каждом нажатии, пока они (действия) не закончаться, потом всё сначала...
 
Изменено:

Nitrogenium

✩✩✩✩✩✩✩
25 Ноя 2022
27
2
Не стал разбираться во всех тонкостях исходника, не люблю я в чужом коде ковыряться...
Да и них...я в нём не понимаю...

Пиши уж честно и до конца.

Конкретно об этом коде... Если микроконтроллер занимается исключительно тем, что крутит функцию
onClick и ожидает нажатия клавиши. Это будет работать.

Когда другого кода прибудет, обработка нажатия будет срабатывать иногда... иногда через раз...
Тут либо вешать нажатие на прерывание, либо....


Программное устранение дребезга контактов .

Ты попробуй в комментах к своему коду объяснить что ты фактически хочешь сделать!:)
 
Изменено: