while(Serial.available()==0) {} loop falls through

Hello,
I'm using while(Serial.available()==0) {} to allow input from console to program via "Serial monitor".
Platform is a MEGA2560 R3. The while loop works fine for stepping through a menu and a "switch_case".
It also works fine as a pause. In other words it cycles until I input something and send from the Serial Monitor. But then it falls through the next 2 instances without pausing and goes back to the calling function which is loop(). If anyone has any ideas as to what is going on, I would really appreciate
something to fix this glitch.
Thanks.

void calc_n()
{
  Serial.println("\nEnter first ...");
  Serial.print("V1 = ");
  while(Serial.available()==0) {}
  V1 = Serial.parseInt();
  Serial.println(V1);

  Serial.println("\nEnter second ...");
  Serial.print("V2 = ");
  while(Serial.available()==0) {}
  V2 = Serial.parseInt();
  Serial.println(V2);

  Serial.println("\nEnter first ...");
  Serial.print("V3 = ");
  while(Serial.available()==0) {}
  V3 = Serial.parseInt();
  Serial.println(V3);

  Serial.println("\nEnter second ...");
  Serial.print("V4 = ");
  while(Serial.available()==0) {}
  V4 = Serial.parseInt();
  Serial.println(V4);

  Serial.println("\nEnter ...");
  Serial.print("r1 = ");
  while(Serial.available()==0) {}
  r1 = Serial.parseInt()*3;
  Serial.println(r1);

  Serial.println("\nEnter ...");
  Serial.print("r2 = ");
  while(Serial.available()==0) {}
  r2 = Serial.parseInt()*3;
  Serial.println(r2);

  Serial.println("\nEnter ...");
  Serial.print("r3 = ");
  while(Serial.available()==0) {}
  r3 = Serial.parseInt()*3;
  Serial.println(r3);

  Serial.println("\nEnter ...");
  Serial.print("r4 = ");
  while(Serial.available()==0) {}
  r4 = Serial.parseInt()*3;
  Serial.println(r4);
  while(Serial.available()==0) {} // pause to copy numbers
  
// OK to here -- falls through the next *while* loops

  F1 = ((V1+V2)/(V1-V2)) * ((r2-r1)/2);
  Serial.print("\nF1 = ");
  Serial.println(F1);
  
  F2 = ((V3+V4)/(V3-V4)) * ((r4-r3)/2);
  Serial.print("F2 = ");
  Serial.println(F2);
  while(Serial.available()==0) {}  // falls through

  Serial.print("\nAverage (rAvg1) = ");
  rAvg1 = (((r2-r1)/2)+r1);
  Serial.println(rAvg1);
  
  Serial.print("Average (rAvg2) = ");  
  rAvg2 = (((r4-r3)/2)+r3);
  Serial.println(rAvg2);
  while(Serial.available()==0) {}  // falls through 

  n=((F1-F2) / (rAvg2-rAvg1));
  Serial.print("\nn = ");
  Serial.print(n,3);
}

How is your Serial Monitor set? Does it automatically append CR and LF ? Those are two characters.

1 Like

Hi ieee, thanks for the response. My SM is set with "no line ending".

1oldfox:
Hi ieee, thanks for the response. My SM is set with "no line ending".

You haven't posted your entire code, so not sure how anyone can debug.

There is lots more code. I don't understand what part of the code you would need. This is a function, not a snipet. The entire program is not what you could call "open source".

Can you share exactly what you type, how you enter the data, from which serial input and what the console exactly prints?

What I Suspect is as follow

while(Serial.available()==0) {} // pause to copy numbers
// OK to here -- falls through the next *while* loops

I suspect you type something here to go thru and As you don't read the buffer, the next time you call available() there is still something in there that you did not empty and thus it goes thru.

Would be interesting also depending on your input to know how you set up timeout

J-M-L Let me put together some stuff and we will see what else you may need. I'll work on it and send it in a later post. Thanks.

I'm 99,9% sure that you problem is that you have a pause "to copy numbers",as you call it, so you type something to continue and that something stays in the buffer as you don't empty it and thus your code just zooms thru the next available() calls.

J-M-L

Can you share exactly what you type, how you enter the data, from which serial input and what the console exactly prints?

OK. Here's enough code to see exactly what is working and how the calc_n function doesn't work.

The, for example, '//enter 300' comments are the numbers you enter from the keyboard into the Serial
Monitor.

Try it out, option "3" first and then "6".

