Go Down

Topic: while(Serial.available()==0) {} loop falls through (Read 14464 times) previous topic - next topic

1oldfox

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.

Code: [Select]
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);
}
If it ain't broke, fix it 'til it is!

ieee488

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


1oldfox

Hi ieee, thanks for the response. My SM is set with "no line ending".
If it ain't broke, fix it 'til it is!

ieee488


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.


1oldfox

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".
If it ain't broke, fix it 'til it is!

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?

What I Suspect is as follow

Code: [Select]

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
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

1oldfox

>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.
If it ain't broke, fix it 'til it is!

J-M-L

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.
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

1oldfox

> J-M-L
Quote
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.

Code: [Select]


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;
*/  }
}


*****************************************************************
Code: [Select]


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) {}  
}


*************************************************************
Code: [Select]


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
If it ain't broke, fix it 'til it is!

1oldfox

Quote
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.
If it ain't broke, fix it 'til it is!

J-M-L

Quote
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.
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

1oldfox

Quote
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.
If it ain't broke, fix it 'til it is!

J-M-L

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
Code: [Select]

  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
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

1oldfox

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.
If it ain't broke, fix it 'til it is!

Robin2

@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

Two or three hours spent thinking and reading documentation solves most programming problems.

Go Up