Go Down

Topic: water temp fan controller (Read 2360 times) previous topic - next topic

cr0sh

tkbyd:
Quote
In the Arduino, unless you start working with interrupts, flow charts and structure diagrams will help you get things DESIGNED right BEFORE you start writing the code.... which has to be RE-written many times, if the design wasn't good going in.


This is actually true regardless of whatever process is being created; from a piece of software to an assembly line to how to order pizza (ok, maybe not the last one, but try flowcharting the process of ordering a pizza sometime - its more complex than you think, if you really think about the steps).

If you want to really understand process, look into six sigma - oh, boy!

But really, flowcharting and other graphical diagrams, along with pseudo-code breakouts and such, to "simulate" a design before committing it to real code is the way to go for any complex piece of software.

Take good notes on all of this, deputyhiro, because while people's comments here may seem like nit-picking, I would hazard to guess that much of it is because of long and hard experience in both coding and circuit design. If you don't do this right, up front, and you decide in five years to change things (after not looking at them for all that time), you may find yourself either scratching your head for a long time trying to figure out what is doing what, or giving up altogether and re-writing the whole thing again!

Also, use better variable names - for instance, instead of "tstat", why not "thermostatState"? It makes the code easier to read (and has that "self-commenting" style that can help yourself and others figure out what is going on).

Final note: USE PLENTY OF CLEAR AND CONSISE COMMENTS IN YOUR CODE - your future self will thank you (you seem to have a good start on this, but I just wanted to say it again)!

Good luck...  :)
I will not respond to Arduino help PM's from random forum users; if you have such a question, start a new topic thread.

deputyhiro

#16
Jan 28, 2010, 12:44 am Last Edit: Jan 28, 2010, 12:46 am by deputyhiro Reason: 1
Ok, I totally reworked this sketch, and it seems to be a lot easier to follow. Paul, when you looked at my last sketch I had  "while (tstat ==HIGH)  digitalwrite(FAN, HIGH)" and you said logically it was not correct and the fan would stay on. You were right, that is what it did.  I was under the assumption that once the stat became low, that made the statement false, turning the fan off.  Now, in this new sketch, I have the function for HEAT. When the tstat closes, it goes into the heat function, and stays there even when the stat goes low. What am I doing wrong now?  oh, and I kinda got the map function figured out, just have to do some experimenting with the numbers and get it calibrated. Thanks Brian


Code: [Select]
#define TSTAT 12                               //OR.OR/W  (THERMOSTAT WIRE COLORS)
#define FAN 13                                 //BR.BR/W  (FAN RELAY WIRE COLORS)
#define TEMP 0                                 // BL.BL/W (COIL TEMP SENSOR WIRE COLORS)
#define PUMP 11                                //G.W      (PUMP CONTROL SSR WIRE COLORS)
#define LITE 10                                //WARNING LITE ON DURING "SHUTDOWN"
const long ONE_SECOND = 1000;                  //DEFINE 1 SECOND
const long ONE_MINUTE = 60 * ONE_SECOND;       //DEFINE 1 MINUTE
const long ONE_HOUR = 60 * ONE_MINUTE;         //DEFINE 1 HOUR
const long FIVE_MINUTES = 5 * ONE_MINUTE;      //DEFINE 5 MINUTES
int TS_STATE = LOW;                            //THERMOSTAT VARIABLE
int T = 0;                                     //RAW COIL TEMP VARIABLE
int temp = 0;

void setup()
{
 pinMode(TSTAT, INPUT);                       //THERMOSTAT STATE INPUT
 pinMode(FAN, OUTPUT);                        //FAN CONTROL RELAY OUTPUT
 pinMode(TEMP, INPUT);                        //COIL TEMP
 pinMode(PUMP, OUTPUT);                       //SSR PUMP CONTROL OUTPUT
 pinMode(LITE, OUTPUT);                       //WARNING LITE OUTPUT
 Serial.begin(9600);                          //OPEN SERIAL PORT (FOR DIAG. ONLY)
 
}

