Teensy ++2.0 Control 1 relay with 2 Temp Sensors

Status
Not open for further replies.

T77

Active member
Hello,
First,....iam another totally new at the DIY Teensy/Arduino programming world.
My project is a Solar Hot Water Control.

Harware.....
Teensy ++ 2.0.
Home made Tennsy ++ 2.0 terminal board.
Windows XP PC.
Arduino Ver. 1.0.6/Teensyduino Ver. 1.2 software.
Keyes/funduino Relay Board Ver. 8R1A
(2) 10K Thermistor Sensors.

Iam trying to control one relay/water pump with 2 sensors. Example: HotWaterTank sensor says water is cold, turn on relay/water pump, but Collector Tank sensor says no, because temperature is not hot enough in Collector Tank. When Collector Tank gets hot enough, then relay/water pump will be allowed to turn on if Hot Water Tank sensor is wanting pump on. Sorry for "dummy" way of explaining it. :) Dont know how to explain it in C language...obviously. ;)

The below program is what i have so far. (Not working correctly.) It is what i originally put together to control 2 relays with 2 sensors. The below is an attempt to control 1 relay with 2 sensors.

Code:
void setup()
{                
  Serial.begin(38400);
  pinMode(PIN_D7, OUTPUT);
  pinMode(PIN_D5, OUTPUT);
}

float code;
float celsius;
float fahrenheit;

void loop()                     
{
  code = analogRead(0);
  celsius = 25 + (code - 512) / 11.00;
  fahrenheit = celsius * 1.8 + 32;
  Serial.print("HotWaterTank: ");
  Serial.print(celsius);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  if (celsius <27)
  {
    digitalWrite(PIN_D7, HIGH);  // Relay1 ON
  }
  else
  {
    digitalWrite(PIN_D7, LOW);  // Relay1 OFF
  }
    code = analogRead(1);
  celsius = 25 + (code - 512) / 11.00;
  fahrenheit = celsius * 1.8 + 32;
  Serial.print("CollectorTank: ");
  Serial.print(celsius);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  if (celsius <25)
  {
    digitalWrite(PIN_D7, LOW);  // Relay1 OFF
  }
  else
  {
    digitalWrite(PIN_D7, HIGH);  // Relay1 ON
  }
  delay(5000);
}
100_1302.jpg

I came up with a way to control pump by using 2 relays, but would rather use only 1 relay if its possible.
Thanks in advance for any info,
Troy
 
Last edited:
Ok I think you want to use AND '&' and OR '|' as per
file:///C:/arduino/arduino-1.0.6_teensy/reference/BitwiseAnd.html
and
file:///C:/arduino/arduino-1.0.6_teensy/reference/BitwiseAnd.html

so you sample and store both temperatures and then AND the two compare results which if I've got your aim worked out right:
Code:
    code = analogRead(0);
  float celsius1 = 25 + (code - 512) / 11.00;
    code = analogRead(1);
  float celsius2 = 25 + (code - 512) / 11.00;

if (celsius1 <27&celsius2>25) digitalWrite(PIN_D7, HIGH); else digitalWrite(PIN_D7, LOW);

If digging deeper into logic in more complex code see the Arduino ref docs linked in the help and note differences between things like '&&' and '&'.

Also while your current delay based code will work if you start adding features you may want to think about non blocking code.
https://learn.adafruit.com/multi-tasking-the-arduino-part-1/overview
 
:) It works!
Here is program after adding your code....

Code:
void setup()
{                
  Serial.begin(38400);
  pinMode(PIN_D7, OUTPUT);
}

float code;
float fahrenheit;

void loop()                     
{
    code = analogRead(0);
  float celsius1 = 25 + (code - 512) / 11.00;

  
  fahrenheit = celsius1 * 1.8 + 32;
  Serial.print("HotWaterTank: ");
  Serial.print(celsius1);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  
   code = analogRead(1);
  float celsius2 = 25 + (code - 512) / 11.00;
  
  fahrenheit = celsius2 * 1.8 + 32;
  Serial.print("CollectorTank: ");
  Serial.print(celsius2);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  
  
  if (celsius1 <27&celsius2>25) 
  {
  digitalWrite(PIN_D7, HIGH);
  } 
  else 
  {
  digitalWrite(PIN_D7, LOW);
  }
  delay(5000);
  }
