Arduino timing, checking if condition satisfied for a time period.

Hello, I’m not very experienced in programming. I want to check if the temperature was between 29 and 31 *C for consecutive 10 seconds. If so I want the cooling() function to work and cycle between heating and cooling if the conditions are satisfied for 10 seconds. I have written this code below but it doesn’t count 10 seconds, it starts executing the cooling() function when the temperature goes between 29 and 31. How can this be fixed, is the problem just caused by timing or are there other issues? I appreciate the help.

double HighTemperature = 30.0;  //The desired temperature of the chamber is 30 *C
boolean flag;

void Heating(void){
  PotValue = analogRead(PotPin) * (255.0 / 1023);  //Read the value from the potentiometer and scale the value

  if(Temperature < (HighTemperature - 1.0)){ //If temperature < 29
    flag = false;
    analogWrite(HalogenPin, 0);  //Fully turn on the lamp
    digitalWrite(FanPin, LOW);  //Fan is off
  }
  else if(Temperature <= HighTemperature && Temperature >= (HighTemperature - 1.0)){  // 29<Temp<30
    flag = true;
    analogWrite(HalogenPin, PotValue);  //You can control with pot
    digitalWrite(FanPin, LOW);  //Fan is off
  }
  else if(Temperature > HighTemperature && Temperature <= (HighTemperature + 1.0)){  //30<Temp<31
    flag = true;
    analogWrite(HalogenPin, PotValue); //You can control with pot
    analogWrite(FanPin, 180);  //Run fast slow
  }
  else if(Temperature > (HighTemperature + 1.0)){  //Temp>31
    flag = false;
    analogWrite(HalogenPin, 255);  //Turn off lamp
    analogWrite(FanPin, 220);  //Run fan faster
  }
  
  if(flag == true){
    unsigned long startTime = millis();  //Start counting
    unsigned long elapsedTime = 0 - startTime;
    if((startTime - elapsedTime) >= 10000){
      Cooling();
    }
  }
  delay(100);                 //Delay between the values
}

void Cooling(void){
  analogWrite(HalogenPin, 255);    //Turn the halogen lamp off
  digitalWrite(FanPin, HIGH);  //Run the fan in full speed
}
    unsigned long elapsedTime = 0 - startTime;

Since startTime is not 0, you are trying to store a negative value in an unsigned variable. That won't do what you think it will.

unsigned long time = millis();                         
  const unsigned long halfMinutes = 0.5 * 60 * 1000;  
  static unsigned long lastSampleTime = 0 - halfMinutes;  
  if (time - lastSampleTime >= halfMinutes){        //If Half minute is passed, do the desired operations
    lastSampleTime = lastSampleTime + halfMinutes;
}

This code checks a condition every 30 seconds and you can do your work accordingly. I wanted to implement something similar where I check if the flag is true first, is this wrong, what should I do?

what should I do?

  static unsigned long lastSampleTime = 0 - halfMinutes;

Go back to basics. Read up on the range of values that can be stored in an UNsigned long. -30000 can NOT be stored in an unsigned long.

What about this?

unsigned long startTime;
long elapsedTime = 0;
long interval = 5000;

void Heating(void){
  PotValue = analogRead(PotPin) * (255.0 / 1023);  //Read the value from the potentiometer and scale the value

  if(Temperature < (HighTemperature - 1.0)){ //If temperature < 29
    flag = false;
    analogWrite(HalogenLampPin, 0);  //Fully turn on the lamp
    digitalWrite(FanPowerPin, LOW);  //Fan is off
  }
  else if(Temperature <= HighTemperature && Temperature >= (HighTemperature - 1.0)){  // 29<Temp<30
    flag = true;
    analogWrite(HalogenLampPin, PotValue);  //You can control with pot
    digitalWrite(FanPowerPin, LOW);  //Fan is off
  }
  else if(Temperature > HighTemperature && Temperature <= (HighTemperature + 1.0)){  //30<Temp<31
    flag = true;
    analogWrite(HalogenLampPin, PotValue); //You can control with pot
    analogWrite(FanPowerPin, 180);  //Run fast slow
  }
  else if(Temperature > (HighTemperature + 1.0)){  //Temp>31
    flag = false;
    analogWrite(HalogenLampPin, 255);  //Turn off lamp
    analogWrite(FanPowerPin, 220);  //Run fan faster
  }
    delay(100);                 //Delay between the values

  
  if(flag == true){
   startTime = millis();  //Start counting
   
    if((startTime - elapsedTime) >= interval){
      elapsedTime = startTime;
      Cooling();
    }
  }
}

void Cooling(void){
  if(Temperature> LowTemperature){
  analogWrite(HalogenLampPin, 255);    //Turn the halogen lamp off
  digitalWrite(FanPowerPin, HIGH);  //Run the fan in full speed
  }
  
}