void loop()  
{
 temp = analogRead(TEMP);                         //READ TEMP SENSOR
 Serial.println(temp);                         //PRINT ACTUAL TEMP
 if (temp > 475)                               //IF COIL TEMP IS LESS THAN 125F
 {
  TEMP_CHECK();                                //GO TO: FUNCTION "TEMP CHECK"
 }
  else                                         //COIL TEMP GREATER THAN 125F
  {
 if ((temp < 475) && (TS_STATE == LOW))        //COIL TEMP GREATER THAN 125 AND THERMOSTAT NOT CALLING FOR HEAT
 {
   STAND_BY();                                 //GO TO: FUNCTION "STAND BY"
 }
 if ((temp < 475) && (TS_STATE == HIGH))       //COIL TEMP GREATER THAN 125F AND THERMOSTAT CALLING FOR HEAT
 {
   HEAT();                                     //GO TO: FUNCTION "HEAT"
 }
 if (temp > 475)                               //COIL TEMP LESS THAN 125F
 {
   SHUTDOWN();                                 //GO TO: FUNCTION "SHUTDOWN"
 }
  }
   
}
                                               //SHUTDOWN (COLD WATER)
                                     //-----------------------------------------
void SHUTDOWN()
{
 Serial.print("SHUTDOWN!!!");                 //PRINT "SHUTDOWN" TO SERIAL PORT FOR DIAG
 delay(ONE_SECOND);                           //DELAY 1 SECOND
 Serial.println(temp);                        //PRINT ACTUAL TEMP
 digitalWrite(PUMP, LOW);                     //TURN PUMP OFF
 digitalWrite(LITE, HIGH);                    //TURN WARNING LITE ON
 delay(ONE_HOUR);                             //DELAY 1 HOUR TO LET BOILER TEMP RISE ABOVE 125F
 return;                                      //RETURN TO LOOP
}

                                              // HEAT FUNCTION
                                    //-------------------------------------------
void HEAT()
{
 Serial.print("HEAT");                        // PRINT "HEAT"
 delay(ONE_SECOND);                           //DELAY 1 SECOND
 Serial.println(temp);                        //PRINT ACTUAL TEMP
 while (( TS_STATE == HIGH) && (temp < 475))  //IF THERMOSTAT CALLS FOR HEAT,
 {                                            //AND COIL IS HOT
   digitalWrite(FAN, HIGH);                   //TURN FAN ON
 }
 if ((TS_STATE == LOW) && ( temp < 475))      //IF NOT, TURN FAN OFF
 {
   digitalWrite(FAN, LOW);
   return;                                    //RETURN TO LOOP
 }

}
                                              //TEMP CHECK FUNCTION
                             //CHECK FOR HOT WATER (ON STARUP, AFTER SHUTDOWN)
                         //-------------------------------------------------------
                         
void TEMP_CHECK()
{
 Serial.print("TEMP CHECK");                 //SERIAL PRINT "TEMP CHECK" FOR DIAG
 delay(ONE_SECOND);                          //DELAY 1 SECOND
 Serial.println(temp);                       //PRINT ACTUAL TEMP
 digitalWrite(PUMP, HIGH);                   //TURN PUMP ON
 delay(FIVE_MINUTES);                        // WAIT FOR COIL TO GET HOT
 temp = analogRead(TEMP);                    //READ TEMP, HOT?
 if (temp < 475)                             //IF TEMP IS OVER 125F
 {
 return ;                                    //GO BACK TO LOOP
 }
 else                                        //IF NOT,
 {
   SHUTDOWN();                               //GO TO FUNCTION: SHUTDOWN
 }
}

                                            //STAND BY, WAIT FOR HEAT CALL
                                    //-------------------------------------------
               
