Arduino Micro: кнопки ввода не работают!

Я понятия не имею, почему это происходит со мной, но кнопки (в данном случае buttonAbort и buttonStage) вообще не работают.

Изменить: Обычно светодиоды располагаются прямо рядом с кнопкой (например, ledStage -> размещается рядом с buttonStage), они начинают мигать, когда таймер достигает нуля, издается звуковой сигнал, и если пользователь нажимает одну из кнопок, звуковой сигнал останавливается, и светодиод, расположенный рядом с нажатой кнопкой, включается, а другой выключается. Кнопки тоже подключил без резисторов. (непосредственно к контактам)

/*
   Jebediah's Launch Control System for Kerbal Space Program
   Alpha Build 2.00
   An Open-Source Project by John Seong
*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 3;

const int buzzer = A3;
const int ledAbort = 5;
const int ledStage = A5;
const int buttonAbort = 4;
const int buttonStage = A4;

char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[ROWS] = {12, 11, 10, 9};
byte colPins[COLS] = {8, 7, 6};

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// Показать двухстрочное сообщение на ЖК-дисплее.
void lcdShow(const char *line0, const char *line1) {
  lcd.clear();
  lcd.print(line0);
  lcd.setCursor(0, 1);
  lcd.print(line1);
}

void lcdShowResult(float result) {
  lcd.print(result);
}

void setup() {
  pinMode(buzzer, OUTPUT);
  pinMode(ledAbort, OUTPUT);
  pinMode(ledStage, OUTPUT);
  pinMode(buttonAbort, INPUT_PULLUP);
  pinMode(buttonStage, INPUT_PULLUP);

  Serial.begin(9600);
  lcd.begin(16, 2);
  while (!keypad.getKey()) ;  // ждем нажатия клавиши
}

void loop() {
  static enum {START, MENU, SET_COUNT, COUNT_DOWN, LAUNCH, SET_THRUST, SET_WEIGHT} state = START;
  static uint32_t last_second;  // значение millis() за последнюю полную секунду
  static int count;
  static float thrust, weight, ratio;

  int stageConfirm = digitalRead(buttonStage);
  int abortConfirm = digitalRead(buttonAbort);

  char key = keypad.getKey();

  switch (state) {
    case START:  // переходное состояние
      lcdShow("1. LAUNCH SEQ", "2. TWR CALC");
      state = MENU;
    /* fallthrough */

    case MENU:
      if (key == '1') {  // Обратный отсчет
        lcdShow("COUNTDOWN TIMER", "SECONDS: ");
        count = 0;
        state = SET_COUNT;
      } else if (key == '2') {  // TWR
        lcdShow("TWR CALCULATOR", "THRUST: ");
        thrust = 0, weight = 0, ratio = 0;
        state = SET_THRUST;
      }
      break;


    case SET_COUNT:
      if (key >= '0' && key <= '9' && count <= 99) {
        lcd.print(key);
        count = 10 * count + (key - '0');
      } else if (key == '#') {
        lcdShow("    T-MINUS", "     SECONDS");
        // Принудительное обновление при вводе COUNT_DOWN:
        last_second = millis() - 1000;
        count++;
        state = COUNT_DOWN;
      } else if (key == '*') {
        state = START;
      }
      break;

    case COUNT_DOWN:
      if (millis() - last_second >= 1000) {
        last_second += 1000;
        count--;
        if (count <= 10) {
          tone(buzzer, 500);
          delay(500);
          noTone(buzzer);
        }
        if (count == 0) {
          Serial.println("Lift off!");
        } else if (count < 0) {
          state = LAUNCH;
          break;
        }
        lcd.setCursor(1, 1);
        lcd.print(count < 10 ? "  " : count < 100 ? " " : ""); // накладка
        lcd.print(count);
      } else if (key == '*') {
        state = START;
      }
      break;

    case LAUNCH:
      tone(buzzer, 3000);
      digitalWrite(ledAbort, HIGH);
      digitalWrite(ledStage, HIGH);
      lcdShow(" T-ZERO WARNING", "CONFIRM IGNITION");
      delay(1000);
      lcd.clear();
      digitalWrite(ledAbort, LOW);
      digitalWrite(ledStage, LOW);
      delay(500);

      stageConfirm = digitalRead(buttonStage);
      abortConfirm = digitalRead(buttonAbort);
      
      if (stageConfirm == LOW) {
        noTone(buzzer);
        digitalWrite(ledStage, HIGH);
        digitalWrite(ledAbort, LOW);
        lcdShow("  LIFT OFF", "HAVE A SAFE FLIGHT");
        break;
        
      } else if (abortConfirm == LOW) {

        break;
      }
      Serial.println(stageConfirm);
      Serial.println(abortConfirm);

      break;

    case SET_THRUST:
      if (key >= '0' && key <= '9' && thrust <= 9999) {
        lcd.print(key);
        thrust = 10 * thrust + (key - '0');
      } else if (key == '#') {
        lcdShow("TWR CALCULATOR", "WEIGHT: ");
        state = SET_WEIGHT;
      } else if (key == '*') {
        state = START;
      }
      break;

    case SET_WEIGHT:
      if (key >= '0' && key <= '9' && weight <= 9999) {
        lcd.print(key);
        weight = 10 * weight + (key - '0');
      } else if (key == '#') {
        lcdShow("THRUST-TO-WEIGHT", "RATIO: ");
        if (thrust != 0 || weight != 0) {
          ratio = thrust / weight;
          lcdShowResult(ratio);
        }
      } else if (key == '*') {
        state = START;
      }
      break;
  }
}