Now i need to add another Sensor,relay and a LCD screen, when it gets here.
Thanks much for the code and links to more info. :)

Troy
Iam waiting on a LCD for this project
 
The formatting of this is hurting my brain to read. :p

Code:
 if (celsius1 <27&celsius2>25)

For the sake of good programming practise while you're learning, something like this might be easier to read and understand:
Code:
 if((celsius1 < 27) && (celsius2 > 25))

Will do exactly the same thing, and in a similar sort of way. Functionally, all I've done is change bitwise AND (&) to a comparative one (&&).

In this instance, either will work however. =)
 
:) Ive done a little C++ (just copy and paste)in the CNC machining world and a real C programmer gave me a similar line. ;)
That does have a more logical flow to it when comparing both examples.

Thanks,
Troy
 
Ok. Below is program with a 3rd temperature sensor and 2nd relay. Also added the millis() function as suggested. This tutorial on using the millis() function was easier for me to grab... http://www.baldengineer.com/millis-tutorial.html...to a certain point.
But i cant figure out how i would add 2 separate millis() functions. Example: 1st relay/PIN_D7 would have a millis() function and the 2nd relay/PIN_D5 would have its own millis()function.

Code:
unsigned long interval=15000;  // the time we need to wait
unsigned long previousMillis=0; // millis() returns an unsigned long.

void setup()
{                
  Serial.begin(38400);
  pinMode(PIN_D7, OUTPUT);
  pinMode(PIN_D5, OUTPUT);
}

float code;
float celsius;
float fahrenheit;

void loop()                     
{
   if ((unsigned long)(millis() - previousMillis) >= interval) {
     previousMillis = millis();
    code = analogRead(0);
  float celsius1 = 25 + (code - 512) / 11.00;
  fahrenheit = celsius1 * 1.8 + 32;
  Serial.print("HotWaterTank: ");
  Serial.print(celsius1);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  
   code = analogRead(1);
  float celsius2 = 25 + (code - 512) / 11.00;
  fahrenheit = celsius2 * 1.8 + 32;
  Serial.print("CollectorTank: ");
  Serial.print(celsius2);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  
  if ((celsius1 < 27) && (celsius2 > 25)) 
  {
  digitalWrite(PIN_D7, HIGH);
  } 
  else 
  {
  digitalWrite(PIN_D7, LOW);
  }
  
  code = analogRead(2);
  celsius = 25 + (code - 512) / 11.00;
  fahrenheit = celsius * 1.8 + 32;
  Serial.print("SolarCollectors: ");
  Serial.print(celsius);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  Serial.println();
  if (celsius >25)
  {
    digitalWrite(PIN_D5, HIGH);  // Relay2
  }
  else
  {
    digitalWrite(PIN_D5, LOW);  // Relay2
  }
  }
}

Thanks for the help,
Troy
 
Last edited:
In this case you just have previousMillis1 and PreviousMillis2 (or names that tie to function 'previousHeaterCheckMillis')

Then if statement for the first relay operation. Once that one closes out do a second IF for the second PreviousMillis. Normal problems extending like this are either never updating the PreviousMillis Value or updating it in the wrong IF statment so it never times out.

That said in this case as long as it's ok for both temperatures to be checked at the same time there is nothing wrong with having one timer and doing what you already have. What will be more important is once you add a display and buttons, they will need to be checked more often. In fact, you may want to make your temperature check even longer since the useful life of the relay is measured in make/unmake cycles so unless very precise control is an aim a 60 second delay on checks (once you have finished fault finding of course) will improve long term reliability.

Also note at the top here:
http://arduino.cc/en/Reference/Millis

about millis rolling over at 50 days. From the sounds of it your project will be potentially running for longer than that so you need to add a trap for the situation where previousMillis is up near 4,294,967,295 and millis() is down near 0, which will prevent your code doing anything for the next 70 days.

My default choice is to make the IF
Code:
((millis() - previousMillis >= interval)|(millis() < previousMillis))

Do note this adds other potential traps, so for example at rollover there will not be an exact interval time. In your case that doesn't matter since once every 3 months the temperatures get checked twice.
 
