View Single Post
Old 03-09-12, 02:59 PM   #1172
Ko_deZ
Helper EcoRenovator
 
Join Date: Jun 2011
Location: Norway
Posts: 63
Thanks: 3
Thanked 10 Times in 10 Posts
Default Arduino code

Hi all

Sorry for the wait. I have only had an hour today, so I did not get to make it very nice or anything, but this should work. Tell me what you want in addition to this. If you do understand a little programming, then making changes to the switch/case thing in the loop function at the bottom should be quite easy. The pump relays could of course also be used to control fans for a water to air or air to air system. No de-icing implemented though. I would add an extra state (or case in the main switch/case part) that has a 5 minute delay and turns off everything except an external deicing heater during this period. Easily done if someone wants it.


This is what you need to do for temperature sensors:

For X number of sensors you need:
2 1N914 diodes
X LM35
X 18kOhm resistors

And some whire. Standard twisted pair or a coaxial cable or whatever you like. If the cable is very long ( > 10 meters ), I would add a small capacitor across the sensor and between output signal and ground all the way out by the sensor, as well as one between ground and signal at the arduino, just to remove any noise that is picked up along the way.

LM35 - Precision Centigrade Temperature Sensor

There are loads of differenty types of temperature sensors, but this one is very easy to use. Also, it gives you a quite accurate temperature range of -55C to +150C. Unfortunately the resolution is not very good, but it is more than good enough for our use.

For the output relays, you need to do like this:

http://www.arduino.cc/playground/upl...ing/relays.pdf

You can use any digital output except 1,2 and 13. I use 13 as a status diode thingy. You will see in the code comments. It is on for either 1, 2, 3 or 4 seconds in a 5 second period to indicate which state it is in.
If you wonder why A0 is connected to the two diodes, that is to get an input reference, as this temperature sensor gives an output signal that is 0V compared to ground at 0C, and 10mV up or down is one C. Analog input 0 will be reference voltage for the temperature sensors. You also get these with Farenheit I believe, in that case, some of the numbers must be changed. Get the Celcius, it is the logical way of measuring temperature anyway

The text at the start should explain most of it. I did leave out a few settings, and I don't utilize the indoor and outdoor temperature. I just left the readings in there so that you could add the probes and get a reading on the serial interface.

WARNING: NOT TESTED IN REAL LIFE!
I did do some simple testing here with a breadboard, but that is the complete extent of it.

Allright, here is the code:
Code:
/* First some legal mumbo jumbo:

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.


 * This is a crude implementation for a state for controlling a
 * ground souce heat pump machine.
 *
 * Written by Morgan Tørvolt <morgan@torvolt.com>.
 *
 * Analog inputs:
 *
 * T1 - indoor temperature, connects to A1
 * T2 - outdoor temperature, connects to A2
 * T3 - accumulator tank temperature, connects to A3
 * T4 - ground loop temperature out, connects to A4
 *
 * Digital outputs:
 *
 * D3 - Relay for ground loop water pump
 * D4 - Relay for warm side water loop to accumulator tank
 * D5 - Relay for starting the heat pump
 *
 * Defined settings for temperatures and such. Set those below this comment section
 *
 * TEMP_TYPE    : CELCIUS or FARENHEIT
 * TEMP_START   : T3 temperature for when the HP should start
 * TEMP_STOP    : T3 temperature for when the HP should stop
 * TEMP_SHUTOFF : T4 temperature that is critically
 *                cold (freezing) and the HP should stop
 * DELAY_BOOT   : Time to wait when powering up in seconds
 * DELAY_START  : How long to run the water pumps before turning
 *                on the HP in seconds
 *
 * State 0: All off
 *   Wait 2 minutes before doing anything. Blink diode 1 second on and 1 second off
 *   Go to state 1 after two minutes
 * State 1:
 *   If T3 < TEMP_START, go to state 2
 *   Blink diode on 2 sek, off 1 sek
 * State 2:
 *   Turn on D3 and D4 (start water pumps), leave D5 off (HP)
 *   Wait for 2 minutes, then go to state 3
 * State 3:
 *   If T4 > TEMP_SHUTOFF and T3 < TEMP_STOP, leave HP and water pumps running using D3, D4 and D5
 *   If T4 < TEMP_SHUTOFF or T3 > TEMP_STOP, jump to state 1
 *
 */

