locking value from looping input

Hello,

I have values coming from two temperature sensors.

I need to read and store the first one and let the other one fluctuate so I can take action depending on the difference between the 2 values (the fixed base and the fluctuating one).

Then every half hour or so, I update the base value coming from the first sensor and continue the process.

I don't know how to 'lock' the value of the first variable. Since the sensor reading is in the loop part of the sketch, both values are always updated. (every way I tried to think of it, it always comes back to this, I need to lock it, but then the locking is also part of the loop, so I would just lock new values at every turn of the loop!)

I need advice,

thanks

Use a timer.

unsigned long t0=millis();

void loop()
{
  if (millis()-t0>1800000UL)
  {
    t0=millis();
    temp1=analogRead(temp1_channel); // Update only after 1800 seconds or half an hour.
  }

  // Do other stuff such as reading the second sensor and else.
}

This simple code will certainly fail after 50 days when millis overflows but by that time you should have figured out how to modify this code to take care of that. :wink:

This simple code will certainly fail after 50 days when millis overflows but by that time .....

not quite right, millis() will indeed overflow but as you use subtraction to get a difference in time the code will not fail .

I adapted liudr's code so you can tune the frequency for both the sensors.

#define TIMEOUT1 30UL * 60UL * 1000UL  // 30 minute  -- frequency of temperature 1
#define TIMEOUT2 60UL * 1000UL   // 1 minute -- frequency of temperature 2

unsigned long t1 = millis();
unsigned long t2 = millis();

void loop()
{
  if ( millis() - t1 > TIMEOUT1 )
  {
    t1 = millis();
    temp1 = analogRead(temp1_channel); 
  }
  
  if ( millis() - t2 > TIMEOUT2 )  
  {
    t2 = millis();
    temp2 = analogRead(temp2_channel); 
    if (abs (temp1 - temp2) > THRESHOLD) doYourThing();
  }

  // ...
}

update -- bug fixed, see next post Msquare - thanx!

The second timer should probably be:

if ( millis() - t2 > TIMEOUT2)  // changed to refer to the 2nd timer variables ...
  {
    t2 = millis();

Great.

This was the first avenue I tried to solve my problem, but since it wasn't working I tried other thing that didn't work either.

now it's getting better, but I still can't make it work without delays even though I use a millis() timer. Here is why: When the timer turns on, I need to have a valve open for about 10 seconds at first and then at other intervals, with the millis() timer, I can get the Arduino to pulse HIGH at the right time, but I have to put a delay to keep it HIGH.

I tried different combinations of indented millis() timers inside the ''main'' millis() tier, but to no good.

I will keep on trying, thank for your help, you put me on the right track

here's the tricky part the code at the moment, it works, but it's not smooth, I get poor control over the valve since I monitor it at fixed intervals instead of having it work only when it needs to.

long previousFlowMillis = 0;     // Flow reset  (t0)
long previousCycleMillis = 0;    // Cycle reset (t0)
long previousPurgeMillis = 0;   // Purge reset (t0)
long purgeInterval = 10000;    // 10 seconds
long flowInterval = 60000;      //  1 minute
long cycleInterval = 1800000;  //  half hour

void loop();
{
 float steinhart2;                                                   //sensor 2, fresh water temp.(steinhart gives the temp in *C (from ladyada's tutorial))
 float steinhart3;                                                   //sensor 3, room temp water.
 unsigned long currentCycleMillis = millis();                 //for the half-hour-update
 unsigned long currentFlowMillis = millis();                  //for the every-minute-update
 unsigned long currentPurgeMillis = millis();                //for the 10 sec. purge of the pipe  
 
 if(currentCycleMillis - previousCycleMillis > cycleInterval)    //if (present time) - (previous action time) > Cycleinterval » start half_hour cycle    
 {
  previousCycleMillis = currentCycleMillis;                          //reset previousCycleMillis for next loop
  digitalWrite(ledPinRelay, HIGH);                                   //ledPinRelay » turn on led and activate relay for valve
  delay(purgeInterval);                                                  //wait 10 seconds to purge the line (every 1/2 hour I open teh valve, let it flow for
 }                                                                             //10 seconds before I take the first temp. reading

 if(currentFlowMillis - previousFlowMillis > flowInterval)       //if (present time) - (previous action time) > flowInterval = start minute flow cycle    
 {
  previousFlowMillis = currentFlowMillis;                            //reset previousCycleMillis for next loop
  if((steinhart3 - steinhart2) <= 2)                                  //compare room temp water with fresh water temp, 
  {
   digitalWrite(ledPinRelay, LOW);                                   //close valve if the temp. difference is less than 2 *Celcius 
  }
  else 
  {
   digitalWrite(ledPinRelay, HIGH);                                  //keep valve open if the temp diff. is more than 2 *Celcius 
   delay(purgeInterval);                                                //let it run for 10 seconds                                         
  }
 }

You should not use delay but use the same type of "timer" we suggested you use. We didn't know you had a digital output to deal with. Why don't you draw up a diagram or flow chart of what you want to do?

Doing two timers at once ... not using delay ... --> hint on the Playground under Tutorials, Avoiding Delay

Hey,

Here's what I want to do.

I have a bucket of water I want to keep as cold as the water is when it comes out of the faucet. I could just leave the faucet open but that would be a waste.

So, I'm hooked on the main water line with a pipe going to a 12v NC on/off valve. This valve is controlled by the Arduino via a relay and, when opened, lets water flow in the bucket. The bucket overflows in a drain.

There is a thermistor (temp 2) in the pipe right at the outlet of the valve for fresh water temp, and another one in the bucket (temp 3) for room temperature temp.

I want the valve to open every 30 minutes (this is a test, I have to check the fluctuation of the water temperature over 24h) and let the water flow for 10 seconds to drain the pipe of it's room temperature water.

Then I take the fresh water temperature as a standard.

For the next 30 minutes if the temperature in the bucket gets more than 1 C warmer than the standard, the valve opens until the temperature in the bucket is less than 1C warmer than the standard.

After 30 minutes (or so) it starts over to reset the standard

here's the code, its a modification of the thermistor code I found here Sensor tutorials - Thermistor

// which analog pin to connect
#define THERMISTORPIN2 A2
#define THERMISTORPIN3 A3
// resistance at 25 degrees C
#define THERMISTORNOMINAL 10000      
// temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL 25   
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES2 5
#define NUMSAMPLES3 5
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT 3950
// the value of the 'other' resistor
#define SERIESRESISTOR2 10000
#define SERIESRESISTOR3 10000 
 
int samples2[NUMSAMPLES2];
int samples3[NUMSAMPLES3];
int ledPin2 = 2;
int ledPin3 = 3;
int ledPinRelay = 4;

long previousPurgeMillis = 0; // Purge reset (t0)
long previousFlowMillis = 0;  // Flow reset  (t0)
long previousCycleMillis = 0; // Cycle reset (t0)

long purgeInterval = 1000;    // 10 seconds
long flowInterval  = 10000;   // 1 minute
long cycleInterval = 1800000; // half hour

unsigned long currentPurgeMillis = millis();     //for the purge
unsigned long currentFlowMillis = millis();      //for the every-minute-update
unsigned long currentCycleMillis = millis();     //for the half-hour-update

void setup(void) {
  Serial.begin(9600);
  analogReference(EXTERNAL);
  pinMode (ledPin2, OUTPUT);
  pinMode (ledPin3, OUTPUT);
  pinMode (ledPinRelay, OUTPUT);  
}

void loop(void) {
 unsigned long currentCycleMillis = millis();                    //for the half-hour-update
 unsigned long currentFlowMillis = millis();                     //for the every-minute-update
 unsigned long currentPurgeMillis = millis();
  uint8_t i, j;
  float average2;
  float average3;
 
  // take N samples in a row, with a slight delay
  for (i=0; i< NUMSAMPLES2; i++) {
   samples2[i] = analogRead(THERMISTORPIN2);
   delay(10);                                                   // Here are short delays, should I avoid them as well?
  }
  for (j=0; j< NUMSAMPLES3; j++) {
   samples3[j] = analogRead(THERMISTORPIN3);
   delay(10);
  }  
 
  // average all the samples out
  average2 = 0;
  average3 = 0;
  for (i=0; i< NUMSAMPLES2; i++) {
     average2 += samples2[i];
  }
  for (j=0; j< NUMSAMPLES3; j++) {
     average3 += samples3[j];
  }  
  
  average2 /= NUMSAMPLES2;
  average3 /= NUMSAMPLES3; 
  
  Serial.print("Average2 analog reading "); 
  Serial.println(average2);
  Serial.print("Average3 analog reading "); 
  Serial.println(average3);
  
  // convert the value to resistance
  average2 = 1023 / average2 - 1;
  average2 = SERIESRESISTOR2 / average2;
  Serial.print("Thermistor resistance2 "); 
  Serial.println(average2);

  average3 = 1023 / average3 - 1;
  average3 = SERIESRESISTOR3 / average3;
  Serial.print("Thermistor resistance3 "); 
  Serial.println(average3);
 
  
  float steinhart2;
  steinhart2 = average2 / THERMISTORNOMINAL;         // (R/Ro)
  steinhart2 = log(steinhart2);                      // ln(R/Ro)
  steinhart2 /= BCOEFFICIENT;                        // 1/B * ln(R/Ro)
  steinhart2 += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart2 = 1.0 / steinhart2;                     // Invert
  steinhart2 -= 273.15;                              // convert to *C
  
  if(steinhart2 > 27)
  {
   digitalWrite(ledPin2, HIGH);
  }
  else
  {
   digitalWrite(ledPin2, LOW);
  }  
 
  Serial.print("Temperature2 "); 
  Serial.print(steinhart2);
  Serial.println(" *C");
  
  float steinhart3;
  steinhart3 = average3 / THERMISTORNOMINAL;         // (R/Ro)
  steinhart3 = log(steinhart3);                      // ln(R/Ro)
  steinhart3 /= BCOEFFICIENT;                        // 1/B * ln(R/Ro)
  steinhart3 += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart3 = 1.0 / steinhart3;                     // Invert
  steinhart3 -= 273.15;                              // convert to C
  
  if(steinhart3 < 27)
  {
   digitalWrite(ledPin3, HIGH);
  }
  else
  {
   digitalWrite(ledPin3, LOW);
  }  
 
  Serial.print("Temperature3 "); 
  Serial.print(steinhart3);
  Serial.println(" *C");

 int temp2 = steinhart2;                                       //fresh water temp.
 int temp3 = steinhart3;                                       //room temp water.
 
 if(currentCycleMillis - previousCycleMillis > cycleInterval)  //Cycle = half_hour cycle    
 {
  previousCycleMillis = currentCycleMillis; 
  digitalWrite(ledPinRelay, HIGH);
  if(currentPurgeMillis - previousPurgeMillis > purgeInterval) //THIS IS WHERE THE PROBLEM LIES, I can't keep it on! If replaced with a delay()
  {                                                                             // it kind of works but it's far from being elegant.
   digitalWrite(ledPinRelay, LOW);
  }
 }
 if(currentFlowMillis - previousFlowMillis > flowInterval)     //Flow = check temp3 every minute, but ideally it would be continuous   
 {
  previousFlowMillis = currentFlowMillis;                      
  if(abs (steinhart3 - steinhart2) >= 1)                       //compare room temp water / fresh water temp, (is abs necessary since t3 will always be higher?) 
  {
   digitalWrite(ledPinRelay, HIGH);                            //open valve if the temp diff. is more than 1 *Celcius
  }
  if(abs (steinhart3 - steinhart2) <= 1)                       //compare room temp water / fresh water temp, (is abs necessary since t3 will always be higher?) 
  {
   digitalWrite(ledPinRelay, LOW);                            //close valve if the temp diff. is less than 1 *Celcius
  }
 }
delay(1000);                                                       //this delay is used to make serial.print usable (i think) should it also be millisied?
}

As you can also see, there are 3 other short delays, two at the beginning of the loop where a sampling is done to average the temperatures and another on at the very end to make the serial.print readable. Should I replace them with millis() as well? or are sort ones ok?