[help needed] Thermostat Idea and Partial Code

Well, I've gotten a little more brave, and a little more (very little) skill in my hands, so i decided to dive in.

Mission:
Thermostat that has predetermined set points, high and low
Limits adjusted by pots not easily accessible (later to be replaced by wireless communication reprogram)
Minimum time above/below set points before activating HVAC
Minimum time for HVAC to run, but run until setpoint is passed for minimum amount of time
Reporting of current, max set, min set, and whichever of the following are relevant:
Time till activate heat (starts counting on overtemp)
time till activate cool (starts counting on undertemp)
time hvac running (obvious)
time till hvac shutdown (starts counting when between limits if hvac is on)

Current state:
Reporting current temp by ds18b20
Reporting min/max sets from pots
sending info to 20x4 LCD by serial+TTL inverter(PITA)

Current problem: (NEED HELP)
can't get LED's to turn on/off to simulate heat or cool state

Learning needed:
Don't know where to start to do the counting down stuff.

Please accept my apology for sloppy code with unnecessary pieces and commented out stuff, bad formatting, etc. it DOES compile and run up to this point, (except the LED simulators)

I welcome any and all help. I am very much a beginner, cobble hack and duct-tape kinda person. I want to learn, but i kinda need some of it in crayon.

Thanks everyone for all the help, on this and all the other stuff I've gotten help for.

Code that has gotten me this far: (scrounged from around the net and stitched/taped/wired/glued together)

#include <OneWire.h>

// DS18S20 Temperature chip i/o
OneWire ds(10);  // on pin 10
int heating = 7;
int cooling = 6;
void setup(void) {
  // initialize inputs/outputs
  // start serial port
  Serial.begin(9600);
  Serial.print(254, BYTE);
  Serial.print(1, BYTE);
pinMode(heating, OUTPUT);
pinMode(cooling, OUTPUT);
}

void loop(void) {

  
  byte i;
  byte present = 0;
  byte data[12];
  byte addr[8];
   int lowPin = 0;    // select the input pin for the low limit potentiometer
int highPin = 1;   // select the input pin for the high limit potentiometer
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract, nowtemp, maxtemp, mintemp, heatontime, heatwaittime, coolwaittime, coolontime, heating, cooling;
   maxtemp = analogRead(lowPin);
   mintemp = analogRead(highPin);
  //Standard read/report setup for Dallas 18B20

  if ( !ds.search(addr)) {
    //   Serial.print("No more addresses.\n");
    ds.reset_search();
    return;
  }

  //  Serial.print("R=");
  for( i = 0; i < 8; i++) {
    //    Serial.print(addr[i], HEX);
    //    Serial.print(" ");
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
    Serial.print("CRC is not valid!\n");
    return;
  }

  if ( addr[0] != 0x28) {
    Serial.print("Device is not a DS18S20 family device.\n");
    return;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);         // start conversion, with parasite power on at the end

  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.

  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  //  Serial.print("P=");
  //  Serial.print(present,HEX);
  //  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    //    Serial.print(data[i], HEX);
    //    Serial.print(" ");
  }
  // Serial.print(" CRC=");
  // Serial.print( OneWire::crc8( data, 8), HEX);
  // Serial.println();

  LowByte = data[0];
  HighByte = data[1];
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  if (SignBit) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }
  Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25

  Whole = Tc_100 / 100;  // separate off the whole and fractional portions
  Fract = Tc_100 % 100;
  //reporting done to LCD screen, 20x4
  line1();
  Serial.print("Temp Now= ");
  nowtemp = Tc_100 / 100;
  nowtemp = nowtemp*1.8+32;
  Serial.print(nowtemp);
  if (SignBit) // If its negative
  {
    Serial.print("-");
  }
  //Serial.print(Whole);
  //Serial.print(".");
  //if (Fract < 10)
  //{
  //  Serial.print("0");
  //}
  //Serial.print(Fract);

  // Serial.print("\n");
  Serial.print(" degrees");
  // end temp reporting

  // display the thermostat limits. note not editable at the report panel, only in code.  LCD is for convenience sake at the controller   box. 
  //set temperature trigger points for household heating/cooling kick on
  heatwaittime=300000; //time to wait after nowtemp < mintemp till heaton, if nowtemp remains < mintemp
  coolwaittime=300000; //time to wait after nowtemp > maxtemp  till coolon, if nowtemp remains > maxtemp
  heatontime=300000; // min time to run heater.  
  coolontime=300000; // min time to run AC. 
  
 maxtemp = maxtemp / 80 + 70; // convert to degF and set to acceptable range
  line3(); // report max limit set range
  Serial.print("Max Temp= ");
  Serial.print(maxtemp);
  Serial.print(" degrees");
  
 mintemp = mintemp / 80 + 60; // convert to degF and set to acceptable range
  line4(); // report min limit set range
  Serial.print("Min Temp= ");
  Serial.print(mintemp);
  Serial.print(" degrees");

  // compare the temperature reported to the set points
  // Notes on things to learn to do here:
  // EVERYTHING :( 

  // Notes on visualized steps
  // plain english description:
  //when temp goes 1° below minimum and stays for 10 minutes, heater comes on, and must stay on for at least 10 minutes and until the temp stays above minimum for 10 minutes
  //when temp goes 1° above maximum and stays for 10 minutes, AC comes on and must stay on for at least 10 minutes and until the temp stays above minimum for 10 minutes
  //Display will show current temp, minimum and maximum setpoints, and either the time till activation of heat/cool ( "Heat begins in 5:00" ) 
  //report the time remaining on the countdown till activating the heat/cool. when it is exhausted and the unit is running, Show how long the unit has been running. 
  //when the temp has held in the acceptable range for 10 minutes, display time to shutdown ( " 5:00 until AC Off " )