, 👍1

Обсуждение

Попробуйте распечатать значения stageConfirm и abortConfirm сразу после того, как вы прочитаете кнопки, и посмотрите, читаются ли они так, как вы думаете. Ваша логика в ваших операторах if кажется мне странной, если кнопка stageConfirm не нажата ИЛИ если кнопка отмены нажата, скажите: «Счастливого полета». Мне кажется, что нажатие кнопки прерывания не должно приводить к взлету., @Delta_G

Покажи и свою проводку., @Delta_G

Музыка с комментариями /* ... */ отвлекает. Почему ты его хранишь? Не могли бы вы создать копию своей программы и удалить все, что не связано с проблемой кнопки, например, заставку LCD в setup(). Это тоже помогло бы., @Thomas Weller

О, это должно быть &&, а не ||. Извините за путаницу!, @John Seong

вы должны объяснить, что вы ожидаете от кнопок, @jsotola

если buttonStage == 1 -> ledStage = 1, ledAbort = 0, @John Seong

если buttonAbort == 1 -> ledStage = 0, ledAbort = 1, @John Seong

В основном светодиоды располагаются рядом с кнопкой (например, ledStage -> помещаются рядом с buttonStage), они начинают мигать, когда таймер достигает нуля с помощью зуммера, и если пользователь нажимает одну из кнопок, звук зуммера прекращается. и светодиод, расположенный рядом с нажатой кнопкой, включается, а другой выключается., @John Seong


1 ответ


Лучший ответ:

0

Этот код считывает кнопки в двух местах в loop(), но первый раз результаты игнорируются. Только показания, сделанные в LAUNCH состояние может иметь любые последствия. Проблема в том, что чтение выполняется только в одно очень определенное время, через 1,5 секунды после отображения «ПОДТВЕРДИТЬ ЗАЖИГАНИЕ". Если вы нажмете кнопку до или после этого момента, она никакого эффекта.

Чтение только один раз за итерацию цикла допустимо, если цикл достаточно быстро, не застревая в delay(). Как общее правило, вы стараетесь избегать delay() всякий раз, когда хотите написать программу, которая должен реагировать на внешние события, такие как нажатия кнопок. См. Ардуино пример Мигайте без промедления, чтобы узнать, как это сделать. А Конечный автомат — хороший способ программировать без задержек. к счастью, вы уже работаете с одним из них. Чтобы обнаружить нажатие кнопки, обычно вы используете два разных состояния:

  • состояние ожидания нажатия кнопки, зависящее от нажатия кнопки
  • состояние «кнопка нажата», которое достигается, когда пользователь нажимает кнопку.

Состояний «нажата кнопка» может быть несколько, если их несколько. кнопки ждать. Переход из состояния «ожидание» в другие затем зависят от нажатия кнопки:

case WAIT_FOR_BUTTON_PRESS:
    if (digitalRead(button_1_pin) == LOW) {
        do_the_action_relevant_to_button_1();
        state = BUTTON_1_HAS_BEEN_PRESSED;
    } else if (digitalRead(button_2_pin) == LOW) {
        do_the_action_relevant_to_button_2();
        state = BUTTON_2_HAS_BEEN_PRESSED;
    }
    break;

Очевидно, что вы бы выбрали названия штатов, которые больше подходят для вашего конкретный проект.

,