The only reason i was wanting to have 2 seperate timers is for possible future additions of project, where i might need the Solar Sensor to check at a different time. I might try something like adding a temperature differential to Solar Sensor. But until i actually get this off my desk and actually working, i will try to keep it simple as you suggested and have only 1 timer to start with.

I was wondering about how the lcd display would be handled, but will wait until it gets here to open that can of worms. ;)

My current timer setting of 15000ms was only for testing at my desk...thinking more of 5 to 15 minutes for real world testing.

This project will be running all the time 24/7 all year around, minus power outage and shutdown for maintenance and such. Do i understand the following correctly?.... when project has been running for 50 days, all code stops working until power is reset or ?

Thanks,
Troy
 
No, Arduino can run fine but you need to avoid Y2K type issues when you write the code.

So anytime you have a counter running you need to track 'what happens when it runs out of digits?'. Millis() is coded so it's fine crash wise, but as noted with the millis() link it runs for 70 days upwards to 4 billion and then starts over at 0. And if your code does the naive is 'currenttime bigger than old' time it will just say 'current time (0) is less than old time' so the If condition will stop triggering, though the code is still happily looping.

In fact re-reading that if statement it's more interesting and rather clever. So we take the current millis() and subtract the old Millis Value and see if it's bigger than 1500. When Millis() rolls over to 0 we then have ~ 4 billion in previous millis and do '0-4billion' and do a is > 1500 check on it. Which normally would give a math result of neg four billion but notice we are using unsigned longs, which only code positive numbers. So going down from zero rolls into the top of 4 billion again, which is greater than the interval value so the if statement still triggers, writes the previousMillis value and keeps going

So in fact the code you have will work without my suggest change across the 70 day roll over, albiet with an unknown but less than intervalTime delay which in your case doesn't matter.

As an amateur at this stuff I find it takes about twice as long to sort out all the overflow cases in code as it took to work out the original math.

Or there is the XKCD solution http://xkcd.com/1495/
 
Quote from http://xkcd.com/1495/...

" Who are you?

I'm just this guy, you know? I'm a CNU graduate with a degree in physics. Before starting xkcd, I worked on robots at NASA's Langley Research Center in Virginia. As of June 2007 I live in Massachusetts. In my spare time I climb things, open strange doors, and go to goth clubs dressed as a frat guy so I can stand around and look terribly uncomfortable. At frat parties I do the same thing, but the other way around."

:D lol
 
Now iam trying to add to my IF function of relay2. Below is code to operate relay2 only.

Code:
unsigned long interval=5000;  // the time we need to wait
unsigned long previousMillis=0; // millis() returns an unsigned long.

void setup()
{                
  Serial.begin(38400);
  pinMode(PIN_D5, OUTPUT);
}

float code;
//float celsius;
float fahrenheit;

void loop()                     
{
   if ((unsigned long)(millis() - previousMillis) >= interval) {
     previousMillis = millis();
     
   code = analogRead(1);
  float celsius1 = 25 + (code - 512) / 11.00;
  fahrenheit = celsius1 * 1.8 + 32;
  Serial.print("CollectorTank: ");
  Serial.print(celsius1);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  
  
    code = analogRead(2);
  float celsius2 = 25 + (code - 512) / 11.00;
  fahrenheit = celsius2 * 1.8 + 32;
  Serial.print("SolarCollectors: ");
  Serial.print(celsius2);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  Serial.println();
  
  if ((celsius2 > 27) && (celsius2 + 10> celsius1)) 
  {
    digitalWrite(PIN_D5, HIGH);  // Relay ON
  }
  else
  {
    digitalWrite(PIN_D5, LOW);  // Relay OFF
  }
  }
}

What iam needing is relay2 to turn on if celsius2 is greater than 27degrees and 10 degrees greater than celsius1 temperature. So what am i missing?

Thanks,
Troy
 
Last edited:
Not sure but i believe i got it working... does this look correct? Am i missing something that might cause a problem?

Code:
if ((celsius2 > 27) && (celsius2 > celsius1 + 10))
 
Last edited:
Freeze protection

The if statement seems to be working (at least in bench testing). Here is full updated Code...
Code:
unsigned long interval=5000;  // the time we need to wait
unsigned long previousMillis=0; // millis() returns an unsigned long.