// relay activation section to turn on/off HVAC according to parameters. 
{
  if ( nowtemp > maxtemp );
    digitalWrite(heating, HIGH); 
}
{
  if ( nowtemp < maxtemp );
    digitalWrite(heating, LOW); 
}
{
  if (nowtemp < mintemp);
    digitalWrite(cooling, HIGH);
}
{
  if (nowtemp > mintemp);
    digitalWrite(cooling, LOW);
}
//line4(); 
//  Serial.print("Heat in: ");
//  Serial.print(heatwaittime);
//  Serial.print(heatontime);

//  line4(); //report the time remaining on the countdowns till activating the AC unit for overtemp
//  Serial.print("Cool in: ");
//  Serial.print(coolwaittime);
//  Serial.print(coolontime);


}




//  LCD  FUNCTIONS-- keep/edit the ones you need. 

// clear the LCD
void clearLCD(){
  Serial.print(254, BYTE);
  Serial.print(1, BYTE);
}

// go to line 1 start
void line1() { 
  Serial.print(254, BYTE);
  Serial.print(128, BYTE);
}

// go to line 2 start
void line2() { 
  Serial.print(254, BYTE);
  Serial.print(192, BYTE);
}

// go to line 3 start
void line3() { 
  Serial.print(254, BYTE);
  Serial.print(148, BYTE);
}

// go to line 4 start
void line4() { 
  Serial.print(254, BYTE);
  Serial.print(212, BYTE);
}

// move the cursor to the home position
void cursorHome(){
  Serial.print(254, BYTE);
  Serial.print(2, BYTE);
}


// move the cursor to a specific place
// e.g.: cursorSet(3,2) sets the cursor to x = 3 and y = 2
void cursorSet(int xpos, int ypos){  
  Serial.print(254, BYTE);
  Serial.print(71, BYTE);               
  Serial.print(xpos);   //Column position   
  Serial.print(ypos); //Row position 
} 


// backspace and erase previous character
void backSpace() { 
  Serial.print(8, BYTE); 
}


// move cursor left
void cursorLeft(){    
  Serial.print(254, BYTE); 
  Serial.print(76, BYTE);   
}


// move cursor right
void cursorRight(){
  Serial.print(254, BYTE); 
  Serial.print(77, BYTE);   
}


// set LCD contrast
void setContrast(int contrast){
  Serial.print(254, BYTE); 
  Serial.print(80, BYTE);   
  Serial.print(contrast);   
}


// turn on backlight 
void backlightOn(int minutes){
  Serial.print(254, BYTE); 
  Serial.print(66, BYTE);   
  Serial.print(minutes); // use 0 minutes to turn the backlight on indefinitely   
}


// turn off backlight
void backlightOff(){
  Serial.print(254, BYTE); 
  Serial.print(70, BYTE);   
}

I use an arduino to 'be a thermostat' but that is only one of the several things it does.

The thermostat bit is simple, it just turns a digital pin on or off to control my central heating boiler, I have no cooling facility, so it has just one set temperature, if the temp reported by the onewire thermometer is less than the set temp, it turns it on, if its more than the set temp it turns to off. It used to be more involved with making decsions based on on other factors like outside temperature and how log it had been running, it just increased the complexity, it didn't improve the heating system, so I went back to simple. The aruino is hooked up to a small server that (among other things) tells the arduino what temperature to maintain at what time of day and week.

You can take a look at the whole system here :

http://pluggy.is-a-geek.com/

