Arduino Serial Monitor inputting random 0's and not waiting for user input

I am in the process of trying to write a calculator code. The code waits for the Serial monitor to be ready (through Serial.available) and then it runs through its if statements. It parses the user's first number, the second number (which is used to determine the operation) and the third number. It will then print the answer on the Serial Monitor. I have the Serial Monitor currently echoing back the values you entered for the first number, operator, and the final number for debugging purposes. This code works if you type if fast enough. However, once you get the code going, if you don't enter the numbers fast enough the Serial Monitor grabs a value of 0 from somewhere and stores that value for whatever step you were on. I have tried changing the the if statement to blank while statements, I have tried using a do-while statement, I have tried changing the bottom settings in the serial monitor, and I have tried writing in Serial.available after each step however none of these methods have fixed the problem. What am I doing wrong?? I have attached my code. (The Serial.println("ERROR!!") section is also there just for debugging)

/* Use a variable called byteRead to temporarily store
the data coming from the computer /
//void(
resetFunc)(void) = 0;

enum mathOperation {
NONE,
Add,
Subtract,
Multiply,
Divide
};
int byteRead;
int byteRead2;
int i = 0;
int op = 0;
int answer;
int test;
mathOperation _mathOperation = NONE;

void setup() {
// Turn the Serial Protocol ON
Serial.begin(9600);
}

void loop() {

if (Serial.available() == 1){
if (i == 0){
byteRead = Serial.parseInt();
Serial.println(byteRead);
i++;
}

else if (i == 1) {
op = Serial.parseInt();
if(op == 1){
_mathOperation = mathOperation::Add;
Serial.println(_mathOperation);
i++;
}
if(op == 2){
_mathOperation = Subtract;
Serial.println(op);
i++;
}
if(op == 3){
_mathOperation = Multiply;
Serial.println(op);
i++;
}
if(op == 4){
_mathOperation = Divide;
Serial.println(op);
i++;
}
}
else if (i == 2){
byteRead2 = Serial.parseInt();
if(byteRead2 == 0)
Serial.println("ERROR!!!!!!!");
Serial.println(byteRead2);
i++;
}

else if (i == 3){
if(_mathOperation == Add){
answer= byteRead + byteRead2;
Serial.println(answer);
i++;
}
else if(_mathOperation == Subtract){
answer= byteRead - byteRead2;
Serial.println(answer);
i++;
}
else if (_mathOperation == Multiply){
answer= byteRead * byteRead2;
Serial.println(answer);
i++;
}
else if (_mathOperation == Divide){
answer = byteRead / byteRead2;
Serial.println(answer);
i++;
}
}
}
}

SerialFinalCalc.ino (1.68 KB)

I think that you will find that Serial.parseInt() returns a zero if a timeout (default 1 second) occurs before a character terminating a number is received.

Solution : don't use Serial.parseInt()

Why not wait for more data?
if (Serial.available() == 1){
Or don't start anything until you see a newline or carriage return, or both if that is what your serial monitor is set to?
(see the little box at the bottom right of the serial monitor - I've hosed myself like that before)

Why are you using a type (byte) in the name of a variable that is NOT of that type?

Why are you storing the long that the stupidly named toInt() method returns in an int?

ElleB:
I am in the process of trying to write a calculator code.

What's this going to become, actually?

A "math expression evaluator", where you can send a math expressions as input from Serial and the sketch evaluates and sends some answer to the Serial monitor?
Integer math only? or floating point math?

What do you expect as an answer to the expression "(1+2++3+4)/3="?

Would the exprected answer be "3 and remainder 1? Or something like" 3.33333"?

Or do you just want to do basic math operations at the level of elementary school, like "number operator number and then see the result as an int, with no brackets or chain calculations in the math expression?

  if (Serial.available() == 1)

is completely fragile - your program will simply hang forever if more than one character gets
into the serial buffer.

Use this:

  if (Serial.available () > 0)

Maybe have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example.

...R

Thank you all so much for your suggestions! I have messed around with the if statement attached to Serial.available already and it hasn't seemed to fix the problem. This is a very very basic calculator in that it does either addition, subtraction, multiplication, or division between two SINGLE integer numbers. Messing with the newline and no line settings in the bottom changes the error but still leaves an error. If no line is selected, the program won't grab random 0s but it won't output the answer until another number(what would become the first number in the second calculation) is entered. If newline is used, then the solution outputs when it is supposed to but the 0s are grabbed if the numbers aren't entered very quickly.

If newline is used, then the solution outputs when it is supposed to but the 0s are grabbed if the numbers aren't entered very quickly.

THAT is avoidable. Don't all parseInt() if there is no serial data to read.

Post the code you are currently having issues with.

I believe I got the code to work on the Arduino end. I used the no line ending setting in the serial monitor and took the portion of the code that printed the solution out of the check Serial available loop. This allowed the code to print the solution without waiting for another number to be entered. I would still like to figure out if there is a way to use the newline setting without it grabbing 0s though for future reference! Current code that worked on Arduino end:

/* Use a variable called byteRead to temporarily store
the data coming from the computer /
//void(
resetFunc)(void) = 0;

enum mathOperation {
NONE,
Add,
Subtract,
Multiply,
Divide
};
int byteRead;
int byteRead2;
int i = 0;
int op = 0;
int answer;
int test;
mathOperation _mathOperation = NONE;

void setup() {
// Turn the Serial Protocol ON
Serial.begin(9600);
}

void loop() {

if (Serial.available() == 1){
if (i == 0){
byteRead = Serial.parseInt();
//Serial.println(byteRead);
i++;
}

else if (i == 1) {
op = Serial.parseInt();
if(op == 1){
_mathOperation = mathOperation::Add;
//Serial.println(_mathOperation);
i++;
}
if(op == 2){
_mathOperation = Subtract;
//Serial.println(op);
i++;
}
if(op == 3){
_mathOperation = Multiply;
//Serial.println(op);
i++;
}
if(op == 4){
_mathOperation = Divide;
//Serial.println(op);
i++;
}
}
else if (i == 2){
byteRead2 = Serial.parseInt();
//Serial.println(byteRead2);
i++;
}
}
else if (i == 3){
if(_mathOperation == Add){
answer= byteRead + byteRead2;
Serial.println(answer);
i++;
}
else if(_mathOperation == Subtract){
answer= byteRead - byteRead2;
Serial.println(answer);
i++;
}
else if (_mathOperation == Multiply){
answer= byteRead * byteRead2;
Serial.println(answer);
i++;
}
else if (_mathOperation == Divide){
answer = byteRead / byteRead2;
Serial.println(answer);
i++;
}
}
else if(i == 4){
i = 0;
}
}

You have not addressed any of the issues that have been brought up so far. Why should we continue to try to help you?

int byteRead;

byteRead is a stupid name for a variable who's type is int.

if (Serial.available() == 1){

Why do you do nothing if there is 0 bytes to read AND if there are two or more?

if(Serial.available() > 0) is a MUCH more robust solution!

I have changed the int value name and I have switched the if statement. The new if statement causes issues with entering the numbers. I think the big issue lies in what parseInt() is looking for. How it handles newline characters and how long it waits before it generates a 0.

I have changed the int value name and I have switched the if statement.

But, no new code. :frowning:

The new if statement causes issues with entering the numbers. I think the big issue lies in what parseInt() is looking for. How it handles newline characters and how long it waits before it generates a 0.

Show us the input you are sending, and the output that the Arduino generates.

If you don't try to read before there is data to read, parseInt(), though unnecessary, IS well behaved.

By the way, a switch() on op would be much more readable.

   switch(op)
   {
       case 1:
         _mathOperation = Add;
         break;
       case 2:
         _mathOperation = Subtract;
         break;
       case 3:
         _mathOperation = Multiply;
         break;
       case 4:
         _mathOperation = Divide;
         break;
       deafult:
         i--;
   }
   i++;

Note that it is not necessary to increment i in each case. Decrement i if the operation is invalid (what does 6 mean?), so that the unconditional increment will simply put i back where it was.

With the no line ending setting selected in the serial monitor, the code below works. However when newline is selected thats when we get the 0s. I have attached the code and a screenshot of the 0s generated in newline serial monitor. The zeros seen are spit out after waiting about .5-1 second. The current code spits out the number you enter for num, then the value for op(which determines the math operator), and then the third number you enter(num2) along with the solution. So the zeros generated here were made because I didn't immediately input the value for the third number (num2). While the code works in the no line ending setting, I would like to find out how I could make it work in newline setting as well.

enum mathOperation {
NONE,
Add,
Subtract,
Multiply,
Divide
};
int num;
int num2;
int i = 0;
int op = 0;
int answer;
int test;
mathOperation _mathOperation = NONE;

void setup() {
// Turn the Serial Protocol ON
Serial.begin(9600);
}

void loop() {

if (Serial.available() == 1){
if (i == 0){
num = Serial.parseInt();
Serial.println(num);
i++;
}

else if (i == 1) {
op = Serial.parseInt();
if(op == 1){
_mathOperation = mathOperation::Add;
Serial.println(op);
i++;
}
if(op == 2){
_mathOperation = Subtract;
Serial.println(op);
i++;
}
if(op == 3){
_mathOperation = Multiply;
Serial.println(op);
i++;
}
if(op == 4){
_mathOperation = Divide;
Serial.println(op);
i++;
}
}
else if (i == 2){
num2 = Serial.parseInt();
Serial.println(num2);
i++;
}
}
else if (i == 3){
if(_mathOperation == Add){
answer= num + num2;
Serial.println(answer);
i++;
}
else if(_mathOperation == Subtract){
answer= num - num2;
Serial.println(answer);
i++;
}
else if (_mathOperation == Multiply){
answer= num * num2;
Serial.println(answer);
i++;
}
else if (_mathOperation == Divide){
answer = num / num2;
Serial.println(answer);
i++;
}
}
else if(i == 4){
i = 0;
}
}

if (Serial.available() == 1){

You said you fixed this. And, yet, here it is again.

I tried to fix it but it didn't work with the suggested change

ElleB:
I tried to fix it but it didn't work with the suggested change

Something happened. You did something, with some expectations that the code would do something. We have no idea what happened, what you did, or what you expected.

We are trying to help you, but you need to realize that we can NOT see what you see or what you do. Except that. I saw that.

Interesting observation in that the if statement change you suggested (if(serial.available() > 1) makes the newline setting work perfectly! It is the first screenshot I attached. However, if it is switched to no line ending, the outputs become skewed and don't match the values I enter. I tried to enter 1 and then a 1 and then other numbers. It printed the two ones as 11 and then never output anything else.

enum mathOperation {
NONE,
Add,
Subtract,
Multiply,
Divide
};
int num;
int num2;
int i = 0;
int op = 0;
int answer;
int test;
mathOperation _mathOperation = NONE;

void setup() {
// Turn the Serial Protocol ON
Serial.begin(9600);
}

void loop() {

if (Serial.available() > 1){
if (i == 0){
num = Serial.parseInt();
Serial.println(num);
i++;
}

else if (i == 1) {
op = Serial.parseInt();
if(op == 1){
_mathOperation = mathOperation::Add;
Serial.println(op);
i++;
}
if(op == 2){
_mathOperation = Subtract;
Serial.println(op);
i++;
}
if(op == 3){
_mathOperation = Multiply;
Serial.println(op);
i++;
}
if(op == 4){
_mathOperation = Divide;
Serial.println(op);
i++;
}
}
else if (i == 2){
num2 = Serial.parseInt();
Serial.println(num2);
i++;
}
}
else if (i == 3){
if(_mathOperation == Add){
answer= num + num2;
Serial.println(answer);
i++;
}
else if(_mathOperation == Subtract){
answer= num - num2;
Serial.println(answer);
i++;
}
else if (_mathOperation == Multiply){
answer= num * num2;
Serial.println(answer);
i++;
}
else if (_mathOperation == Divide){
answer = num / num2;
Serial.println(answer);
i++;
}
}
else if(i == 4){
i = 0;
}
}

Why are you using parseInt at all? You're reading in single digit numbers. Just read them with Serial.read() and subtract '0' to convert from ascii.

You should have a look at Serial Input Basics - updated - Introductory Tutorials - Arduino Forum

You could type 16+28 and hit send, with line ending set to something other than none, and then parse the string that was collected, without the need to use parseInt() or to send 1, 2, 3, or 4 to define how to process the two numbers.

You're reading in single digit numbers

I don't think that is the case. parseInt() handles more than single digit numbers. I saw nothing in OPs post that hints at a limitation to single digit numbers. I'll admit that I haven't read all of this thread completely, so I might have missed something.