Simple Math Sketch Adding Unwanted Data

Hi There,

I've done a simple sketch where if you enter a single digit in the serial monitor, it multiplies that number by 2. Here is the code:

int number;

void setup()
{
Serial.begin(9600);
}

void loop()
{
number = 0;
Serial.flush();
while (Serial.available() == 0)
{
//??
}
while (Serial.available() > 0)
{
number = Serial.read() - '0'; //read the number in the serial buffer and remove ASCII text offset for zero: '0'
}
Serial.print("You entered: ");
Serial.println(number);
Serial.print(number);
Serial.print(" multiplied by two is ");
number = number * 2;
Serial.println(number);

}

However, whatever number I enter, it also adds the line: You entered: -38
-38 multiplied by two is -76

So it looks like this:

You entered: 2
2 multiplied by two is 4
You entered: -38
-38 multiplied by two is -76

It's the same every time, no matter what number 0-9 I enter. I have two controllers and tried it on both with the same result. Anybody have any ideas? Thanks in advance.

When you enter a digit like '3' on serial monitor and press Send, two characters are sent to the Arduino: the '3' character and then the ENTER character, which is either ASCII code 10 or 13, I can't remember. So when the ENTER character is received, your code subtracts the ASCII code for '0' and that gives a negative number.

PaulRB:
When you enter a digit like '3' on serial monitor and press enter, two characters are sent to the Arduino: the '3' character and then the ENTER character, which is either ASCII code 10 or 13, I can't remember. So when the ENTER character is received, your code subtracts the ASCII code for '0' and that gives a negative number.

Well '0' is 0x30 or 48 decimal.

You may be entering a return or linefeed character. Check how you have the serial monitor set up.

Good programming practice suggests that your program should not assume that the character entered is a digit 0-9.

An easy way to check for digits is included in the Arduino language: isDigit()

I appreciate all the feedback. But I'm still pretty new and from the responses, I'm not sure what I'm doing wrong, or at least not doing right. As for the serial monitor settings, they seem pretty limited, unless there are hidden settings that I don't know about.

Doing a bit of digging around, it does seem that the monitor is reading enter as a character/number, whether I use the return key or Send button.

BobbyKay:
whether I use the return key or Send button.

Because they are identical.

The "Enter" key is the "Send" button. The serial monitor gives you options as to what is added to the line you have typed when you issue the "Send" command. If you do not want to send a newline/ CR, just select "no line ending". In which case you cannot issue a newline (or perhaps can using the control key :grinning: ).

At the lower right hand corner of the serial monitor window are three pull down menu boxes. The leftmost one is for setting the line endings which are sent along with what is typed in the top input box. The line endings have ascii values which are being read by your code.

Thanks, cattledog. I don't know how I missed that but it fixed the problem.

BobbyKay:
Hi There,

I've done a simple sketch where if you enter a single digit in the serial monitor, it multiplies that number by 2. Here is the code:

You are supposed to do this with code, as told in the read me before posting thread at the top of the forum.
Here's the address to cut&paste:
https://forum.arduino.cc/index.php?topic=148996.0

int number;

void setup()
{
  Serial.begin(9600);
}

void loop() 
{
  number = 0;
  Serial.flush();
  while (Serial.available() == 0)
  {
    //??
  }
  while (Serial.available() > 0)
  {
    number = Serial.read() - '0'; //read the number in the serial buffer and remove ASCII text offset for zero: '0'
  }
  Serial.print("You entered: ");
  Serial.println(number);
  Serial.print(number);
  Serial.print(" multiplied by two is ");
  number = number * 2;
  Serial.println(number);

}

Nick Gammon has a state machine tutorial about 1/3rd down the page here: Gammon Forum : Electronics : Microprocessors : How to process incoming serial data without blocking
There is a lot of explanation on the site, line-by-line of the code below.

This code reads letter-number combination commands and only accepts valid input. It does that without blocking or buffering.

// Example state machine reading serial input
// Author: Nick Gammon
// Date: 17 December 2011

// the possible states of the state-machine
typedef enum {  NONE, GOT_R, GOT_S, GOT_G } states;

// current state-machine state
states state = NONE;
// current partial number
unsigned int currentValue;

void setup ()
{
  Serial.begin (115200);
  state = NONE;
}  // end of setup

void processRPM (const unsigned int value)
{
  // do something with RPM 
  Serial.print ("RPM = ");
  Serial.println (value);
} // end of processRPM

void processSpeed (const unsigned int value)
{
  // do something with speed 
  Serial.print ("Speed = ");
  Serial.println (value);
} // end of processSpeed

void processGear (const unsigned int value)
{
  // do something with gear 
  Serial.print ("Gear = ");
  Serial.println (value);  
} // end of processGear

void handlePreviousState ()
{
  switch (state)
  {
  case GOT_R:
    processRPM (currentValue);
    break;
  case GOT_S:
    processSpeed (currentValue);
    break;
  case GOT_G:
    processGear (currentValue);
    break;
  }  // end of switch  

  currentValue = 0; 
}  // end of handlePreviousState

void processIncomingByte (const byte c)
{
  if (isdigit (c))
  {
    currentValue *= 10;
    currentValue += c - '0';
  }  // end of digit
  else 
  {

    // The end of the number signals a state change
    handlePreviousState ();

    // set the new state, if we recognize it
    switch (c)
    {
    case 'R':
      state = GOT_R;
      break;
    case 'S':
      state = GOT_S;
      break;
    case 'G':
      state = GOT_G;
      break;
    default:
      state = NONE;
      break;
    }  // end of switch on incoming byte
  } // end of not digit  
  
} // end of processIncomingByte

void loop ()
{
  while (Serial.available ())
    processIncomingByte (Serial.read ());

  // do other stuff in loop as required
  
}  // end of loop

This is where it evaluates numbers:

void processIncomingByte (const byte c)
{
  if (isdigit (c))
  {
    currentValue *= 10;
    currentValue += c - '0';
  }  // end of digit
  else 
  {

You can use it, just figure out the else part that fits your need.

Do you ignore letters or count them as errors?

How do you handle errors? How well do you treat the user?

Input routines that catch errors and let the user take up from just before the bad key was hit save time re-typing what was good. I got appreciation for doing that back when the software was as primitive as the 8-bit bus hardware. It beat the make em type the whole thing then beep+error message and prompt for that whole entry again over 1 mistype default method.

Thanks. I'll have a look at that tutorial and post my code properly going forward.