void setup()
{                
  Serial.begin(38400);
  pinMode(PIN_D7, OUTPUT);
  pinMode(PIN_D5, OUTPUT);
}

float code;
float fahrenheit;

void loop()                     
{
   if ((unsigned long)(millis() - previousMillis) >= interval) {
     previousMillis = millis();
    code = analogRead(0);
  float celsius0 = 25 + (code - 512) / 11.00;
  fahrenheit = celsius0 * 1.8 + 32;
  Serial.print("HotWaterTank: ");
  Serial.print(celsius0);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  
   code = analogRead(1);
  float celsius1 = 25 + (code - 512) / 11.00;
  fahrenheit = celsius1 * 1.8 + 32;
  Serial.print("CollectorTank: ");
  Serial.print(celsius1);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  
  if ((celsius0 < 27) && (celsius1 > 25)) 
  {
  digitalWrite(PIN_D7, HIGH); //Relay ON
  } 
  else 
  {
  digitalWrite(PIN_D7, LOW); //Relay OFF
  }
  
   code = analogRead(2); // Solar Collector Temperature Sensor
  float celsius2 = 25 + (code - 512) / 11.00;
  fahrenheit = celsius2 * 1.8 + 32;
  Serial.print("SolarCollectors: ");
  Serial.print(celsius2);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  Serial.println();
  
  if ((celsius2 > 27) && (celsius2 > celsius1 + 10)) //If Solar Collector is at least 27 dg and 
                                                     //10 dg greater than Collector Tank, then
                                                     //turn on relay2 SolarCollector pump.
  {
    digitalWrite(PIN_D5, HIGH);  // Relay2 SollarCollector Pump ON
  }
  else
  {
    digitalWrite(PIN_D5, LOW);  // Relay SollarCollector Pump OFF
  }
  }
}
// Note: 
// Add a freeze protection for Sollar Collector pump to turn on
// when Sollar Collector temperature drops below a set temperature.

Now i need to add a freeze protection of Sollar Collectors. Which will turn on relay2 if temperature falls below a set freezing temperature and will not shut off pump until temperature reaches above freezing to a set temperature.
I dont know where to start implementing this in the above code.

Any info is much appreciated,
Troy
 
Last edited:
That should be fine. celsius1+10 is safe unless you start getting temperatures well outside anything sensible.

One thing to think about now is the amount of noise and accuracy of those temperature readings as finally installed. If this is still on a bench it may be useful to tape or bolt all your sensors together and cycle the temperature recording results checking for A. similar numbers and B. variation within a sensor. If any of the sensors will have long wires when installed fit roughly that length to the sensor for the test.

If you do so suggest writing a separate simple program to sample each sensor 10 times, serial print the results then wait 20 seconds. If you want to get clever you can also use arrays
http://arduino.cc/en/reference/array
to store those 10 values and calculate averages and standard deviation.

All of this is overkill for this specific application but can be worth getting your head around and will help trap any assumptions by having actual data.

You may also want to find out what temperature happens if a sensor is unplugged and add an IF statement to put the relays to a safe state in this case.
 
There are a couple of ways to hit the freezing problem. Either use a variable that can be set in turn by multiple if statments
int RunPump=0;
IF conditionA is true -> runpump=1
IF conditionB is true -> runpump=1
IF runPump>0 -> set relay/else unset relay

or you can stuff it all into one line
Code:
  if (((celsius2 > 27) && (celsius2 > celsius1 + 10))|| celsius2<0)

So we have a true output for hightemp+tempdifferential OR it's freezing

In your case it may be easier to have a couple of tracking variables like 'sensorFail','itsFreezing', 'panelAbove27' and 'temperatureDiffOK' and feed them into simple two case IF statements. The code will be longer but done right it will be pretty human readable. Can also lead to wonderful spaghetti code so go with what fits inside your head.
 
I started looking at variables last night, but more than i would like to chew for now. I can see the strength in variables, they are similar to how variables are used in Gcode in the CNC world. :) The OR added to IF statement makes more sense to me right now.

If a sensor becomes disconnected the reading on that analog input reads -21.55C. If this happens to the Solar Collector sensor the pump will run....this is a good thing for summer and winter. It will prevent a stagnation. This system is also a closed loop glycol 50/50 mixture, good to well below freezing temperatures.
 
