Go Down

Topic: How to remain inside a function? (Read 1 time) previous topic - next topic

Lsnyman

I need some assistance to understand structuring my own functions. I can create a function and call the function based on a decision in the void loop() but why does the program return to the loop afterward?
How do I structure it to just remain within the function once it has branched there. I know it sounds silly with this example but basically my application makes a decison between 2 different sets of data to execute based on the initial value of the analog input. Once that decison is made it should remain within the function. So in my example code I branch to option 1 which is executed and I would never expect the Serial.println ("Why?")  statement to be executed but it is.
Can someone explain why and tell me the correct way to structure this?

the output is -
Why?
0
1
2
3
Why?
0
1
2
3
Why?
0
1
2
3
Why?


Code: [Select]

int i = 1;
//==========================================================================================================//
void setup()
{
  Serial.begin(9600);
   }
//================================================================================================//
// Decision between option1 & option2
void loop()

   if (i = 1){
   option1();
          } 

   else if (i = 2){
     option2();
    }
  Serial.println("Why?");
}
//===============================================================================================================================================//
void option1()
{
      for (int i=0; i <= 3; i++){
     
      Serial.println(i);
      delay(200);
        }
}

//============================================================================================//
void option2()
{
      for (int i=10; i <= 13; i++){
   
      Serial.println(i);
      delay(200);
        }

Arrch

That's just how structured programming was designed. If you want to stay inside the loop forever, then encapsalate the code within the function in a while (1) { } although I can't imagine their are many circumstances where that's actually what is wanted.

Code: [Select]
if (i = 1){
Not how you write an if statement.
= is assignment
== is equivalence

Dyslexicbloke

#2
Oct 11, 2012, 05:50 am Last Edit: Oct 11, 2012, 05:57 am by Dyslexicbloke Reason: 1
Since you are obviously new to all this, we've all been there, you might like to draw a flow chart .... It will help you visualise what you want to do.

I don't understand why you would want to pick a loop and stay there either but if that is what you need then while is the simplest construct
Have a look at the reference section ...
http://arduino.cc/en/Reference/While
Code: [Select]

void loop()
while(i = 1){
  // statement(s)
}
while(i = 2){
  // statement(s)
}
Serial.println("Why?");
}

If i is not 1 or 2 you will continually print why.
if i is 1 or 2 you will continually loop through the code in one of the while loops.

In the  Arduino IDE ...
void Setup() always runs first, but only once.
then
void loop() is called and any code within it is executed sequentially, when you reach the bottom it simply starts again, no matter how long or short it is
(within constraints of time and available memory)

If you call a function from anywhere, including the main loop, the code in it will run and when its done the control is passed back to the line immediately below the function call in the original code, a bit like a detour off the path to visit something on one side.

You are going to need to read up on some basics to get a feel for things.
I hope I have given you somewhere to start
If I knew where the box was I would probably still want to think outside it!

Feel free to be blunt ... Its how I learn.

Nick Gammon

Code: [Select]

while(i = 1){
  // statement(s)
}


Should be:

Code: [Select]

while(i == 1){
  // statement(s)
}


Ditto to the OP.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Lsnyman

Thank you for the replies. Using the While statement works well. The actual issue i am having is with Arduino Leonardo. My original code runs without problems on the UNO, because the Uno resets when you connect to USB and that allows my sketch to do the analogRead and make the decision between the 2 loops. However the Leonardo does not reset. So I have been trying to troubleshoot it and wanted to make sure of the structure to use function calls.
I have followed the getting started guide for Leonardo and it says I can use the  while (!Serial) ;
statement to do nothing until a serial connection is made. This works when I structure it like the below but somehow when I apply it to my original code, the program just continues to execute even if the Serial Monitor is closed. This means i miss the calibration step in the beginning analogRead.
Sorry, I know it is confusing.
Code: [Select]
int i = 1;
//==========================================================================================================//
void setup()
{
  Serial.begin(9600);
  while (!Serial) ;
   }
//================================================================================================//
// Decision between option1 & option2
void loop()

   if (i == 1){
           Serial.println("Option 1"); 
   option1();

     } 

   else if (i = 2){
          Serial.println("Option 2");
     option2();

    }
  Serial.println("Why?");
}
//===============================================================================================================================================//
void option1()
{
while (i==1){     
  for (int i=0; i <= 3; i++){
     
      Serial.println(i);
      delay(200);
        }}
}

