Не удается получить ввод с клавиатуры 4x4

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

void loop(){
int a = getNumber();

if(a != NO_KEY){
    do{
    operationType = getOperationType();
    }while(!operationType);
  }

}

Получить номер

  int getNumber(){
  char userInput = customKeypad.getKey();
  int value;

  if (userInput == '0' || userInput == '1' || userInput == '2' || userInput == '3' || userInput == '4' || userInput == '5' || 
  userInput == '6' || userInput == '7' || userInput == '8' || userInput == '9'){
      value = userInput - '0';
      Serial.println("value");
      Serial.println(value);
      
    }
  return value;
  }

getOperationType getOperationType

char getOperationType(){
char userInput = customKeypad.getKey();
 

  switch (userInput){

      case '+':
//      add(a , b);
        Serial.println("add");
        break;
      case '-':
//      subtract(a , b);  
        Serial.println("subtract");  
        break;
      case '*':
//      multiply(a , b);
        Serial.println("multiply");
        break;
      case '/':
//      divide(a , b);
        Serial.println("Divide");
        break;  
      case 'C':
//      TODO
        break;
    }
    return userInput;
  } 

Могу ли я получить какой-нибудь намек на то, почему я не могу просто получать простые вводы с клавиатуры?

, 👍-1

Обсуждение

логика вашей программы предполагает, что ваша программа ожидает нажатия клавиши .... сократите свой код до "получить нажатие клавиши, напечатать значение нажатия клавиши`... это покажет вам, с чем вы имеете дело, @jsotola


1 ответ


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

1

Вам нужно следить за тем, что вы возвращаете, и инициализированы ли ваши переменные. Итак, что здесь происходит:

В loop() вы вызываете getNumber(). Там вы объявляете две переменные:

  • userInput, который вы инициализируете возвращаемым значением customKeypad.getKey(). Таким образом, эта переменная будет иметь значение NO_KEY, если ни одна клавиша не нажата.
  • значение, которое вы не инициализируете. Таким образом, его значение равно тому, что было в пространстве памяти переменных до того, как оно было выделено. Это может быть что угодно, но в большинстве случаев это не случайно. Это зависит от того, что ваша программа делала до этого, но у вас нет никакого контроля над этим.

Затем вы проверяете, является ли userInput цифрой ASCII. Поскольку вы не нажимали клавишу, это, очевидно, равно false, поэтому значение переменной никогда не записывается. А затем вы возвращаете эту переменную.

В loop() вы проверяете, не равно ли возвращаемое значение getNumber() NO_KEY. И поскольку вы не инициализировали значение, вероятно, так оно и есть. Таким образом, программа переходит непосредственно к части типа операции.


Что же теперь делать?

Первое: всегда инициализируйте каждую переменную, которую вы объявляете в функции. Глобальные переменные инициализируются неявно, но не локальные переменные. Чтобы быть уверенным, что я не совершу ошибку, я просто всегда инициализирую ВСЕ свои переменные при их объявлении.

Во-вторых: текущее значение не будет равно NO_KEY, поскольку вы не присваиваете это значение переменной. Но это не соответствовало бы логике вашей программы. значение - это реальное числовое значение, а не его представление в формате ASCI. И NO_KEY определяется в библиотеке клавиатуры как \0 (нулевой символ с числовым значением ноль). Таким образом, NO_KEY на самом деле равно 0. И ноль также является допустимым вводом для вашего калькулятора.

Вместо этого я бы предложил вернуть значение -1, если ни одна клавиша не была нажата, а затем в loop() проверить это. Итак, что-то вроде этого:

int getNumber(){
  char userInput = customKeypad.getKey();
  int value;

  if (userInput == '0' || userInput == '1' || userInput == '2' || userInput == '3' || userInput == '4' || userInput == '5' || userInput == '6' || userInput == '7' || userInput == '8' || userInput == '9'){
    value = userInput - '0';
    Serial.println("value");
    Serial.println(value);    
  } else {
    return -1;
  }
  return value;
}

void loop(){
  int a = getNumber();

  if(a != -1){
    do{
      operationType = getOperationType();
    }while(!operationType);
  }
}

Тем не менее, у меня есть несколько предложений для вас, чтобы пойти дальше:

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

      if(isDigit(userInput))
    
  • Если вы продолжите в этом стиле, вы обнаружите, что оборачиваете несколько циклов друг в друга, так как вам нужно выполнить цикл для ожидания нажатия клавиши. Это может стать довольно запутанным, и будет сложно добавить дополнительные функциональные возможности. Вместо этого вы могли бы реализовать конечный автомат (FSM). Здесь код в loop() состоит в основном из структуры switch case , где каждый case - это одно состояние вашей программы. Например, у вас могут быть состояния NUMBER1_INPUT, OPERATION_INPUT, NUMBER2_INPUT, DISPLAY_RESULT. Структура коммутатора использует единственную переменную int в качестве маркера состояния. Например, когда вы устанавливаете для этой переменной состояния значение NUMBER1_INPUT, она останется там и будет зацикливаться. Когда пользователь выполнит ввод числа, вы можете изменить переменную состояния на OPERATION_INPUT и позволить ей продолжаться там. Это важная концепция, и она изменит ваш способ кодирования Arduino к лучшему.

    Существует множество ресурсов для изучения того, как программировать FSM. Я когда-то писал более длинный ответ на этотвопрос, но вы можете поискать что-то вроде "Конечного автомата" на этом сайте или в Интернете, чтобы узнать больше.

,

Большое вам спасибо за такое объяснение. Я посмотрю на ваш ответ о FSM. Я действительно ценю ваши усилия., @user851242