Interpreting a number from the Serial Monitor

I am trying to read and store an integer input from the serial monitor in the range 0-15. However, I also want to account for garbage/unexpected input. Ex.) "zxcvb7bvc" will return an invalid input message, not the number 7. How can this be done?

I have tried using Serial.parseInt(), but this function seems to print any number that it can decipher from the serial monitor. I have also tried using the isDigit() function, but have not had any luck. Any help would be great thanks!

Where is the garbage coming from? Why not cure the garbage problem instead of trying to read through it?

I suggest you read Robin2's excellent serial input basics tutorial and see if that helps you https://forum.arduino.cc/index.php?topic=396450.0

You say you have tried to do this, you are more likely to get help if you post your best attempt and ask for help with the bit you are struggling with.

groundFungus:
Where is the garbage coming from? Why not cure the garbage problem instead of trying to read through it?

The garbage is just from the user input. I can make the program work with just expected inputs in the range (0-15) but I am trying to account for mistakes, like if the user enters "1wr5" on accident I do not want my code to see "15".

isDigit() is useful.

My tutorial Text I/O for the Real World covers this sort of problem.
It uses my SafeString library available from the library manager. There is a detailed tutorial here
SafeString includes a robust method for parsing integers.
See this part of the tutorial and the example file included with the library SafeStringToNum.ino
e.g.

#include "SafeString.h"
createSafeString(str, 20); // a SafeString object 
 . . .
  str = "5a";
  Serial.print(F("SafeString version.  str.toLong(l_num); "));
  if (str.toLong(l_num)) {
    Serial.print(F("returns true, l_num set to "));
    Serial.println(l_num);
  } else {
    Serial.println(F(" returns false, not a valid integer. l_num unchanged."));
  }

which return false.

For reading the input you can use the SafeString non-blocking reader that can return ‘words’ delimited by your choice of delimiters, eg. space comma newline CR etc
see SafeString tutorial User Commands Example
A complete example is

// install SafeString from the library manager or from
// www.forward.com.au/pfod/ArduinoProgramming/SafeString/index.html
#include "SafeStringReader.h"

createSafeStringReader(sfReader, 15, " ,\r\n"); // create the non-blocking SafeStringReader sfReader and its supporting buffers 
// to handle cmds upto 15 chars long delimited by space, comma, Carrage return or Newline

void setup() {
  Serial.begin(9600);
  for (int i = 10; i > 0; i--) { // pause a little to give you time to open the Arduino monitor
    Serial.print(i); Serial.print(' '); delay(500);
  }
  Serial.println();
  SafeString::setOutput(Serial); // enable error messages and SafeString.debug() output to be sent to Serial
  sfReader.connect(Serial); // where SafeStringReader will read from
  sfReader.echoOn(); // echo back all input, by default echo is off
//  sfReader.setTimeout(2000); // optionally set a non-blocking read timeout
  Serial.println(F("Enter integer in range 0-15"));
}
int number = 0;
bool validNumber = false;

void loop() {
  
  if (sfReader.read()) {
    // got a 'word'
    if (sfReader.toInt(number)) {
      Serial.print("got a valid number:");Serial.println(number);
      if ((number < 0) || (number > 15)) {
        Serial.println(" number out of range");
      } else {
        validNumber = true;
      }
    } else {
      Serial.print("'"); Serial.print(sfReader); Serial.println("' is not a valid number");
    }
  } // else no delimited command yet

  if (validNumber) {
    // do stuff
  }
  // rest of code here is executed while the user typing in commands
}

Output: (with echoOn)

Enter integer in range 0-15
fj 'fj' is not a valid number
jf 'jf' is not a valid number
kd
'kd' is not a valid number
22 got a valid number:22
 number out of range
a
'a' is not a valid number
 5b
'5b' is not a valid number
4.
'4.' is not a valid number
 10
got a valid number:10
1lw5
'1lw5' is not a valid number

One very successful approach is to train the user to not supply garbage.

"Sorry, try again" is a valid computer response to garbage input.

This is analogous to a recycling problem. It is easy to separate paper, plastic and metal. But it is very difficult to separate good plastic from bad. How do you know a good number that is input from a bad number? So, like jremington suggests, make the user responsible for the separation (correct input).

Here is a version using Arduino Strings

String input;
size_t maxInputLen = 15;
void setup() {
  Serial.begin(9600);
  for (int i = 10; i > 0; i--) { // pause a little to give you time to open the Arduino monitor
    Serial.print(i); Serial.print(' '); delay(500);
  }
  Serial.println();
  Serial.println(F("Enter integer in range 0-15"));
  input.reserve(maxInputLen); // to prevent fragmentation
}
int number;
bool validNumber;

bool parseInput(String &input) {
  // this is the tricky part because toInt in not robust
  input.trim(); // remove white space leading and trailing
  Serial.print(F("parse:'")); Serial.print(input); Serial.print(F("'"));
  if ((!isDigit(input[0])) && (input[0] != '-')) { // this handle empty string also input[0] of empty string returns '\0'
    Serial.println(F(" does not start with digit"));
    return false;
  }
  int tempNumber = input.toInt();
  String testNum = String(tempNumber);
  if (input != testNum) {
    Serial.println(F(" has extra chars"));
    return false;
  }
  if ((tempNumber < 0) || (tempNumber > 15)) {
    Serial.println(F(" number out of range"));
    return false;    
  }
  number = tempNumber; // got valid one update global
  return true;
}
bool readNumber() {
  if (Serial.available()) {
    char c = Serial.read();
    if ((c == ' ') || (c == ',') || (c == '\n') || (c == '\r')) {
      bool rtn = parseInput(input);
      input = ""; // clear for next time
      return rtn;
    } // else
    input += c;
    if (input.length() >= maxInputLen) {
      input = ""; // discard very long words
    }
    return false;
  }
  return false;
}

void loop() {
  validNumber = readNumber();
  if (validNumber) {
    Serial.print(F(" go valid number ")); Serial.println(number);
    // so stuff
    validNumber = false; // have handle this one
  }
}

output

Enter integer in range 0-15
parse:'' does not start with digit
parse:'8' go valid number 8
parse:'-5' number out of range
parse:'5a' has extra chars
parse:'a5' does not start with digit
parse:'3.' has extra chars

Avoid using low-level c-string methods as they are very prone to coding errors.
see “Secure Coding in C and C++”, chapter 5 and chapter 2

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.