//============================================================================================//
void option2()
{
      for (int i=10; i <= 13; i++){
   
      Serial.println(i);
      delay(200);
        }
}

Dyslexicbloke

Oooops silly error ... Told you I was new at this, thanks for the correction.
If I knew where the box was I would probably still want to think outside it!

Feel free to be blunt ... Its how I learn.

Lsnyman

Ok I think I found my problem. I have a while (millis() < 80000) statement in each of my branch functions  as usually this is the time for the initial calibration of my sensor. I measure the minimum and maximum value of my sensor in this time. Obviously by the time the serial connection is made with the Leonardo the millis is already counting down.
I will have to find another way to delay the calibration feature. This sensor has no buttons or switches that i can use as it just operates when you plug in the USB.

AWOL

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

PaulS

Code: [Select]
int i = 1;
while (i==1){     
  for (int i=0; i <= 3; i++){
      Serial.println(i);

Which i are you printing? The global one or the local one?

See why using local and global variables with the same name is not a good idea? See why using one letter global names is not a good idea?

Unless this is a just a dummy program to illustrate a problem, I can't see how it is useful. There is no way to ever get back to the loop() function.

Lsnyman

Hi Paul
Yes this was indeed just a dummy to show the branch requirement, that is why it did not matter about the variable, I just assigned it to a fixed value to see the result of branching without having to use the analog input for decision.
The reason I never need to get back to the main loop is that the application is a sensor that has 2 different data sets depending on the initial startup condition. So if the sensor value is X at startup the program should go to Branch 1 and if it is Y then it should go to Branch 2. Once in a particular branch, there is a calibration routine. For the first 4 seconds I read the sensors max value (with full load) and in the next 4 seconds I read its MIN value (with no load). Once it is calibrated, the sensor is used to make measurements until such time it is turned off, so i never need to get back to the main loop.
I have to find another way to do the calibration step. Below is what I was using which worked fine on the UNO, I guess I will have to use a few FOR loops?

Code: [Select]
static int sampleLow = 1024;
static int sampleHigh = 0;

  while (millis() < 8000UL)

  {
    if (millis() <4000) {
    lcd.setCursor(0, 0);
    lcd.print("Measure");
    lcd.setCursor(0, 1);
    lcd.print("High");
     Serial.println("Measuring High");
    }
    if (millis() >4000) {
    lcd.setCursor(0, 0);
    lcd.print(" Remove ");
    lcd.setCursor(0, 1);
    lcd.print(" Load");
    Serial.println(" Remove Load");
    delay (200);
  }
   
       
    // MEASURE
    int sensorVal = analogRead(A0);

    // MATH
      sampleLow = min(sampleLow, sensorVal);
      sampleHigh = max(sampleHigh, sensorVal);
}

PaulS

Code: [Select]
  while (millis() < 8000UL)
Depending on when this code gets called, this may, or may not, be a good idea. Typically, you want to test the current time minus some previous time (when calibration started, for instance) against the interval, not just the current time.

Lsnyman

But isn't that what the next 2 IF statements do? Test in the 0-4 seconds for the max value and test in 4-8 seconds for the min value?

PaulS

Quote
But isn't that what the next 2 IF statements do? Test in the 0-4 seconds for the max value and test in 4-8 seconds for the min value?

The millis() function returns a relative time. The time is relative to when the Arduino was reset. You are using it as though it was some sort of absolute time.

Your watch is another relative device. It tells you what time it is relative to some arbitrary event that occurred long ago. Yet, you'd have no problem showing up if I said "Meet me at the bar in 20 minutes, and I'll buy you a drink." You'd have no problem answering if we were supposed to meet there at 2:00, and I was late, and I asked you how long you'd been waiting.

You need to use millis() the same way. Set a variable with the time that calibration started. Test whether now (millis()) minus then (the stored time) is greater than, or less than, some interval.

Lsnyman

Right, that is why it worked ok in the UNO because it was mostly absolute. It is used only once from Reset so the 0-4 Seconds was just that, minus a small startup time. It doesnt work very well in leonardo because of the way the Serial port works so I am trying to find another way to test the Max and Min.

Go Up