void STAND_BY()
{
  digitalWrite(PUMP, HIGH);                 //TURN COOLANT PUMP ON
  Serial.print("STAND BY");                 //PRINT "STAND BY" FOR DIAG
  delay(ONE_SECOND);                        //DELAY 1 SECOND
  Serial.print(temp);                       //SERIAL PRINT MAPPED TEMP READING FOR DIAG
 TS_STATE = digitalRead(TSTAT);             //CHECK THERMOSTAT STATE
 temp = analogRead(TEMP);                   //READ TEMP
 if (TS_STATE == HIGH)                      // IF THERMOSTAT IS CALLING FOR HEAT
 {
   return;                                  //RETURN TO LOOP
 }
 if (temp > 475)                            //IF COIL TEMP IS LESS THAN 125F
 {
   SHUTDOWN();                              //GO TO FUNCTION: SHUTDOWN
 }
}

PaulS

In STAND_BY, you have this:
Code: [Select]
  Serial.print(temp);                       //SERIAL PRINT MAPPED TEMP READING FOR DIAG
 TS_STATE = digitalRead(TSTAT);             //CHECK THERMOSTAT STATE
 temp = analogRead(TEMP);                   //READ TEMP


Shouldn't the printing of temp come after the analogRead that values temp?

In loop, you have 4 if statements involving temp. I think that this could be simplified. You want to do something if temp is below 475, and something else if it isn't.

If temp is below 475, the action depends on the thermostat, so that requires another if test, in the else block.

If the thermostat is HIGH, you call HEAT, which seems a reasonable thing to do. In the HEAT function, you have blocks that depend on the value in TS_STATE, but in the HEAT function, the value of TS_STATE never changes, and HEAT is only called when TS_STATE is HIGH.

I would guess that you need to call digitalRead in this function, to see if the thermostat is saying "Enough already, it's roasting in here" (or something like that).



This is unrelated to your problem, but worth mentioning. Look at the paragraph above the one above this one. See anything strange? You can't tell, unless you are familiar with the code which capitalized words are function names and which are constants.

There is a convention that says that all capital letters are reserved for #define'd value (HIGH, LOW, INPUT, OUTPUT, etc.). Function names are generally all letters (no _), using either camelCase or PascalCase for naming. For instance, digitalRead or analogWrite are two word function names, while print and delay are one word names. Variable names are typically all lower case.

I'd encourage you to follow the convention, so parts of your code can be picked up quickly by other people.

deputyhiro

Got it, uploaded it, and i'll be damned.......it works. All functions work as designed. Thank you Paul and all who helped. I will post the final code with all mods.

deputyhiro

#19
Jan 30, 2010, 02:32 pm Last Edit: Jan 30, 2010, 02:33 pm by deputyhiro Reason: 1
Here is the finished, (working) product.......at least so far. Thanks again to all who helped.


Code: [Select]
#define TSTAT 12                               //OR.OR/W  (THERMOSTAT WIRE COLORS)
#define FAN 13                                 //BR.BR/W  (FAN RELAY WIRE COLORS)
#define TEMP 0                                 // BL.BL/W (COIL TEMP SENSOR WIRE COLORS)
#define PUMP 11                                //G.W      (PUMP CONTROL SSR WIRE COLORS)
#define LITE 10                                //WARNING LITE ON DURING "SHUTDOWN"
const long ONE_SECOND = 1000;                  //DEFINE 1 SECOND
const long ONE_MINUTE = 60 * ONE_SECOND;       //DEFINE 1 MINUTE
const long ONE_HOUR = 60 * ONE_MINUTE;         //DEFINE 1 HOUR
const long FIVE_MINUTES = 5 * ONE_MINUTE;      //DEFINE 5 MINUTES
int tsstate = LOW;                            //THERMOSTAT VARIABLE
int T = 0;                                     //RAW COIL TEMP VARIABLE
int temp = 0;

void setup()
{
 pinMode(TSTAT, INPUT);                       //THERMOSTAT STATE INPUT
 pinMode(FAN, OUTPUT);                        //FAN CONTROL RELAY OUTPUT
 pinMode(TEMP, INPUT);                        //COIL TEMP
 pinMode(PUMP, OUTPUT);                       //SSR PUMP CONTROL OUTPUT
 pinMode(LITE, OUTPUT);                       //WARNING LITE OUTPUT
 Serial.begin(9600);                          //OPEN SERIAL PORT (FOR DIAG. ONLY)
 
}