Last edited:
I should point out that you've grabbed yourself quite a complex problem there so it's normal for things to be taking time. Would suggest keeping notes either on paper or as comments on what you have done and what things do since the final result is going to be a fairly complex piece of code that you will be revisiting every part of before you are done.
 
Thats what iam doing now....making comments in my sketch and on paper so i dont forget what is going on. ;) And maybe someone else can use this code.

Thanks again,
Troy
 
A function that helps keeping all these millis statement neat is elapsedMillis. If you are programming on Teensy only you don't need to include a library as elapsedMillis is part of Teesnyduino.
For normal Arduino boards you need too include it as a library. It's explained at the bottom of the linked page.
 
Last edited:
I think i have a situation where i need individual millis() or whatever way to have 2 different things happening at once like the link that was posted before describes. https://learn.adafruit.com/multi-tasking-the-arduino-part-1/overview Not sure how to apply this example for my code.

What iam doing is adding a 3rd relay and it needs to be controlled with a separate delay or millis(). I tried adding a 2nd millis() after the first millis() but the code after first millis()will not run until 1st millis() completes. Here is an example code.....

Code:
unsigned long interval1 =30000;  // the time we need to wait
unsigned long previousMillis1=0; // millis() returns an unsigned long.

unsigned long interval2 =1000;  // the time we need to wait
unsigned long previousMillis2=0; // millis() returns an unsigned long.
void setup()
{                
  Serial.begin(38400);
  pinMode(PIN_D5, OUTPUT);
  pinMode(PIN_D7, OUTPUT);
}

float code;
float fahrenheit;

void loop()                     
{
   if ((unsigned long )(millis() - previousMillis1) >= interval1) {
     previousMillis1 = millis();
     
  code = analogRead(1);
  float celsius1 = 25 + (code - 512) / 11.00;
  fahrenheit = celsius1 * 1.8 + 32;
  Serial.print("temp.SENSOR1: ");
  Serial.print(celsius1);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");

  if (celsius1 > 27)
  {
    digitalWrite(PIN_D5, HIGH);  // Relay
  }
  else
  {
    digitalWrite(PIN_D5, LOW);  // Relay
  }
  
 if ((unsigned long )(millis() - previousMillis2) >= interval2) {
     previousMillis2 = millis();
     
  code = analogRead(2);
 float celsius2 = 25 + (code - 512) / 11.00;
  fahrenheit = celsius2 * 1.8 + 32;
  Serial.print("temp.SENSOR2: ");
  Serial.print(celsius2);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");

  if (celsius2 < 25)
  {
    digitalWrite(PIN_D7, HIGH);  // Relay
  }
  else
  {
    digitalWrite(PIN_D7, LOW);  // Relay
  }   
    
   }
}
}

Thanks for any info again,
Troy
 
Last edited:
What you've done is embed your check for interval 2 within the code that gets called when your first timer elapses. Pay careful attention to your curly braces. This results in your check for your 1 second interval only being called when your 30 second interval has expired. This is why correct indentation can be very useful as you can easily see what code sections are embedded in what. Have a look here for some more information regarding indentation and formatting: http://www.cs.arizona.edu/~mccann/indent_c.html

I've put together a template you can work off with the curly braces and formatting corrected you can use if you wish.

Code:
const unsigned long interval1 = 30000;
const unsigned long interval2 = 1000;

unsigned long lastInterval1CallTime = 0;
unsigned long lastInterval2CallTime = 0;

void setup()
{
  //Setup stuff 
}

void loop() 
{
  if((millis() - lastInterval1CallTime) > interval1) 
  {
    lastInterval1CallTime = millis(); 
    //Whatever you need to do every 30 seconds (interval 1).
  }
  
  if((millis() - lastInterval2CallTime) > interval2)
  {
    lastInterval2CallTime = millis();
    //Whatever you need to do every second (interval 2). 
  }
}
 
Last edited:
Awesome. :) I didnt know/understand that the curly braces could be used like that. I thought the 2 braces at the end was like a end of code similar to how an M30 works in Gcode, CNC world.
Curious as too what is the difference in the way you used millis() and the one iam using? Is one better than the other for certain things?

Thanks for the formatting info link. Iam working on that now.

Troy
 
Status
Not open for further replies.
Back
Top