At the last line in the monitor "F1 = 435.00". you can go for a cup of coffee and when you return that line will
still be the last line in the monitor. Hit 0 (zero) or any other char and then hit enter. That will drive the
while loop false and then move on until the next while "pause" loop.

Now compare that "calcF1" function with the "calc_n" function and you will see what I mean by "pausing" or
falling through. Trust me this is the easiest way to explain it.

int Vm;
int V1; 
int V2;
int V3;
int V4;
int r1;
int r2;
int r3;
int r4;

float rAvg1;
float rAvg2;
float D;
float Fm;
float Fa;
float F1;
float F2;
float n;
float R;

int choice;

float vInput;
int vTable[10]; 
int v;
float totV;
float avgV;

int i;

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

void loop()
{
  Serial.println("\n      Choose\n");
//  Serial.println("1 = Calculate AV");
//  Serial.println("2 = Calculate Ar");
  Serial.println("3 = Calculate F1");
//  Serial.println("4 = Calculate F2");
//  Serial.println("5 = Calculate Fm");  
  Serial.println("6 = Calculate n");
//  Serial.println("7 = Calculate Fa");
//  Serial.println("8 = Calculate BD\n");  
  while(Serial.available()==0) {}
  choice = Serial.parseInt();
  switch(choice)
    {
/*      case 1:
        calcAV();
      break;
      case 2:
        calcAr();
        break;
*/      case 3:
        calcF1();
        break;
/*      case 4:
        calcF2();
        break;        
      case 5:
        calcFm();
        break;
*/      case 6:
        calc_n();
        break;
/*      case 7:
        calcFa();
      break;
      case 8:
        calcBD();
      break;
*/  }
}

void calcF1()  F1 = ((V1+V2)/(V1-V2)) * (r2-r1)/2)
{
  Serial.println("\nEnter ...");    //enter 300
  Serial.print("V1 = ");
  while(Serial.available()==0) {}
  V1 = Serial.parseInt();
  Serial.println(V1);

  Serial.println("\nEnter ...");    //enter 280
  Serial.print("V2 = ");
  while(Serial.available()==0) {}
  V2 = Serial.parseInt();
  Serial.println(V2);

  Serial.println("\nEnter ...");    //enter 0
  Serial.print("r1 = ");
  while(Serial.available()==0) {}
  r1 = Serial.parseInt()*3;
  Serial.println(r1);

  Serial.println("\nEnter ...");    //enter 30
  Serial.print("r2 = ");
  while(Serial.available()==0) {}
  r2 = Serial.parseInt()*3;
  Serial.println(r2);

  F1 = ((V1+V2)/(V1-V2)) * ((r2-r1)/2);
  Serial.print("\nF1 = ");
  Serial.println(F1);
  while(Serial.available()==0) {}  
}

void calc_n()  // n=((F1-F2) / (rAvg1-rAvg2))
{
  Serial.println("\nEnter ...");    //enter 300
  Serial.print("V1 = ");
  while(Serial.available()==0) {}
  V1 = Serial.parseInt();
  Serial.println(V1);

  Serial.println("\nEnter ...");    //enter 280
  Serial.print("V2 = ");
  while(Serial.available()==0) {}
  V2 = Serial.parseInt();
  Serial.println(V2);

  Serial.println("\nEnter ...");    //enter 230
  Serial.print("V3 = ");
  while(Serial.available()==0) {}
  V3 = Serial.parseInt();
  Serial.println(V3);

  Serial.println("\nEnter ...");    //enter 210
  Serial.print("V4 = ");
  while(Serial.available()==0) {}
  V4 = Serial.parseInt();
  Serial.println(V4);

  Serial.println("\nEnter ...");    //enter 0
  Serial.print("r1 = ");
  while(Serial.available()==0) {}
  r1 = Serial.parseInt()*3;
  Serial.println(r1);

  Serial.println("\nEnter ...");    //enter 10
  Serial.print("r2 = ");
  while(Serial.available()==0) {}
  r2 = Serial.parseInt()*3;
  Serial.println(r2);

  Serial.println("\nEnter ...");    //enter 70
  Serial.print("r3 = ");
  while(Serial.available()==0) {}
  r3 = Serial.parseInt()*3;
  Serial.println(r3);

  Serial.println("\nEnter ...");    //enter 80
  Serial.print("r4 = ");
  while(Serial.available()==0) {}
  r4 = Serial.parseInt()*3;
  Serial.println(r4);
  while(Serial.available()==0) {} // pause to copy numbers onto R card

  F1 = ((V1+V2)/(V1-V2)) * ((r2-r1)/2);
  Serial.print("\nF1 = ");
  Serial.println(F1);
  F2 = ((V3+V4)/(V3-V4)) * ((r4-r3)/2);
  Serial.print("F2 = ");
  Serial.println(F2);
  while(Serial.available()==0) {}  

  Serial.print("\nAvg r... = ");
  rAvg1 = (((r2-r1)/2)+r1);
  Serial.println(rAvg1);
  Serial.print("Avg r... = ");  
  rAvg2 = (((r4-r3)/2)+r3);
  Serial.println(rAvg2);
  while(Serial.available()==0) {}  

  n=((F1-F2) / (rAvg2-rAvg1));
  Serial.print("\nn = ");
  Serial.print(n,3);
  while(Serial.available()==0) {}  
}