Theres some old code and an out of date writeup linked from there you can peruse.

Yes, I remember seeing your thread. It is very interesting and innovative that you used the "drift" or "momentum" calculated to shut the boiler off and coast up to the temp, instead of cutting off at the limit and overshooting it. Here, our HVAC is all electric, so there isn't much momenum of change, and our insulation is very good, so it won't likely "bounce" much but i want to be sure it doesnt happen.

On for a minimum of 5 min, and temp past limit for min of 5 min before shutting off. how long between can be unlimited to reach the required limit. those are the parts I don't know how to code atm.

The simulation of simply turning heat/cool on and off according to the limits is puzzling me, I don't see a purpose that it isn't working. It should be simple, so the solution likely is as well. And simple baffles me. :smiley:

well, i've tried a dozen things, and none is improving matters. I am dead in the water...it's got to be something simple or i would have accidentally found it. anybody have any suggestions?

Our IT guy made some suggestions. He's not an ardu programmer, but good in the vb and c and all. Going to give this one a try.

#include <OneWire.h>

// DS18S20 Temperature chip i/o
OneWire ds(10);  // on pin 10
int heating = 7;
int cooling = 6;
void setup(void) {
  // initialize inputs/outputs
  // start serial port
  Serial.begin(9600);
  Serial.print(254, BYTE);
  Serial.print(1, BYTE);
pinMode(heating, OUTPUT);
pinMode(cooling, OUTPUT);
}

void loop(void) {

  
  byte i;
  byte present = 0;
  byte data[12];
  byte addr[8];
   int lowPin = 0;    // select the input pin for the low limit potentiometer
int highPin = 1;   // select the input pin for the high limit potentiometer
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract, nowtemp, maxtemp, mintemp, heatontime, heatwaittime, coolwaittime, coolontime, heating, cooling;
   maxtemp = analogRead(lowPin);
   mintemp = analogRead(highPin);
  //Standard read/report setup for Dallas 18B20

  if ( !ds.search(addr)) {
    //   Serial.print("No more addresses.\n");
    ds.reset_search();
    return;
  }

  //  Serial.print("R=");
  for( i = 0; i < 8; i++) {
    //    Serial.print(addr[i], HEX);
    //    Serial.print(" ");
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
    Serial.print("CRC is not valid!\n");
    return;
  }

  if ( addr[0] != 0x28) {
    Serial.print("Device is not a DS18S20 family device.\n");
    return;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);         // start conversion, with parasite power on at the end

  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.

  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  //  Serial.print("P=");
  //  Serial.print(present,HEX);
  //  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    //    Serial.print(data[i], HEX);
    //    Serial.print(" ");
  }
  // Serial.print(" CRC=");
  // Serial.print( OneWire::crc8( data, 8), HEX);
  // Serial.println();

  LowByte = data[0];
  HighByte = data[1];
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  if (SignBit) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }
  Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25

  Whole = Tc_100 / 100;  // separate off the whole and fractional portions
  Fract = Tc_100 % 100;
  //reporting done to LCD screen, 20x4
  line1();
  Serial.print("Temp Now= ");
  nowtemp = Tc_100 / 100;
  nowtemp = nowtemp*1.8+32;
  Serial.print(nowtemp);
  if (SignBit) // If its negative
  {
    Serial.print("-");
  }
  //Serial.print(Whole);
  //Serial.print(".");
  //if (Fract < 10)
  //{
  //  Serial.print("0");
  //}
  //Serial.print(Fract);

  // Serial.print("\n");
  Serial.print(" degrees");
  // end temp reporting

  // display the thermostat limits. note not editable at the report panel, only in code.  LCD is for convenience sake at the controller   box.
  //set temperature trigger points for household heating/cooling kick on
  heatwaittime=300000; //time to wait after nowtemp < mintemp till heaton, if nowtemp remains < mintemp
  coolwaittime=300000; //time to wait after nowtemp > maxtemp  till coolon, if nowtemp remains > maxtemp
  heatontime=300000; // min time to run heater.  
  coolontime=300000; // min time to run AC.
  
 maxtemp = maxtemp / 80 + 70; // convert to degF and set to acceptable range
  line3(); // report max limit set range
  Serial.print("Max Temp= ");
  Serial.print(maxtemp);
  Serial.print(" degrees");
  
 mintemp = mintemp / 80 + 60; // convert to degF and set to acceptable range
  line4(); // report min limit set range
  Serial.print("Min Temp= ");
  Serial.print(mintemp);
  Serial.print(" degrees");

  // compare the temperature reported to the set points
  // Notes on things to learn to do here:
  // EVERYTHING :(

  // Notes on visualized steps
  // plain english description:
  //when temp goes 1° below minimum and stays for 10 minutes, heater comes on, and must stay on for at least 10 minutes and until the temp stays above minimum for 10 minutes
  //when temp goes 1° above maximum and stays for 10 minutes, AC comes on and must stay on for at least 10 minutes and until the temp stays above minimum for 10 minutes
  //Display will show current temp, minimum and maximum setpoints, and either the time till activation of heat/cool ( "Heat begins in 5:00" )
  //report the time remaining on the countdown till activating the heat/cool. when it is exhausted and the unit is running, Show how long the unit has been running.
  //when the temp has held in the acceptable range for 10 minutes, display time to shutdown ( " 5:00 until AC Off " )