void loop()  
{
 tsstate = digitalRead(TSTAT);                 //READ THERMOSTAT STATE
 temp = analogRead(TEMP);                      //READ TEMP SENSOR
 Serial.println(temp);                         //PRINT ACTUAL TEMP
 delay(250);                                   //WAIT 1/4 SECOND SO SERIAL INFO IS NOT CRAMMED TOGETHER
 if (temp > 475)                               //IF COIL TEMP IS LESS THAN 125F
 {
  tempCheck();                                 //GO TO: FUNCTION "TEMP CHECK"
 }
                                           
                                           
 if (tsstate == HIGH)                          //THERMOSTAT CALLING FOR HEAT
 {
   heat();                                     //GO TO: FUNCTION heat
 }
 else                                           //COIL TEMP GREATER THAN 125F AND THERMOSTAT CALLING FOR HEAT
 {
   standBy();                                     //GO TO: FUNCTION standBy
 }
  }

                                               //SHUTDOWN (COLD WATER)
                                     //-----------------------------------------
void shutdown()
{
 Serial.println("SHUTDOWN!!!");                 //PRINT "SHUTDOWN" TO SERIAL PORT FOR DIAG
 delay(250);                                  //WAIT 1/4 SECOND
 temp = analogRead(TEMP);                     //READ TEMP SENSOR
 Serial.println(temp);                        //PRINT ACTUAL TEMP
 delay(250);                                  //WAIT 1/4 SECOND
 digitalWrite(PUMP, LOW);                     //TURN PUMP OFF
 digitalWrite(FAN, LOW);                      //TURN FAN OFF
 digitalWrite(LITE, HIGH);                    //TURN WARNING LITE ON
 delay(ONE_HOUR);                             //DELAY 1 HOUR TO LET BOILER TEMP RISE ABOVE 125F
 return;                                      //RETURN TO LOOP
}

                                              // HEAT FUNCTION
                                    //-------------------------------------------
void heat()
{
 Serial.println("HEAT");                        // PRINT "HEAT"
 delay(250);                                  //WAIT 1/4 SECOND
 temp = analogRead(TEMP);                     //READ TEMP SENSOR
 Serial.println(temp);                        //PRINT ACTUAL TEMP
 delay(250);                                  //WAIT 1/4 SECOND
 tsstate = digitalRead(TSTAT);                //READ THERMOSTAT STATE
 if (( tsstate == HIGH) && (temp < 475))      //IF THERMOSTAT CALLS FOR HEAT,
 {                                            //AND COIL IS HOT
   digitalWrite(FAN, HIGH);                   //TURN FAN ON
 }
 if ((tsstate == LOW) && (temp > 475))        //IF NOT, TURN FAN OFF
 {
   digitalWrite(FAN, LOW);
   return;                                    //RETURN TO LOOP
 }
 if (temp > 475)
 {
   tempCheck();
 }
}
                                              //TEMP CHECK FUNCTION
                             //CHECK FOR HOT WATER (ON STARUP, AFTER SHUTDOWN)
                         //-------------------------------------------------------
                         
void tempCheck()
{
 Serial.println("TEMP CHECK");                 //SERIAL PRINT "TEMP CHECK" FOR DIAG
 delay(250);                                 //WAIT 1/4 SECOND
 temp = analogRead(TEMP);                    //READ TEMP SENSOR
 Serial.println(temp);                       //PRINT ACTUAL TEMP
 delay(250);                                 //WAIT 1/4 SECOND
 digitalWrite(PUMP, HIGH);                   //TURN PUMP ON
 delay(FIVE_MINUTES);                        // WAIT FOR COIL TO GET HOT
 temp = analogRead(TEMP);                    //READ TEMP, HOT?
 if (temp < 475)                             //IF TEMP IS OVER 125F
 {
 return ;                                    //GO BACK TO LOOP
 }
 else                                        //IF NOT,
 {
   shutdown();                               //GO TO FUNCTION: shutdown
 }
}

                                            //STAND BY, WAIT FOR HEAT CALL
                                    //-------------------------------------------
               
