Need help. Local variables not deleting after function is terminated

Hey guys, so I've written a self calibrating program for a capacitive soil moisture sensor that begins when a button is pressed.

Everything works fine, the program calculates the highest and lowest values once the readings are done in a specific period of time.

In essence I run 2 separate for loops that run for 10 seconds and 30 seconds depending on the calibration being done (air value vs wet value).

Everything works for the first time I run the program. However, once I try to run the calibration program again, it seems that the for loop conditions are immediately met, and the program skips to the next part.

I believe the problem lies in the local valiables I created for the for loops (to count the time the for loops run for) not deleting.

Any insight into this would be super helpful.


#include <LiquidCrystal.h>
#include <JELdimmer2.h>
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);

//Configuraciones del sensor de humedad
int ValorAire = 600;   //Este es el valor del sensor cuando está totalmente seco y al aire.
int ValorAgua = 250;  //Este es el valor del sensor cuando está sumergido en agua.
int tiempoLecturaAgua = 30000; //Este es el tiempo que el programa de calibración usa para leer el sensor sumergido en agua.
int tiempoLecturaAire = 10000; //Este es el tiempo que el programa de calibración usa para leer el sensor sumergido en agua.
int HumedadTierra = 0;
byte HumedadTierraPorciento = 0;
byte BotonCalibracion = 8;



void setup() {
  
  Serial.begin(9600); // Abrir puerto serial.
  
  lcd.begin(16, 2);
  
  
  pinMode(BotonCalibracion, INPUT_PULLUP);
  
  

}

void loop() {

  Inicio:
  
  HumedadTierra = analogRead(A0);
  HumedadTierraPorciento = map(HumedadTierra, ValorAire, ValorAgua, 0, 100);
  Serial.println(HumedadTierra);
  Serial.print(HumedadTierraPorciento);
  Serial.println("%");
  lcd.setCursor(0, 0);
  lcd.print("Humedad");
  lcd.setCursor(0, 1);
  lcd.print(HumedadTierraPorciento);
  lcd.print(" %   ");

  delay(1000);


  
  
  if (digitalRead(BotonCalibracion) == LOW){

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Calibremos");
    lcd.setCursor(0, 1);
    lcd.print("el sensor");
    delay(2000);
    lcd.clear();

    while (digitalRead(BotonCalibracion) == HIGH){
    
    lcd.setCursor(0, 0);
    lcd.print("Seque sensor");
    lcd.setCursor(0, 1);
    lcd.print("completamente");
    
      if (digitalRead(BotonCalibracion) == LOW){

        lcd.clear();
        
        for (int tiempoInicioAire = millis(); (millis()-tiempoInicioAire) < tiempoLecturaAire; ){
          ValorAire = max(analogRead(0), ValorAire);
          lcd.setCursor(0, 0);
          lcd.print("Calibrando");
          lcd.setCursor(0, 1);
          lcd.print("para aire ");
          Serial.println(ValorAire);
 
        }

          lcd.clear();  
          lcd.setCursor(0, 0);
          lcd.print("Valor Aire");
          lcd.setCursor(0, 1);
          lcd.print("establecido: ");
          lcd.print(ValorAire);
          Serial.println(ValorAire);
          delay(5000);
      
          lcd.clear();


         while (digitalRead(BotonCalibracion) == HIGH){


              
              lcd.setCursor(0, 0);
              lcd.print("Ahora sumerja");
              lcd.setCursor(0, 1);
              lcd.print("en agua");

              if (digitalRead(BotonCalibracion) == LOW){

                    lcd.clear();
        
                    for (int tiempoInicioAgua = millis(); (millis()-tiempoInicioAgua) < tiempoLecturaAgua; ){
                    ValorAgua = min(analogRead(0), ValorAgua);
                    lcd.setCursor(0, 0);
                    lcd.print("Calibrando");
                    lcd.setCursor(0, 1);
                    lcd.print("para agua");
                    Serial.println(ValorAgua);
 
                    }

                    lcd.clear();
                      
                    lcd.setCursor(0, 0);
                    lcd.print("Valor Agua");
                    lcd.setCursor(0, 1);
                    lcd.print("establecido: ");
                    lcd.print(ValorAgua);
                    Serial.println(ValorAgua);
                    delay(5000);

                    lcd.clear();  
                    
                    lcd.setCursor(0, 0);
                    lcd.print("Calibracion");
                    lcd.setCursor(0, 1);
                    lcd.print("exitosa");
                    
                    Serial.println(ValorAgua);
                    delay(5000);
                    lcd.clear();

                   
         return;
          
         }


      }

   

   }
  
 }
 
}

}

    