// relay activation section to turn on/off HVAC according to parameters.

  if ( nowtemp > maxtemp ){digitalWrite(heating, HIGH);}


  if ( nowtemp < maxtemp )
{
  digitalWrite(heating, LOW);
}

  if (nowtemp < mintemp)
{
  digitalWrite(cooling, HIGH);
}

  if (nowtemp > mintemp)
{
  digitalWrite(cooling, LOW);
}
//line4();
//  Serial.print("Heat in: ");
//  Serial.print(heatwaittime);
//  Serial.print(heatontime);

//  line4(); //report the time remaining on the countdowns till activating the AC unit for overtemp
//  Serial.print("Cool in: ");
//  Serial.print(coolwaittime);
//  Serial.print(coolontime);


}




//  LCD  FUNCTIONS-- keep/edit the ones you need.

// clear the LCD
void clearLCD(){
  Serial.print(254, BYTE);
  Serial.print(1, BYTE);
}

// go to line 1 start
void line1() {
  Serial.print(254, BYTE);
  Serial.print(128, BYTE);
}

// go to line 2 start
void line2() {
  Serial.print(254, BYTE);
  Serial.print(192, BYTE);
}

// go to line 3 start
void line3() {
  Serial.print(254, BYTE);
  Serial.print(148, BYTE);
}

// go to line 4 start
void line4() {
  Serial.print(254, BYTE);
  Serial.print(212, BYTE);
}

// move the cursor to the home position
void cursorHome(){
  Serial.print(254, BYTE);
  Serial.print(2, BYTE);
}


// move the cursor to a specific place
// e.g.: cursorSet(3,2) sets the cursor to x = 3 and y = 2
void cursorSet(int xpos, int ypos){  
  Serial.print(254, BYTE);
  Serial.print(71, BYTE);              
  Serial.print(xpos);   //Column position  
  Serial.print(ypos); //Row position
}


// backspace and erase previous character
void backSpace() {
  Serial.print(8, BYTE);
}


// move cursor left
void cursorLeft(){    
  Serial.print(254, BYTE);
  Serial.print(76, BYTE);  
}


// move cursor right
void cursorRight(){
  Serial.print(254, BYTE);
  Serial.print(77, BYTE);  
}


// set LCD contrast
void setContrast(int contrast){
  Serial.print(254, BYTE);
  Serial.print(80, BYTE);  
  Serial.print(contrast);  
}


// turn on backlight
void backlightOn(int minutes){
  Serial.print(254, BYTE);
  Serial.print(66, BYTE);  
  Serial.print(minutes); // use 0 minutes to turn the backlight on indefinitely  
}


// turn off backlight
void backlightOff(){
  Serial.print(254, BYTE);
  Serial.print(70, BYTE);  
}

Well, those changes didn't help any. I'm back to clueless.

One idea I used to stop rapid cycling was to just check the temp and do the swirching at say 5 minute intervals, it means if its on it runs for a minumum of 5 minutes and if its off it stays off for 5 minutes. This is an extract from an earlier version of my sketch, it might give you some ideas :

if (time >= fiveminloop){
    temphigh = tempch ;
    templow = tempch -1;
    fiveminloop = time + 300000;  
    if (tempin - tempout >= 160){ temphigh = tempch +1; }
    if (tempin >= temphigh){ digitalWrite(chrelayPin, LOW);      fiveminloop = time + 180000; heatingon = false; }
    if (tempin <= templow ){ digitalWrite(chrelayPin, HIGH); heatingon = true; }
   
  } // end fiveminloop

'time' is set earlier just as 'time=millis();

If your problem is simply that the simulation LEDs won't turn on/off then why not just just put a few serial.println in the code just before the if statements to show nowtemp,mintemp and maxtemp. This way you know if your math is right. If it is right there may be something wrong with the wiring of the LEDs. If that is the case switch one to Digital Pin 13 because the LED is already mounted on the board.