void standBy()
{
  digitalWrite(PUMP, HIGH);                 //TURN COOLANT PUMP ON
  Serial.println("STAND BY");                 //PRINT "STAND BY" FOR DIAG
  delay(250);                               //WAIT 1/4 SECOND
  temp = analogRead(TEMP);                  //READ TEMP
  Serial.println(temp);                       //SERIAL PRINT MAPPED TEMP READING FOR DIAG
  delay(250);                               //WAIT 1/4 SECOND
  digitalWrite(FAN, LOW);
 tsstate = digitalRead(TSTAT);             //CHECK THERMOSTAT STATE
 if (tsstate == HIGH)                      // IF THERMOSTAT IS CALLING FOR HEAT
 {
   return;                                  //RETURN TO LOOP
 }
 if (temp > 475)                            //IF COIL TEMP IS LESS THAN 125F
 {
   tempCheck();                              //GO TO FUNCTION: tempCheck
 }
}

deputyhiro

#20
Jan 30, 2010, 03:02 pm Last Edit: Jan 30, 2010, 03:04 pm by deputyhiro Reason: 1
Here is the close to fininshed alternative. Paul when we first talked, I was writing a program that only turned the pump on when it called for heat. this last finished product Im sure you noticed the pump is on all the time as long as the water is hot. That is all fine, until the outside temp gets up into the mid 20s and 30s. So then I want to turn the pump off so I dont overheat the house....It will get into 78-80 range just from natual convection when that coil is hot. So for now, I run the 2 programs and when it gets  hot outside, (more efficient with the pump off/on) I upload 1 and when it gets cold outside, (it works more efficiently with the pump constantly on, Ive found) i do the other. this is the first year with this home made boiler and i am still learning its behaviors. Youre all thinking thats alot of work to, why not add an outdoor temp sensor and program it to do that on its own. I know.... That is the next step. Here is the code for the "warm weather" controller.  This one does have the map function in it, I am still working on the numbers.

Code: [Select]
#define TSTAT 12                           //OR.OR/W  (WIRE COLOR THERMOSTAT WIRING)
#define FAN 13                             //BR.BR/W  (WIRE COLOR FAN CONTROL RELAY)
#define TEMP 0                             // BL.BL/W (WIRE COLOR COIL TEMP SENSOR)
#define PUMP 11                            //G.W      (WIRE COLOR PUMP SSR)
#define LITE 10                            //SHUTDOWN WARNING LITE
const long ONE_SECOND = 1000;              //DEFINE ONE SECOND
const long ONE_MINUTE = 60 * ONE_SECOND;   //DEFINE ONE MINUTE
const long ONE_HOUR = 60 * ONE_MINUTE;     //DEFINE ONE HOUR

int T = 0;                                 //ANALOG READ TEMP
int temp = 0;                              //ACTUAL TEMP
int tstat = LOW;                           //THERMOSTAT STATE VARIABLE
void setup(){
 pinMode(TSTAT, INPUT);                   // THERMOSTAT INPUT
 pinMode(FAN, OUTPUT);                    //FAN RELAY OUTPUT
 pinMode(TEMP, INPUT);                    //COIL TEMP SENSOR
 pinMode(PUMP, OUTPUT);                   //PUMP SSR OUTPUT
 pinMode(LITE, OUTPUT);                   //WARNING LITE OUTPUT
 Serial.begin(9600);                      //OPEN SERIAL PORT
}

void loop(){
 temp = map(T, 0, 1023, 284, 43);
 tstat = digitalRead(TSTAT);               //READ THERMOSTAT
 delay(250);                               //WAIT 1/4 SECOND
 Serial.println(tstat);                    //PRINT THERMOSTAT STATE FOR DIAG
 delay(250);                               //WAIT 1/4 SECOND
 if (tstat == LOW)
 {                                         //IF THERMOSTAT IS LOW, NOT CALLING FOR HEAT
     digitalWrite(PUMP, LOW);              //TURN PUMP OFF
 }
 
 else                                      //IF THERMOSTAT IS HIGH, CALLING FOR HEAT
 {
     coilWarmup;                           //GO TO FUNCTION coilWarmup
 }
  }

                                                 //FUNCTION: shutdown
                          //FUNCTION IS RUN AFTER DETECTING COLD WATER FROM BOILER, SHUTS DOWN FOR 1 HOUR TO LET BOILER CATCH UP
 