What do you mean? The first time you press the button after a reset or power cycle on -off?

As far as I can see, flow is controlled entirely by the button. What variable(s) are you talking about that seem to get in the way?

a7

Uh-oh

That button is not declared so defaults to INPUT which requires an external pull-up resistor. Is one installed? How do you have the button wired up?

All of your time variables should be of type 'unsigned long', not 'int'.

This:

        for (int tiempoInicioAire = millis(); (millis() - tiempoInicioAire) < tiempoLecturaAire; ) {
          ...
        }

does not keep track of elapsed time. Once through the loop does not equal 1 millisecond. Look at the Blink Without Delay example in the IDE (File->examples->02.digital->Blink Without Delay) to learn how to track elapsed time.

You might also benefit from several things at the same time as your code has multiple layers of while/for which is usually NOT the correct design. You want to let loop() execute as much as possible. Everything does not have to be done on a single trip through loop()

All of your 'for' loops use local variables. You do not have a problem there. Otherwise, your program is controlled completely by the 'BotonCalibracion' button. However, I'm having a hard time understanding how you intend to use the button transitions for calibration. The way the code is written you have to hold the button for up 1 second to start the calibration and release it within 2 seconds to continue the calibration. The rest I have a hard time following.

Wouldn't it just be easier to start the calibration process when the button is pressed without having to worry about how long you have to hold it and when you release it?

You are right, the "calibration program" starts with one button push, then continues with more button pushes.

The first time the calibration program works very well. The for loops run for the time defined in the header.

They redefine the variables "ValorAgua", and "ValorAire" just as expected.

However, when I try to run the calibration program a second time, just to see if it works, the program skips the for loops, as if the conditions are met for the for loops to stop.

Basically, the program jumps to the part where "Valor aire establecido" is printed to the screen. Same for "Valor agua establecido".

This is why it makes me believe that the variables defined in the for loop brackets have not been deleted.

Good catch, deleted it. Still, it seems like it didn't affect the program at all.

Thanks for the definition of the variables with unsigned long, that makes sense.

The for loops do run for the time I define them. I define the time elapsed at the beginning of the program, in the header.

The time variables are: tiempoLecturaAgua, and tiempoLecturaAire

Button is declared at the setup() function:

  pinMode(BotonCalibracion, INPUT_PULLUP);

It does work as you mention it on the second paragraph.

Once the button is pressed, a brief welcome message is shown. Then, it waits for the user to press the button to go to the next step.

The unsigned long seemed to do the trick.... Funny how one detail screws up the entire code.

Thank you for your help. Much appreciated.

Going through a for() loop 10,000 times does not equal running a loop for 10,000 milliseconds.

Could you explain on this a bit? Don't see the connection with the current for loops I'm using.

That bit of code. First off, your loop variable needs to be unsigned long.
But, now that I look at it again, I see you aren't just incrementing your loop variable, but subtracting it from millis() so you are tracking time. My bad. Just not a common way of doing it.

Yes, you,re right on the unsigned long. That was the reason why the for loop didn't work for a second time. Thank you.


Perhaps you would like this better if expressed conventionally (no difference to the logic):
 {
    int tiempoInicioAire = millis();

    while ((millis() - tiempoInicioAire) < tiempoLecturaAire) {
        ...
    }
}

The extra braces are just for the local variable scope.

Edit: Sry, just read far enough, should have, to see

a7

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.