I made sure the temperature was between 29 and 31 for 5 seconds. This time the program doesn’t automatically go to Cooling() when the temperature is between 29 and 31, it just never goes to Cooling()?

  if(Temperature < (HighTemperature - 1.0)){ //If temperature < 29
    flag = false;

flag conveys no information. isTooHot, on the other hand, defines exactly what the issue is.

Or maybe it should be itsJustRight. It’s very hard to tell from your context.

    delay(100);                 //Delay between the values

That comment is meaningless. You may be delaying between actions, but you are not delaying between values. That makes no sense.

it just never goes to Cooling()?

How do you know?

Serial.println("Cooling -->"); // Put this at the start of the function
Serial.println("Cooling <--"); // Put this at the end of the function

and remove all doubt.

It really isn’t clear what you are trying to do. If you want the cooling function to execute for some defined amount of time, when cooling is needed, just add delay(thatAmountOfTime); to Cooling().

If the idea is to execute the Cooling() function in a non-blocking fashion, and require that the function run for a defined amount of time, then you need to NOT change the value of flag during the time that Cooling() is to run.

Please explain, WITHOUT ANY CODE, exactly what you are trying to do.

PaulS: Please explain, WITHOUT ANY CODE, exactly what you are trying to do.

I'm trying to build some sort of thermal cycler. I have a halogen lamp to increase the temperature, a fan to decrease the temperature and I'm using a thermistor to read the temperature. I want two set temperatures, 30 for high and 20 for low (they can changed in the future). When the program starts, the thermistor is read and the temperature is shown to the serial monitor (starts around room temperature). Then, I call the Heating() function to increase the temperature to around the high temperature (30 *C). Because the temperautre doesn't stay constant at 30.00 *C exactly, I wanted to implement, if the temperature is between 29 and 31 for some period of time, it would be good enough. So, I wanted to check whether the temperature was between 29 and 31 for some amount of time(10 consecutive seconds) and if so I could move to my Low temperature (20*C) and do the same operation there and move back to Heating to get the temperature 30 *C. This is what I want to do. I hope it's clear enough.

I wanted to implement, if the temperature is between 29 and 31 for some period of time, it would be good enough.

So, when the temperature is 29, and was lower than that, record the time that the transition happened.

What should happen if the temperature goes above 31?

It sounds like you want several states - doing nothing, active heating, passive heating, active cooling, and passive cooling. Without getting into how to deal with the states, and how to transition from one to another, and what should happen when the transition occurs, do I have a good understanding of the states?

Hello, I’ve worked on it a bit and wrote something like this:

unsigned long previousMillis = 0;
int interval=5000;
boolean heatflag;
boolean heatcomplete;
boolean coolflag;
boolean coolcomplete;

void Heating(void){
  PotValue = analogRead(PotPin) * (255.0 / 1023);  //Read the value from the potentiometer and scale the value

  if(Temperature < (HighTemperature - 1.0)){ //If temperature < 29
    heatflag = false;
    analogWrite(HalogenLampPin, 0);  //Fully turn on the lamp
    digitalWrite(FanPowerPin, LOW);  //Fan is running
  }
  else if(Temperature >= (HighTemperature - 1.0) && Temperature <= (HighTemperature + 1.0) ){  // 29<Temp<31
    heatflag = true;
    analogWrite(HalogenLampPin, PotValue);  //You can control with pot
    analogWrite(FanPowerPin, 200);  //Fan turn fan on
  }
  else if(Temperature > (HighTemperature + 1.0)){  //Temp>31
    heatflag = false;
    analogWrite(HalogenLampPin, 255);  //Turn off lamp
    analogWrite(FanPowerPin, 200);  //Run fan
  }
  if(heatflag == true){ 
    unsigned long currentMillis = millis();  //Start counting
    if((unsigned long)(currentMillis - previousMillis) > interval) {
      heatcomplete = true;
      previousMillis = currentMillis;
    }
  }
  if(heatcomplete == true){
    Cooling();
  }
}

void Cooling(void){
  if(Temperature > (LowTemperature + 1.0)){
    coolflag = false;
    digitalWrite(FanPowerPin, HIGH);
    analogWrite(HalogenLampPin, 255);
  }
  else if(Temperature <= (LowTemperature + 1.0) && Temperature >= (LowTemperature - 1.0)){
    coolflag = true;
    analogWrite(FanPowerPin, 200);
    analogWrite(HalogenLampPin, PotValue);
  }
  else if (Temperature < (LowTemperature - 1.0)){
    coolflag= false;
    digitalWrite(FanPowerPin, LOW);
    analogWrite(HalogenLampPin, 0);
  }
  if(coolflag == true){ 
    unsigned long currentMillis = millis();  
    if((unsigned long)(currentMillis - previousMillis) > interval) {
      coolcomplete = true;
      previousMillis = currentMillis;
    }
  }
  if(coolcomplete == true){
    Heating();
  }
}

The problem is, when run

 if((unsigned long)(currentMillis - previousMillis) > interval)

statement, it takes just the moment when the temperature reaches 29 and enters Cooling() function. I think if it didn’t take the first value, it would be alright, because I tried before writing the Cooling() function and saw a message every 5 seconds when the condition was met. Also, in my loop() function, I just call a thermistor() function which reads and prints the temperature and Heating() function. After the cooling() I realized the system resets. Is there a way to fix this? Thanks.

You are using previousMillis() in both Heating() and Cooling(). Do you have some aversion to using names that make sense and are unique? Something like heatingStarted and coolingStarted?

It still doesn't count the time, just switches to cooling when reaches 29.