void shutdown()        
   {  
     Serial.println("SHUTDOWN!");           //PRINTS SHUTDOWN TO SERIAL PORT FOR DIAG    
     digitalWrite(FAN, LOW);               //TURN FAN OFF
     digitalWrite(PUMP, LOW);              //TURN PUMP OFF
     digitalWrite(LITE, HIGH);             //TURN WARNING LITE ON
     delay(ONE_HOUR);                      //WAIT 1 HOUR FOR BOILER TO CATCH UP
     return;                               //GO BACK TO LOOP
   }
   
                                   
                                          //FUNCTION: coilWarmup
                           //RUNS PUMP FOR 5 MINUTES AND CHECKS FOR HOT WATER
void coilWarmup()    
  {
    digitalWrite(PUMP, HIGH);                            //TURN PUMP ON
    unsigned long T = millis();                          //RECORD TIME
    temp = analogRead(TEMP);                             //READ TEMP
  if (( millis() - T < 5 * ONE_MINUTE) && ( temp < 475)) //IF MORE THAN 5 MINUTES HAVE ELAPSED AND TEMP HAS REACHED 125, GO TO heat
  {
    heat;
  }
   else                                                  //IF COIL DOES NOT WARM UP IN 5 MINUTES, GO TO shutdown
   {
     shutdown;
   }
  }
 
 
                                           //FUNCTION: heat
void heat()
  {
    temp = analogRead(TEMP);             //READ TEMP
    Serial.println(temp);                //PRINT TEMP FOR DIAG
    delay(250);                          //WAIT 1/4 SECOND
    tstat = digitalRead(TSTAT);          //READ THERMOSTAT STATE
    if (tstat == HIGH)                   // IF THERMOSTAT CALLS FOR HEAT
    {
      digitalWrite(FAN, HIGH);           //TURN FAN ON
    }
    else                                 //IF THERMOSTAT DOESNT CALL FOR HEAT
    {
      digitalWrite(FAN, LOW);            //TURN FAN OFF
      digitalWrite(PUMP, LOW);
      return;
    }
    if  (temp > 475)                     //IF COIL TEMP DROPS BELOW 125 WHILE IN HEAT MODE, GO TO FUNCTION coilWarmup
    {
      coilWarmup;
    }
  }
   
 

PaulS

Until you get the outdoor temp sensor, you could just use a switch. If the switch is in the "it's cold out there" position, do the cold thing. If the switch is in the "Oh, what a beautiful day!" position, do the warm thing.

That way, you only need one sketch.

With modular code like you have now, it's much easier to implement these kind of changes.

When you get the outdoor temp sensor, it's easy to change the digitalRead to analogRead. The if test to determine mode will be of the form:

Code: [Select]
if(outdoorTemp >= someValue)

instead of

Code: [Select]
if(coldOutside == HIGH)

gedw99

if have noticed that a good way to decide if you are in summer or winter is to record the temperature over a period of say 2 weeks, and if the temperature is above 20 degrees for 1 week in those 2 weeks, then declare the system to be in summer.

But to do this you need state stored somewhere, and you only need to do this check once day.

gedw99

Hey All,

I am about to install fFCU ( Fan coil Units).
I am using these:
http://www.flaktwoods.eu/products/air-terminal-devices-and-ducts/fan-coils-chilled-water-cassette-perimeter-wall/satellite-qzsc

These have a 3 step Fan, and a 3 way valve for controlling water throughput.

SO, can anyone point me to the hardware aspects of doing this, rather than the software ??

gedw99 AT GMAIL dot COM

Go Up