enum { CELCIUS, FARENHEIT };

#define TEMP_TYPE       CELCIUS
#define TEMP_START      40
#define TEMP_STOP       50
#define TEMP_SHUTOFF    1
#define DELAY_BOOT      120
#define DELAY_START     120

// General program code. Go further down
// if you don't want to know what is going on
// in the background

void blinkDiode( int on, int period )
{
  if( ( ( millis() / 1000 ) % period ) < on )
  {
    digitalWrite( 13, HIGH );
  }
  else
  {
    digitalWrite( 13, LOW );
  }
}

float getTemperature( int input )
{
  int raw = static_cast< int >( analogRead( input ) ) - static_cast< int >( analogRead( A0 ) );
  switch( TEMP_TYPE )
  {
  case CELCIUS:
    // 1024 states across 5V gives 4.8828 mV per step. For celcius, 10 mV = 1C, so we multiply by 0.48828 to get celcius
    return raw * 0.48828;
  case FARENHEIT:
    // °F = (°C × 9/5) + 32
    return ( raw * 0.8789 ) + 32;
  }
  // This should never happen
  return 0;
}

void setOutputs( int output_3, int output_4, int output_5 )
{
    digitalWrite( 3, output_3 );
    digitalWrite( 4, output_4 );
    digitalWrite( 5, output_5 );
}

void setup()
{
  // declare all digital pins as output pins:
  for( int i = 2; i <= 13; ++i )
  {
    pinMode( i, OUTPUT );
    digitalWrite( i, LOW );
  }

  Serial.begin( 9600 );
}

int           state      = 0;   // We start in state 0
unsigned long waitUntil  = 0;
bool          diodeState = 0;

 void loop()
{
  delay( 50 ); // No need to rush things, and also make sure we don't overflow the serial interface
  Serial.print( "State: " );
  Serial.print( state );
  Serial.print( " Temps: " );
  Serial.print( getTemperature( A1 ) );
  Serial.print( " " );
  Serial.print( getTemperature( A2 ) );
  Serial.print( " " );
  Serial.print( getTemperature( A3 ) );
  Serial.print( " " );
  Serial.println( getTemperature( A4 ) );
  switch( state )
  {
  case 0:
    setOutputs( LOW, LOW, LOW );
    if( millis() > DELAY_BOOT*1000 )
    {
      state = 1;
    }
    blinkDiode( 1, 5 ); // on 1 of 5 seconds
    break;
  case 1:
    setOutputs( LOW, LOW, LOW );
    if( getTemperature( A3 ) < TEMP_START )
    {
      waitUntil = millis() + DELAY_START * 1000;
      state = 2;
    }
    blinkDiode( 2, 5 ); // on 2 of 5 seconds
    break;
  case 2:
    setOutputs( HIGH, HIGH, LOW );
    if( millis() > waitUntil && millis() - waitUntil < 20000 ) // Just making sure that things does not get screwed up when the unsigned long overflows.
    {
      state = 3;
    }
    blinkDiode( 3, 5 ); // on 3 of 5 seconds
    break;
  case 3:
    setOutputs( HIGH, HIGH, HIGH );
    if( getTemperature( A3 ) > TEMP_STOP || getTemperature( A4 ) < TEMP_SHUTOFF )
    {
      state = 1;
    }
    blinkDiode( 4, 5 ); // on 4 of 5 seconds
    break;
  }
}
Ko_deZ is offline   Reply With Quote
The Following User Says Thank You to Ko_deZ For This Useful Post:
buffalobillpatrick (03-24-14)