Hopefully you can figure this out. I have removed a lot and commented out a lot that have no bearing on
this particular problem.

Thanks

I'm 99,9% sure that you problem is that you have a pause "to copy numbers",as you call it, so you type something to continue and that something stays in the buffer as you don't empty it and thus your code just zooms thru the next available() calls.

The "to copy numbers" means to write them down with pencil and paper. No computer entries whatsover. Just a char and "enter" to make while false and move on.

The funny thing is that it all works up to a point. and then fails and I always use "0+enter" as the
trigger, so to speak.

At the last line in the monitor "F1 = 435.00". you can go for a cup of coffee and when you return that line will
still be the last line in the monitor. Hit 0 (zero) or any other char and then hit enter. That will drive the
while loop false and then move on until the next while "pause" loop.

Well what do you think happens to your 0+enter? Your char '0' stays in the buffer because you don't read it out. So the next call to availabel() returns a positive number and thus you don't wait.

If you want your code to work, just ensure you read everything out of the input buffer once available() said something was there. Once the serial buffer is empty, then proceed.

Well what do you think happen to your 0+enter?

And therein lies the problem. I wasn't even thinking about that 0 that I was stuffing into the buffer. I was just
thinking about that error that pops up if you hit "send" with an empty buffer. Now the entire sketch works
as I intended. Just put a "Serial.parseInt() after each while that I didn't read and that was that.

Thanks a million, J. I learned something new today, from you. This old grey matter just gets hung up on one
thing sometimes an then I really do need to back off and have another cup of coffee.

Thanks again. Onward and upwards.

Good!!!

A suggestion don't use Serial.parseInt() after each while - that kinda works because you type a zero but that function will wait until it completed reading a full int - which happens if it can read something that looks like an int (you zero) and then another char that is not a number arrives. As you just type 1 char and nothing that looks like the end of an int, the function call will wait until timeout which is set by default to 1 second => so that slows down your user interface and your program will wait 1 sec after you press enter before continuing.

What I suggest when you just want to wait and don't care about what is being typed in, is doing another loop with while something is in serial.available then read it with a serial.read. Once this is done then your program will continue - so instead of waiting for a 1s timeout you will just have a few microseconds after you typed zero+enter for your program to continue its execution

  while(Serial.available()==0) {}; // wait for 1 keypress
  while(Serial.available() > 0) {Serial.read()}; // we had at least 1 char, empty the buffer from all input
 // here we are good to go with an empty buffer and we did not wait for any timeout

Hope this helps

1 Like

Thanks J. And yes, that helps a lot. I'm still learning the capabilities of the Arduino language. There
have been numerous times in the past when I just used a delay() to pause. Honestly I struggled a little with the possibilities of conditions with a while loop. It never did become intuitive. Your example really
opened my eyes and laid it out, real clear, for me. I hope other folks read this post. I think it would be
helpful for many folks struggling with the same problem.

Thanks again and have a nice 4th.

@1oldfox, have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

There is also a simple user input function in Planning and Implementing a Program

...R

Robin, thanks. Good stuff. I browsed through both of them. That's a lot of stuff. I'll read and learn all
of it during my next coffee break. :grinning:

Thanks again.

How does parseInt() interact with end-of-line markers? Maybe that's why the next ones are falling though - the peek at but don't consume the \n, \r, or \r\n .

@paulMurray

indeed that would be an issue as well in the general case but 1oldfox mentioned above:

Hi ieee, thanks for the response. My SM is set with "no line ending".

so he does not generate any extra characters.