Temperature control chamber programming

I while back I asked design advice for a temperature control chamber.http://forum.arduino.cc/index.php?topic=268476.0

I have got to the point where I try to create the code that could actually run it and I am finding it fairly difficult.

I have tried to get tings working step by step but as code get longer problems are becoming more frequent. So I will do my best to describe what I want the chamber to to and what hardware I am using.

Temperature chamber intended features:

Keeps chamber temperature close to set value using sensor feedback.
Two relays are used to switch Peltier device. H-bridge configuration allows to switch polarity. If Peltier is cooling then blue LED lights up and if heating then orange LED lights up.
(These LEDs are not controlled by the microcontroller. They are simply connected to Peltier wires with series resistors and diodes.)
Two DS18B20 sensors are used to monitor chamber temperature and their values are averaged.
Running ~5 second average (10 readings) is defined to be chamber temperature.

Knob is used to select target temperature.
Turning this knob overrides temporarily current LCD screen mode and displays knob value and target temperature. After knob has been idle for 3 seconds, previous screen mode returns.
During these 3 seconds the screen mode cycle/scroll button should still work, to force screen change if so desired.

Button press stores target temperature and signals device to pursue and maintain that value.
Also this target temperature is written on to SD card and reused on next startup.

Green LED indicates that mean chamber temperature matches target value within allowed offset margin of 0.5 degrees C (or alternatively red LED indicates mismatch).

By default LCD displays status information (target temp., measured temp.)

Screen also can display: ambient temperature, outside heat sink temperature, inside heat sink temperature, date and time, measured temperature offset, temperature selection knob value, possibly some error messages (eg. SD card not detected)
(Button is used to cycle/scroll between LCD screen modes)

Sensor values with timestamps are logged to SD card (important when trying to develop temperature control algorythm and test the unit).

Saftey features:
As pointed out in previous thread, quickly switching Perltier element polarity could damage the unit due to overheating (can`t pump through the extra heat contained in the still hot heat sink).
This issue could be solved either by introducing a cooldown timer or by monitoring the heatsink temperatures and allowing to switch only if the hot heatsink has cooled to some acceptible temperature (the latter seems the more refined option).

General overheating protection will cut the power to Peltier device if either heatsink temperature reaches over 120* C.

Hardware part is somewhat described in the other thread (first link) but I will add it here as well for easier reading.

Old computer PSU to provide low voltage high current DC;
TEC1-12715 thermoelectric element;
CoolerMaster CPU cooler for outside heat sink;
Aluminum heat sink with fan inside the chamber;
plywood and Styrofoam as chamber walls and insulation;
Arduino nano as cotroller;
Relay module with two 10A relays to switch on and reverse polarity of TEC1-12715;
SD card module to log data;
RTC module DS3231 to keep accurate time;
5 DALLAS DS18B20 sensors for temperature monitoring (one for ambient, two for chamber and one on each heat sink);
Standard 16x2 blue back-light LCD screen;
10k pot to adjust LCD contrast;
10k pot to select target temperature;
Push-button NO switch to store selected temperature connected to analog only pin that is pulled low with 9.1k resistor and will pull pin to 5V when button is pressed;
Push-button NO switch to cycle/scroll LCD screen (I need to enable internal pull-up for that) that will pull pin logic low when pressed.

Things are connected to NANO board as shown in table (attachment) using wires. No wire is longer than 30 cm and most are much shorter.

Pinout.png

Could not fit all in one post. Continued:

I will post the code I have so far. Many things are still missing.

#include <LiquidCrystal.h> //LCD library
#include <SD.h>            //SD card library
//#include <Time.h> 
//#include <TimeAlarms.h>
//#include <Wire.h>
//#include <DS1307RTC.h>
#include <OneWire.h>             //One wire library. Beeded for temperature sensors.   
#include <DallasTemperature.h>   //Dallas temperature sensor library
#include <PWM.h>                 //PWM frequency control library downloaded from:   //http://code.google.com/p/arduino-pwm-frequency-library/downloads/list

//LCD#########
LiquidCrystal lcd(9, 8, 4, 5, 6, 7) ;  //declares LCD pins
//############
const int StoreTempPin = A6;           //declare
const int AdjustTempPin = A7;
  int AdjustTempValue; //declares variable for analog input
  int SetTempTarget;   //declares variable for mapped temperature value
  int StoreTempButton;      //declares variable for analog button input
  int TargetTemp = 22 ;    //declares variable for terget temperature. Default 22°C.
File myFile;

//Inside heatsink air mixing fan speed control#######
byte fanPin = 3;               // the pin that the fan control wire is connected to
  byte fanSpeed = 95;            // how fast fan runs (from 0 to 255). Uses fixed speed.
  int frequency = 25000;     // PWM frequency. Fan need 25kHz.
//###################################################
//One wire/Dallas temperature sensor setup######
OneWire oneWire(2); //declares one wire pin
DallasTemperature sensors(&oneWire);
    const byte RavgSize = 10; // set running average array size
    float InHeatsinkTemp;    //variable for Inside heatsink temperature
    float OutHeatsinkTemp;   //variable for Outside heatsink temperature
    float ChamberTemp_1;     //variable for Chamber probe 1 temperature
    float ChamberTemp_2;     //variable for Chamber probe 2 temperature
    float AmbientTemp;       //variable for Ambient temperature

//#########################################



void setup() {
  
  Serial.begin(9600); // start serial port
  //DS18b20###########
  sensors.begin();            // start up DallasTemperature library
  sensors.setResolution(10);  // set sensor resolution (10 bit should be good compromise between resolution and read speed)
  //##################
  //LCD
  lcd.begin(16, 2);      // initialise LCD (n colums, n rows)
  lcd.clear();        // clear just in case
  //
  //SD card #####################
  if (!SD.begin(10)) {
    Serial.println("SD init. failed!");
    return;
  }
  //Create file header
  Serial.println("SD init. OK!");
  myFile = SD.open("chamber.txt", FILE_WRITE);    //open file
    if (myFile) {
    myFile.println("Temperature sensors: DS1820");
    myFile.println("RTC: DS3231");
    myFile.println(" ");
    myFile.print("Time");
    myFile.print("\t");
    myFile.print("\t");
    myFile.print("\t");
    myFile.print("Ambient");
    myFile.print("\t");
    myFile.print("OutHeatsink");
    myFile.print("\t");
    myFile.print("InHeatsink");
    myFile.print("\t");
    myFile.print("Probe_1");
    myFile.print("\t");
    myFile.print("Probe_2");
    myFile.print("\t");
    myFile.print("Average");  //Average of Probe_1 and Probe_2
    myFile.print("\t");
    myFile.print("ChamberTemp");  //running 10 measurement average temperature calculated from Average
    myFile.print("\t");
    myFile.print("TargetTemp");
    myFile.print("\t");
    myFile.print("Temp.Offset");
	
    myFile.close(); // close file
    
  } else {
    // if the file didn't open, print an error:
    lcd.print("Error opening chamber.txt");
  }
  //##########################
  //Fan speed control #########
   //initialize all timers except for 0, to save time keeping functions
  InitTimersSafe(); 

  //sets the frequency for the specified pin
  bool success = SetPinFrequencySafe(fanPin, frequency);
  
  //if the pin frequency was set successfully, turn pin 13 on
  if(success) {
    pinMode(3, OUTPUT);
    digitalWrite(3, HIGH);    
  }
  //##########################
 }





void loop () {
  
  pwmWrite(fanPin, fanSpeed); // Fan Speed
  
  StoreTempButton = analogRead(StoreTempPin);    //read analog button state value (normally open = 0)
  AdjustTempValue = analogRead(AdjustTempPin);   //read potentiometer value
  //If statement to store target temperature from mapped value. 
  //If button is pressed new mapped temperature value is stored, otherwise previous value is used.
  if(StoreTempButton >100) {
    TargetTemp = SetTempTarget;
    TargetTemp = TargetTemp;
  }
  
  lcd.setCursor(0,0);        
  lcd.print("Set target: ");
  SetTempTarget = map(AdjustTempValue, 0, 1023, -5, 50);
  lcd.print(SetTempTarget); 
  if(-1 < SetTempTarget <= 10) {   //needed to avoid displaying trailing 0 for one digit values
    lcd.print(" ");                //
    lcd.setCursor(14,0);           //
  }
  lcd.print((char)223); lcd.print("C");
  lcd.setCursor(0,1);
  lcd.print("TargetTemp: ");
  lcd.print(TargetTemp); 
  if(-1 < TargetTemp <= 10) {     //needed to avoid displaying trailing 0 for one digit values
    lcd.print(" ");               //
    lcd.setCursor(14,1);          //
  }
  lcd.print((char)223); lcd.print("C");
  
  //temperature
    InHeatsinkTemp = sensors.getTempCByIndex(0);
    OutHeatsinkTemp = sensors.getTempCByIndex(1);
    ChamberTemp_1 = sensors.getTempCByIndex(2);
    ChamberTemp_2 = sensors.getTempCByIndex(3);
    AmbientTemp = sensors.getTempCByIndex(4);
    float Average = (ChamberTemp_1+ChamberTemp_2)/2;
    
    Serial.print(InHeatsinkTemp);
    Serial.print("\t");
    Serial.print("\t");
    Serial.print(OutHeatsinkTemp);
    Serial.print("\t");
    Serial.print("\t");
    Serial.print(ChamberTemp_1);
    Serial.print("\t");
    Serial.print("\t");
    Serial.print(ChamberTemp_2);
    Serial.print("\t");
    Serial.print("\t");
    Serial.print(Average);
    Serial.print("\t");
    Serial.print("\t");
    Serial.print(runningAverage(Average));
    Serial.print("\t");
    Serial.print("\t");
    Serial.println(AmbientTemp);
  
  delay(100);
  
}

//function to calculate running average
float runningAverage(float Average) 
{
  static float LM[RavgSize];      // Last 10 measurements
  static byte index = 0;
  static float sum = 0;
  static byte count = 0;
  
  // keep sum updated to improve speed.
  sum -= LM[index];
  sum += LM[index++] = Average;
  index = index % RavgSize;
  if (count < RavgSize) count++;

  return sum / count;
}

The code compiles but temperature readings stopped working after I added running average part. See also this post:

I started with the temperature selection knob part and added more stuff. I was happy with the temperature selection knob and button at first, but as the code got longer I had to keep the button pressed down longer and longer for it to store the temperature. At first only a short press was needed and in the end I had to press it for about half a second or more.

I fear that I might waste too much time trying to get individual elements working and then realizing that after putting it together it fails to perform.

Hopefully experienced programmers will have a more wider vision and understanding how this temperature control chamber software should be built to work.

Should this be in Gigs and Collaboration? You haven't described what is missing.

thanks for writing a big story.

First thing no one read your complete problem. you need to be more specific.

I recommend individually test your code first step by step. adding each sensor one after the other.
your code is incomplete. if you adding some library you also need to share us link from where you downloaded .

when i compile code; error i got

BMP085test.cpp: In function ‘void setup()’:
BMP085test:94: error: ‘InitTimersSafe’ was not declared in this scope
BMP085test:97: error: ‘SetPinFrequencySafe’ was not declared in this scope
BMP085test.cpp: In function ‘void loop()’:
BMP085test:113: error: ‘pwmWrite’ was not declared in this scope

which some functions are absent.

also check your flash memory utization for code.

I never bother with the sort of averaging scheme that you are using. With your scheme, you get a blip if there is an unusual reading, and another blip ten iterations later, when you overwrite it.

I usually use a formula more like

runningAverage = ( 0.9 * runningAverage ) + (0.1 * latestReading );

You probably don’t need to read the temperature so often. Once every 30 seconds is probably often enough.

You call that runningAverage( ) function inside your print function, but you don’t keep the result, it’s hard to see how your control algorithm will work without it.

PaulS: Should this be in Gigs and Collaboration? You haven't described what is missing.

I will be more precise what still needs to be added:

Different LCD screen modes (code has only one at the moment). Two things can fit on screen at most so I will need to have 5 screen modes that can be cycled through with the button. The fifth button press then gets you back to the first screen. I do not know how to make the screen cycling work. I don not know how to make the temperature selection screen come up when the knob is turned and have it stay for 3 seconds after knob has been idle.

Storing last used target temperature to SD card and reading it back during next start-up and using it.

I have done a data-logger before so writing values to SD card I think I can manage (just wanted to get right values to write first). Same with time-stamps.

Temperature control algorithm is also missing. When to switch the relays essentially. Probably needs a lot of trial and error.

Overheating protection. Probably just some if statement? The temperature sensors need to work first.

Indicator LED. This should be a simple if statement.

And general code optimization as well. Ideally I would not like to have any pure delay() function.

AMPS-N:
thanks for writing a big story.

First thing no one read your complete problem. you need to be more specific.

I recommend individually test your code first step by step. adding each sensor one after the other.
your code is incomplete. if you adding some library you also need to share us link from where you downloaded .

when i compile code; error i got
which some functions are absent.

also check your flash memory utization for code.

The problem is that the temperature sensors work with this code:

#include <OneWire.h>
#include <DallasTemperature.h>


OneWire oneWire(2);
DallasTemperature sensors(&oneWire);
    const byte RavgSize = 10;
    float InHeatsinkTemp;
    float OutHeatsinkTemp;
    float ChamberTemp_1;
    float ChamberTemp_2;
    float AmbientTemp;
    

void setup()
{
Serial.begin(9600);
sensors.begin();
sensors.setResolution(10);
}

void loop()

{
    sensors.requestTemperatures();

    InHeatsinkTemp = sensors.getTempCByIndex(0);
    OutHeatsinkTemp = sensors.getTempCByIndex(1);
    ChamberTemp_1 = sensors.getTempCByIndex(2);
    ChamberTemp_2 = sensors.getTempCByIndex(3);
    AmbientTemp = sensors.getTempCByIndex(4);
    float Average = (ChamberTemp_1+ChamberTemp_2)/2;
    
    Serial.print(InHeatsinkTemp);
    Serial.print("\t");
    Serial.print("\t");
    Serial.print(OutHeatsinkTemp);
    Serial.print("\t");
    Serial.print("\t");
    Serial.print(ChamberTemp_1);
    Serial.print("\t");
    Serial.print("\t");
    Serial.print(ChamberTemp_2);
    Serial.print("\t");
    Serial.print("\t");
    Serial.print(Average);
    Serial.print("\t");
    Serial.print("\t");
    Serial.print(runningAverage(Average));
    Serial.print("\t");
    Serial.print("\t");
    Serial.println(AmbientTemp);
}

float runningAverage(float Average)
{
  static float LM[RavgSize];      // LastMeasurements
  static byte index = 0;
  static float sum = 0;
  static byte count = 0;
  
  // keep sum updated to improve speed.
  sum -= LM[index];
  sum += LM[index++] = Average;
  index = index % RavgSize;
  if (count < RavgSize) count++;

  return sum / count;
}

But when I added that averaging to my other code then it does not work anymore. It was working in the longer code without the averaging function. Code compiles and uploads but all sensors show some different fixed temperatures. Almost like they make the firs reading and get stuck or something.

Also I noticed that when I started the longer code today it was displaying 85 degrees C on all sensors but when I uploaded the temperatures only code (above) then they started working and when after that I uploaded the longer code again then the sensors are stuck with these other values and do not change:

22.75 22.00 23.50 23.25 23.37 23.37 23.25
22.75 22.00 23.50 23.25 23.37 23.37 23.25
22.75 22.00 23.50 23.25 23.37 23.37 23.25
22.75 22.00 23.50 23.25 23.37 23.37 23.25
22.75 22.00 23.50 23.25 23.37 23.37 23.25
22.75 22.00 23.50 23.25 23.37 23.37 23.25
22.75 22.00 23.50 23.25 23.37 23.37

I also added the PWM library download link (it is the latest version in that page).

The memory usage for the longer code is 22,544 bytes out of 30k available.

michinyon: I never bother with the sort of averaging scheme that you are using. With your scheme, you get a blip if there is an unusual reading, and another blip ten iterations later, when you overwrite it.

I usually use a formula more like

runningAverage = ( 0.9 * runningAverage ) + (0.1 * latestReading );

You probably don't need to read the temperature so often. Once every 30 seconds is probably often enough.

You call that runningAverage( ) function inside your print function, but you don't keep the result, it's hard to see how your control algorithm will work without it.

My chamber volume is about 140 cubic inches. So very small and changes can be quick. So I want to read temperatures more often.

Also for overheating protection. If something malfunctions (for example somebody jams something in the heat sink fan and it stalls) then 30 seconds after everything could be cooked already.

Could I also call the runningAverage( ) function whenever I need to and not store the value?

I might try to add some filter to reject unusual sensor readings if they become a problem.

So very small and changes can be quick.

And you are using a Peltier device ?

Could I also call the runningAverage( ) function whenever I need to and not store the value?

Well, no. If you don't want to store the value, you then have the problem that if you call the method once for the display, and once for the temperature control, you have to give it a new temperature value, and discard an old one, each time.

If you don't want to keep the value when you retrieve it, you really need two functions. One to stick a new sample into the averaging array, and one to get the average value out.

Also I noticed that when I started the longer code today it was displaying 85 degrees C on all sensors

85 seems to be a number people habitually get, when the one-wire communication is not actually working.

I suspect you have a memory capacity problem.

You should check each number that you receive, and discard it if it is unreasonable.

I have a lot of these devices, and it will be working fine, and then you get one bad reading for no reason, and then it is good again. You need to anticipate that.

michinyon: 85 seems to be a number people habitually get, when the one-wire communication is not actually working.

I suspect you have a memory capacity problem.

Well after trying to build the code up again piece by piece to find the point when it malfunctions, I found that one apparently important line was missing:

sensors.requestTemperatures();

Doh.. No wonder temperatures were not updating when sensors were not asked to provide new values.

Now it started working and memory capacity is not a problem (not yet at least).

These 85 degree values have not popped up also anymore.

What I did notice was that when the code is running, the LCD text is dim. Reddish almost. But when code is not running, like during code upload, then text becomes bright white again. I thin it should always be white. Any idea about this?

What I did notice was that when the code is running, the LCD text is dim.

The code you modified but didn't re-post?

PaulS:
The code you modified but didn’t re-post?

Actually the dim text issue has magically solved itself…? Weird. Hopefully does not happen again.

The current code is this:

#include <LiquidCrystal.h> //LCD library
#include <SD.h>            //SD card library
//#include <Time.h> 
//#include <TimeAlarms.h>
//#include <Wire.h>
//#include <DS1307RTC.h>
#include <OneWire.h>             //One wire library. Needed for temperature sensors.   
#include <DallasTemperature.h>   //Dallas temperature sensor library
#include <PWM.h>                 //PWM frequency control library http://code.google.com/p/arduino-pwm-frequency-library/downloads/list

//LCD#########
LiquidCrystal lcd(9, 8, 4, 5, 6, 7) ;  //declares LCD pins
//############
const byte Relay_1 = A0;           //declare 
const byte Relay_2 = A1;
const byte StoreTempPin = A6;   //declare temperature storage button pin (connected to button leg)
const byte AdjustTempPin = A7;  //declare temperature selection pot pin (connected to potentiometer wiper)
 int AdjustTempValue; //declares variable for analog input
 int SetTempTarget;   //declares variable for mapped temperature value
 int StoreTempButton;      //declares variable for analog button input
 int TargetTemp = 22 ;    //declares variable for terget temperature. Default 22°C.
 
File myFile;

//Inside heatsink air mixing fan speed control#######
const byte fanPin = 3;               // the pin that the fan control wire is connected to
 byte fanSpeed = 95;            // how fast fan runs (from 0 to 255). Uses fixed speed.
 const int frequency = 25000;     // PWM frequency. Fan need 25kHz.
//###################################################
//One wire/Dallas temperature sensor setup######
OneWire oneWire(2); //declares one wire pin
DallasTemperature sensors(&oneWire);
   const byte RavgSize = 10; // set running average array size (onedimentional)
   float InHeatsinkTemp;    //variable for Inside heatsink temperature
   float OutHeatsinkTemp;   //variable for Outside heatsink temperature
   float ChamberTemp_1;     //variable for Chamber probe 1 temperature
   float ChamberTemp_2;     //variable for Chamber probe 2 temperature
   float AmbientTemp;       //variable for Ambient temperature
//#########################################



void setup() {
 
 Serial.begin(9600); // start serial port
 //DS18b20###########
 sensors.begin();            // start up DallasTemperature library
 sensors.setResolution(10);  // set sensor resolution (10 bit should be good compromise between resolution and read speed)
 //##################
 //LCD
 lcd.begin(16, 2);      // initialise LCD (n colums, n rows)
 lcd.clear();        // clear just in case
 //
 //SD card #####################
 if (!SD.begin(10)) {
   Serial.println("SD init. failed!");
   return;
 }
 //Create file header
 Serial.println("SD init. OK!");
 myFile = SD.open("chamber.txt", FILE_WRITE);    //open file
   if (myFile) {
   myFile.println("Temperature sensors: DS1820");
   myFile.println("RTC: DS3231");
   myFile.println(" ");
   myFile.print("Time");
   myFile.print("\t");
   myFile.print("\t");
   myFile.print("\t");
   myFile.print("Ambient");
   myFile.print("\t");
   myFile.print("OutHeatsink");
   myFile.print("\t");
   myFile.print("InHeatsink");
   myFile.print("\t");
   myFile.print("Probe_1");
   myFile.print("\t");
   myFile.print("Probe_2");
   myFile.print("\t");
   myFile.print("Average");  //Average of Probe_1 and Probe_2
   myFile.print("\t");
   myFile.print("ChamberTemp");  //running 10 measurement average temperature calculated from Average
   myFile.print("\t");
   myFile.print("TargetTemp");
   myFile.print("\t");
   myFile.print("Temp.Offset");

   myFile.close(); // close file
   
 } else {
   // if the file didn't open, print an error:
   lcd.print("Error opening chamber.txt");
 }
 //##########################
 //Fan speed control #########
  //initialize all timers except for 0, to save time keeping functions
 InitTimersSafe(); 

 //sets the frequency for the specified pin
 bool success = SetPinFrequencySafe(fanPin, frequency);
 
 //if the pin frequency was set successfully, turn pin 13 on
 if(success) {
   pinMode(3, OUTPUT);
   digitalWrite(3, HIGH);    
 }
 //##########################
}





void loop () {
 
 pwmWrite(fanPin, fanSpeed); // Fan Speed
 
 StoreTempButton = analogRead(StoreTempPin);    //read analog button state value (normally open = 0)
 AdjustTempValue = analogRead(AdjustTempPin);   //read potentiometer value
 //If statement to store target temperature from mapped value. 
 //If button is pressed new mapped temperature value is stored, otherwise previous value is used.
 if(StoreTempButton >100) {
   TargetTemp = SetTempTarget;
 }
 
 lcd.setCursor(0,0);        
 lcd.print("Set target: ");
 SetTempTarget = map(AdjustTempValue, 0, 1023, -5, 50);
 lcd.print(SetTempTarget); 
 if(-1 < SetTempTarget <= 10) {   //needed to avoid displaying trailing 0 for one digit values
   lcd.print(" ");                //
   lcd.setCursor(14,0);           //
 }
 lcd.print((char)223); lcd.print("C");
 lcd.setCursor(0,1);
 lcd.print("TargetTemp: ");
 lcd.print(TargetTemp); 
 if(-1 < TargetTemp <= 10) {     //needed to avoid displaying trailing 0 for one digit values
   lcd.print(" ");               //
   lcd.setCursor(14,1);          //
 }
 lcd.print((char)223); lcd.print("C");
 
 //temperature
   sensors.requestTemperatures();
   InHeatsinkTemp = sensors.getTempCByIndex(0);
   OutHeatsinkTemp = sensors.getTempCByIndex(1);
   ChamberTemp_1 = sensors.getTempCByIndex(2);
   ChamberTemp_2 = sensors.getTempCByIndex(3);
   AmbientTemp = sensors.getTempCByIndex(4);
   float Average = (ChamberTemp_1+ChamberTemp_2)/2;  //averages two camber temperature sensors
   float Ravg = runningAverage(Average);     //assigns running average chamber temperature to a variable
   
   Serial.print(InHeatsinkTemp);
   Serial.print("\t");
   Serial.print("\t");
   Serial.print(OutHeatsinkTemp);
   Serial.print("\t");
   Serial.print("\t");
   Serial.print(ChamberTemp_1);
   Serial.print("\t");
   Serial.print("\t");
   Serial.print(ChamberTemp_2);
   Serial.print("\t");
   Serial.print("\t");
   Serial.print(Average);
   Serial.print("\t");
   Serial.print("\t");
   Serial.print(Ravg);
   Serial.print("\t");
   Serial.print("\t");
   Serial.println(AmbientTemp);
 
 
}

//function to calculate running average
float runningAverage(float Average) 
{
 static float LM[RavgSize];      // Last 10 measurements
 static byte index = 0;
 static float sum = 0;
 static byte count = 0;
 
 // keep sum updated to improve speed.
 sum -= LM[index];
 sum += LM[index++] = Average;
 index = index % RavgSize;
 if (count < RavgSize) count++;

 return sum / count;
}

And there is significant lag when turning the pot and having the mapped temperature value change on LCD screen. Same with the button.

I suspect that some operation is taking long time to complete and the MCU is waiting until it completes before it continues and this reduces drastically loop cycles per second? It might be the one wire sensors that take the time as they would only update slowly even if no delay() function is used.

Is there a way to make the MCU fetch temperature values only when the sensors have produced them already and run other code in the mean time?

Long delay suggests you are blocking for the temperature reading.

You need to separate the temperature code into two parts one to start the conversion and one to extract the value at the end.

I am confused by the 120C temperature limit - most peltiers will not tolerate such high temperatures as they use indium based semiconductors with very low melting points.

MarkT:
Long delay suggests you are blocking for the temperature reading.

You need to separate the temperature code into two parts one to start the
conversion and one to extract the value at the end.

I guess I need to do some research then…

MarkT:
I am confused by the 120C temperature limit - most peltiers will not tolerate
such high temperatures as they use indium based semiconductors with
very low melting points.

That is a good point. The first TEC1-12706 modules I ordered that had fake markings on them and were probably TEC1-12703 actually, had a temperature rating of 200 degrees C. (supposedly)

The TEC1-12715 ones indeed claim max operating temperature only <90 degrees C.
http://www.hebeiltd.com.cn/peltier.datasheet/TEC1-12715.pdf

I have these e-Bay ones:
http://www.ebay.com/itm/New-2-PCS-TEC1-12715-TEC-Thermoelectric-Cooler-Peltier-12V-40mm-/160654915658?pt=LH_DefaultDomain_0&hash=item2567c7784a

that seem to match with the datasheet.

On the other hand the e-Bay ones describe Tmax of 70 degrees C. 70 would be very low indeed. I thought that maybe that was a mistake and they meant max temperature difference of 70 degrees C.

So not sure what safety value to use.

MarkT:
Long delay suggests you are blocking for the temperature reading.

You need to separate the temperature code into two parts one to start the
conversion and one to extract the value at the end.

Managed to find an example in the dallas-temperature-control library called “WaitForConversion2” and salvage some code from there and bodge it in. Now the potentiometer and button response has improved significantly but it is not as fast, as it was by its self. Probably should expect that as other code will slow it down too.

My code:

#include <LiquidCrystal.h> //LCD library
#include <SD.h>            //SD card library
//#include <Time.h> 
//#include <TimeAlarms.h>
//#include <Wire.h>
//#include <DS1307RTC.h>
#include <OneWire.h>             //One wire library. Needed for temperature sensors.   
#include <DallasTemperature.h>   //Dallas temperature sensor library
#include <PWM.h>                 //PWM frequency control library http://code.google.com/p/arduino-pwm-frequency-library/downloads/list

//LCD#########
LiquidCrystal lcd(9, 8, 4, 5, 6, 7) ;  //declares LCD pins
//############
//Relay###############
const byte Relay_1 = A0;           //declare 
const byte Relay_2 = A1;
//#####################
const byte StoreTempPin = A6;   //declare temperature storage button pin (connected to button leg)
const byte AdjustTempPin = A7;  //declare temperature selection pot pin (connected to potentiometer wiper)
 int AdjustTempValue; //declares variable for analog input
 int SetTempTarget;   //declares variable for mapped temperature value
 int StoreTempButton;      //declares variable for analog button input
 int TargetTemp = 22 ;    //declares variable for terget temperature. Default 22°C.
 
File myFile;

//Inside heatsink air mixing fan speed control#######
const byte fanPin = 3;               // the pin that the fan control wire is connected to
 byte fanSpeed = 95;            // how fast fan runs (from 0 to 255). Uses fixed speed.
 const int frequency = 25000;     // PWM frequency. Fan need 25kHz.
//###################################################
//One wire/Dallas temperature sensor setup######
#define ONE_WIRE_BUS 2  //define one wire pin
OneWire oneWire(ONE_WIRE_BUS);  
DallasTemperature sensors(&oneWire); // Pass oneWire reference to Dallas Temperature.
   const byte resolution = 10; // set sensor resolution (10 bit should be good compromise between resolution and read speed)
   unsigned long lastTempRequest = 0; // variable to keep time when last temperature was requested
   int  DallasDelay = 0;    //Time given to sensors to get temperatures
   const byte RavgSize = 10; // set running average array size (onedimentional)
   float InHeatsinkTemp;    //variable for Inside heatsink temperature
   float OutHeatsinkTemp;   //variable for Outside heatsink temperature
   float ChamberTemp_1;     //variable for Chamber probe 1 temperature
   float ChamberTemp_2;     //variable for Chamber probe 2 temperature
   float AmbientTemp;       //variable for Ambient temperature
   
   
//#########################################



void setup() {
 
 Serial.begin(9600); // start serial port
 //DS18b20###########
 sensors.begin();            // start up DallasTemperature library
 sensors.setResolution(resolution);  // set sensor resolution
 sensors.setWaitForConversion(false);
 sensors.requestTemperatures();
 DallasDelay = 750 / (1 << (12 - resolution)); 
 lastTempRequest = millis(); 
 //##################
 //LCD
 lcd.begin(16, 2);      // initialise LCD (n colums, n rows)
 lcd.clear();        // clear just in case
 //
 //SD card #####################
 if (!SD.begin(10)) {
   Serial.println("SD init. failed!");
   return;
 }
 //Create file header
 Serial.println("SD init. OK!");
 myFile = SD.open("chamber.txt", FILE_WRITE);    //open file
   if (myFile) {
   myFile.println("Temperature sensors: DS1820");
   myFile.println("RTC: DS3231");
   myFile.println(" ");
   myFile.print("Time");
   myFile.print("\t");
   myFile.print("\t");
   myFile.print("\t");
   myFile.print("Ambient");
   myFile.print("\t");
   myFile.print("OutHeatsink");
   myFile.print("\t");
   myFile.print("InHeatsink");
   myFile.print("\t");
   myFile.print("Probe_1");
   myFile.print("\t");
   myFile.print("Probe_2");
   myFile.print("\t");
   myFile.print("Average");  //Average of Probe_1 and Probe_2
   myFile.print("\t");
   myFile.print("ChamberTemp");  //running 10 measurement average temperature calculated from Average
   myFile.print("\t");
   myFile.print("TargetTemp");
   myFile.print("\t");
   myFile.print("Temp.Offset");

   myFile.close(); // close file
   
 } else {
   // if the file didn't open, print an error:
   lcd.print("Error opening chamber.txt");
 }
 //##########################
 //Fan speed control #########
  //initialize all timers except for 0, to save time keeping functions
 InitTimersSafe(); 

 //sets the frequency for the specified pin
 bool success = SetPinFrequencySafe(fanPin, frequency);
 
 //if the pin frequency was set successfully, turn pin 13 on
 if(success) {
   pinMode(3, OUTPUT);
   digitalWrite(3, HIGH);    
 }
 //##########################
}





void loop () {
 
 pwmWrite(fanPin, fanSpeed); // Fan Speed
 
 //temperature sensors###############
   if (millis() - lastTempRequest >= DallasDelay) { // waited long enough??
   InHeatsinkTemp = sensors.getTempCByIndex(0);
   OutHeatsinkTemp = sensors.getTempCByIndex(1);
   ChamberTemp_1 = sensors.getTempCByIndex(2);
   ChamberTemp_2 = sensors.getTempCByIndex(3);
   AmbientTemp = sensors.getTempCByIndex(4);
   float Average = (ChamberTemp_1+ChamberTemp_2)/2;  //averages two camber temperature sensors
   float Ravg = runningAverage(Average);     //assigns running average chamber temperature to a variable
   
   Serial.print(InHeatsinkTemp);
   Serial.print("\t");
   Serial.print("\t");
   Serial.print(OutHeatsinkTemp);
   Serial.print("\t");
   Serial.print("\t");
   Serial.print(ChamberTemp_1);
   Serial.print("\t");
   Serial.print("\t");
   Serial.print(ChamberTemp_2);
   Serial.print("\t");
   Serial.print("\t");
   Serial.print(Average);
   Serial.print("\t");
   Serial.print("\t");
   Serial.print(Ravg);
   Serial.print("\t");
   Serial.print("\t");
   Serial.println(AmbientTemp);
   
   sensors.requestTemperatures(); 
   DallasDelay = 750 / (1 << (12 - resolution));
   lastTempRequest = millis(); 
 }
//#########################
 StoreTempButton = analogRead(StoreTempPin);    //read analog button state value (normally open = 0)
 AdjustTempValue = analogRead(AdjustTempPin);   //read potentiometer value
 //If statement to store target temperature from mapped value. 
 //If button is pressed new mapped temperature value is stored, otherwise previous value is used.
 if(StoreTempButton >100) {
   TargetTemp = SetTempTarget;
 }
 
 lcd.setCursor(0,0);        
 lcd.print("Set target: ");
 SetTempTarget = map(AdjustTempValue, 0, 1023, -5, 50);
 lcd.print(SetTempTarget); 
 if(-1 < SetTempTarget <= 10) {   //needed to avoid displaying trailing 0 for one digit values
   lcd.print(" ");                //
   lcd.setCursor(14,0);           //
 }
 lcd.print((char)223); lcd.print("C");
 lcd.setCursor(0,1);
 lcd.print("TargetTemp: ");
 lcd.print(TargetTemp); 
 if(-1 < TargetTemp <= 10) {     //needed to avoid displaying trailing 0 for one digit values
   lcd.print(" ");               //
   lcd.setCursor(14,1);          //
 }
 lcd.print((char)223); lcd.print("C");
 

 
 
}

//function to calculate running average
float runningAverage(float Average) 
{
 static float LM[RavgSize];      // Last 10 measurements
 static byte index = 0;
 static float sum = 0;
 static byte count = 0;
 
 // keep sum updated to improve speed.
 sum -= LM[index];
 sum += LM[index++] = Average;
 index = index % RavgSize;
 if (count < RavgSize) count++;

 return sum / count;
}

Going to try to add more things in. Any suggestions how to approach the different LCD screen modes that can be cycled through with a button press?

Has been a while and I have achieved most goals for my code. LCD screen cycling works, temperature measuring and control algorithm works (kind of).

Strange problem has occurred. The relays ONLY start working when SD card is inserted. When no SD card is inserted and device is turned on, then relays that switch the Peltier will not engage. If I insert the SD card while device is already running then relays will not work. If I start device when SD card is inserted, then relays work and if I then remove SD card, relays continue to work. What could be causing this sort of behavior?

I want the chamber to work regardless of having SD card inserted or not.

Code (first half):

#include <LiquidCrystal.h> //LCD library
#include <SD.h>            //SD card library
//#include <Time.h> 
//#include <TimeAlarms.h>
#include <Wire.h>
//#include <DS1307RTC.h>
#include <OneWire.h>             //One wire library. Needed for temperature sensors.   
#include <DallasTemperature.h>   //Dallas temperature sensor library
#include <PWM.h>                 //PWM frequency control library http://code.google.com/p/arduino-pwm-frequency-library/downloads/list

#define RTCaddr 0x68  // Define RTC DS3231 address on I2C port

//LCD#########
LiquidCrystal lcd(9, 8, 4, 5, 6, 7) ;  //declares LCD pins
const byte  buttonPin = A3;    // the pin that the LCD display cycle pushbutton is attached to
  byte buttonPushCounter = 0;   // counter for the number of button presses
  byte buttonState = 0;         // current state of the button
  byte lastButtonState = 0;     // previous state of the button
//############
//Relay###############
const byte Relay_1 = A0;           //declare 
const byte Relay_2 = A1;
//#####################
const byte StoreTempPin = A6;   //declare temperature storage button pin (connected to button leg)
const byte AdjustTempPin = A7;  //declare temperature selection pot pin (connected to potentiometer wiper)
  int AdjustTempValue; //declares variable for analog input
  int SetTempTarget;   //declares variable for mapped temperature value
  int StoreTempButton;      //declares variable for analog button input
  int TargetTemp = 22 ;    //declares variable for terget temperature. Default 22°C.
  
File myFile;

//Inside heatsink air mixing fan speed control#######
const byte fanPin = 3;               // the pin that the fan control wire is connected to
  byte fanSpeed = 95;            // how fast fan runs (from 0 to 255). Uses fixed speed.
  const int frequency = 25000;     // PWM frequency. Fan need 25kHz.
//###################################################
//One wire/Dallas temperature sensor setup######
#define ONE_WIRE_BUS 2  //define one wire pin
OneWire oneWire(ONE_WIRE_BUS);  
DallasTemperature sensors(&oneWire); // Pass oneWire reference to Dallas Temperature.
    const byte resolution = 10; // set sensor resolution (10 bit should be good compromise between resolution and read speed)
    unsigned long lastTempRequest = 0; // variable to keep time when last temperature was requested
    int  DallasDelay = 0;    //Time given to sensors to get temperatures
    const byte RavgSize = 10; // set running average array size (onedimentional)
    float InHeatsinkTemp;    //variable for Inside heatsink temperature
    float OutHeatsinkTemp;   //variable for Outside heatsink temperature
    float ChamberTemp_1;     //variable for Chamber probe 1 temperature
    float ChamberTemp_2;     //variable for Chamber probe 2 temperature
    float AmbientTemp;       //variable for Ambient temperature
    float Average;           //variable for two sensor average temperature
    float Ravg;              //variable for running average temperature
    
//RTC DS3231 ############
// variables to store DS3231 register values in packed BCD format. Each byte contains two digits.
  byte second;      //seconds
  byte minute;      //minutes
  byte hour;        //hours
  byte dayOfWeek;   //weekday (not used later)
  byte dayOfMonth;   //day of month
  byte month;        //month
  byte year;         //year (Decade and year number. No millennium or century.)
  
  char timestamp[20]; // character variable to store timestamp
  char * pt; // character variable to store pointer (needed to make timestamp string)
   
//###################



void setup() {
  
  Serial.begin(9600); // start serial port
  Wire.begin(); // start I2C port
  //DS18b20###########
  sensors.begin();            // start up DallasTemperature library
  sensors.setResolution(resolution);  // set sensor resolution
  sensors.setWaitForConversion(false);
  sensors.requestTemperatures();
  DallasDelay = 750 / (1 << (12 - resolution));  //adjust DS18b20 delay based on resolution used
  lastTempRequest = millis();     // Count time since temperatures were last requested.
  //#######################
  //LCD
  lcd.begin(16, 2);      // initialise LCD (n colums, n rows)
  lcd.clear();        // clear just in case
  // initialize the LCD cycle button pin as a input and activate internal pullup:
  pinMode(buttonPin, INPUT_PULLUP);
  //##################
  //SD card #####################
  if (!SD.begin(10)) {
    Serial.println("SD init. failed!");
    return;
  }
  //Create file header
  Serial.println("SD init. OK!");
  myFile = SD.open("chamber.txt", FILE_WRITE);    //open file
    if (myFile) {
    myFile.println("Temperature sensors: DS1820");
    myFile.println(" ");
    myFile.print("Time");
    myFile.print("\t");
    myFile.print("\t");
    myFile.print("\t");
    myFile.print("Ambient");
    myFile.print("\t");
    myFile.print("OutHeatsink");
    myFile.print("\t");
    myFile.print("InHeatsink");
    myFile.print("\t");
    myFile.print("Probe_1");
    myFile.print("\t");
    myFile.print("Probe_2");
    myFile.print("\t");
    myFile.print("ChamberAvg");  //Average of Probe_1 and Probe_2
    myFile.print("\t");
    myFile.print("ChamberRavg");  //running 10 measurement average temperature calculated from Average
    myFile.print("\t");
    myFile.print("TargetTemp");
    myFile.print("\t");
    myFile.println("Temp.Offset");
 
    myFile.close(); // close file
    
  } else {
    // if the file didn't open, print an error:
    lcd.print("Error opening chamber.txt");
  }
  //##########################
  //Fan speed control #########
   //initialize all timers except for 0, to save time keeping functions
  InitTimersSafe(); 

  //sets the frequency for the specified pin
  bool success = SetPinFrequencySafe(fanPin, frequency);
  
  //if the pin frequency was set successfully, turn pin 13 on
  if(success) {
    pinMode(3, OUTPUT);
    digitalWrite(3, HIGH);    
  }
  //##########################
  pinMode(Relay_1, OUTPUT);
  pinMode(Relay_2, OUTPUT);
  //############################
 }

Code (second half):

void loop () {
  
  pwmWrite(fanPin, fanSpeed); // Fan Speed
  
  //temperature sensors###############
   if (millis() - lastTempRequest >= DallasDelay) { // waited long enough??
   getTemps(); // call temperature reading function
//#######Put things that need to print with temperatures down from here!!####
    rTime(); //calls time reading function
    Serial.println(timestamp); // prints timestamp
    
    dataLog(); // function call to write data to SD card
    
//#######Put things that need to print with temperatures up from here!!####
    sensors.requestTemperatures(); 
    DallasDelay = 750 / (1 << (12 - resolution));
    lastTempRequest = millis(); 
  }
  //###########
 //Overheat protection ######
 if (OutHeatsinkTemp > 80 || InHeatsinkTemp > 65) {
   Stop();
 }
 //####
 //######Temperature selection######
  StoreTempButton = analogRead(StoreTempPin);    //read analog button state value (normally open = 0)
  AdjustTempValue = analogRead(AdjustTempPin);   //read potentiometer value
  SetTempTarget = map(AdjustTempValue, 0, 1023, -5, 50);
  //If statement to store target temperature from mapped value. 
  //If button is pressed new mapped temperature value is stored, otherwise previous value is used.
  if(StoreTempButton >100) {
    TargetTemp = SetTempTarget;
  }
  //###########################
  //LCD cycle button part: #############
  buttonState = digitalRead(buttonPin); // read the pushbutton input pin:
  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == LOW) {
      // if the current state is LOW then the button
      // went from off to on:
      buttonPushCounter++;
    } 
  }
  // save the current state as the last state, 
  //for next time through the loop
  lastButtonState = buttonState;
  if (buttonPushCounter >=6) {
    buttonPushCounter = 0;
  }
  //#########################
  //Screen mode choosing part:
  if (buttonPushCounter == 0) {
    display_0();
  }
  if (buttonPushCounter == 1) {
    display_1();
  }
  if (buttonPushCounter == 2) {
    display_2();
  }
  if (buttonPushCounter == 3) {
    display_3();
  }
  if (buttonPushCounter == 4) {
    display_4();
  }
  if (buttonPushCounter == 5) {
    display_5();
  }
  //#######
  //##### Temperature control algorithm ######

  if ( (TargetTemp + 0.5) < Ravg) {  
    Cool();
    }
  if ( (TargetTemp - 0.5) > Ravg) {  
    Heat();
    }
  if ( (TargetTemp - 0.5) < Ravg && Ravg < (TargetTemp + 0.5)) {  
    Stop();
    }
    //##Overheat protection
      if ( OutHeatsinkTemp > 80 || InHeatsinkTemp > 75) {  
      Stop();
      }
  //##
} //### end of loop() ##

Code (third part):

//#####   Functions   ######

//Peltier relay functions####
void Cool() {                      // this cools the chamber
    digitalWrite(Relay_1, HIGH);
    digitalWrite(Relay_2, LOW);
}

void Heat() {                      // this heats the chamber
    digitalWrite(Relay_1, LOW);
    digitalWrite(Relay_2, HIGH);
}

void Stop() {                      // this cuts power to the Peltier
    digitalWrite(Relay_1, HIGH);
    digitalWrite(Relay_2, HIGH);
}
//##
//function to calculate running average temperature####
float runningAverage(float Average) 
{
  static float LM[RavgSize];      // Last 10 measurements
  static byte index = 0;
  static float sum = 0;
  static byte count = 0;
  
  // keep sum updated to improve speed.
  sum -= LM[index];
  sum += LM[index++] = Average;
  index = index % RavgSize;
  if (count < RavgSize) count++;

  return sum / count;
}
//###########
//function to convert BCD time values to ASCII characters
char* BCDtoASCII(char*buf, byte BCD)
{      
	buf[0]=((BCD >> 4)+'0');
        buf[1]=((BCD & 0x0F)+'0');
        buf[2]= '\0';
        return &(buf[2]);
}

//function to read time from DS3231 and create timestamp############
void rTime() {

  Wire.beginTransmission(RTCaddr);
  Wire.write(0); // sets DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(RTCaddr, 7); // requests seven bytes of data from DS3231 starting from register 00h
  // read time values from registers and store into variables
  second = Wire.read();
  minute = Wire.read();
  hour = Wire.read();
  dayOfWeek = Wire.read();
  dayOfMonth = Wire.read();
  month = Wire.read();
  year = Wire.read();
  //create timestamp
    pt = timestamp;
  *(pt++) = '2';
  *(pt++) = '0';
  pt = BCDtoASCII(pt,year);
  *(pt++) = '-';
  pt = BCDtoASCII(pt,month);
  *(pt++) = '-';
  pt = BCDtoASCII(pt,dayOfMonth);
  *(pt++) = ' ';
  pt = BCDtoASCII(pt,hour);
  *(pt++) = ':';
  pt = BCDtoASCII(pt,minute);
  *(pt++) = ':';
  pt = BCDtoASCII(pt,second);
  *(pt++) = '\0';
}
//Temperature function#######

void getTemps() {
  //read temperatures from sensors:
    InHeatsinkTemp = sensors.getTempCByIndex(0);
    OutHeatsinkTemp = sensors.getTempCByIndex(1);
    ChamberTemp_1 = sensors.getTempCByIndex(2);
    ChamberTemp_2 = sensors.getTempCByIndex(3);
    AmbientTemp = sensors.getTempCByIndex(4);
    Average = (ChamberTemp_1+ChamberTemp_2)/2;  //averages two camber temperature sensors
    Ravg = runningAverage(Average);     //computes running average and stores to variable
}
//Data logging function to SD card#####
void dataLog() {
  myFile = SD.open("chamber.txt", FILE_WRITE); // file is opened
  if (myFile) {
    myFile.print(timestamp);
    myFile.print("\t");
    myFile.print(AmbientTemp);
    myFile.print("\t");
    myFile.print(OutHeatsinkTemp);
    myFile.print("\t");
    myFile.print("\t");
    myFile.print(InHeatsinkTemp);
    myFile.print("\t");
    myFile.print("\t");
    myFile.print(ChamberTemp_1);
    myFile.print("\t");
    myFile.print(ChamberTemp_2);
    myFile.print("\t");
    myFile.print(Average);
    myFile.print("\t");
    myFile.print("\t");
    myFile.print(Ravg);
    myFile.print("\t");
    myFile.print("\t");
    myFile.print(TargetTemp);
    myFile.print("\t");
    myFile.print("\t");
    myFile.println(Ravg - TargetTemp); // If chamber temperature is too high then positive, if too low then negative.
    
    
    myFile.close();
    } //end of if
    else {
    // if the file didn't open, print an error:
    lcd.print("Error opening chamber.txt");
    } //end of else
 }

//LCD#Display functions###############

//This displays chamber average temperature and target temperature
void display_0() {
  lcd.setCursor(0,0);        
  lcd.print("Chamber:   ");
  lcd.setCursor(10,0);
  lcd.print(Ravg); 
  if(-1 < SetTempTarget <= 10) {   //needed to avoid displaying trailing 0 for one digit values
    lcd.print(" ");                //
    lcd.setCursor(14,0);           //
  }
  lcd.print((char)223); lcd.print("C");
  lcd.setCursor(0,1);
  lcd.print("TargetT.:     ");
  lcd.setCursor(10,1);
  lcd.print(TargetTemp); 
  if(-1 < TargetTemp <= 10) {     //needed to avoid displaying trailing 0 for one digit values
    lcd.print(".0");               //
    lcd.setCursor(14,1);          //
  }
  lcd.print((char)223); lcd.print("C");
}

//This displays temperature selection value and target temperature
void display_1() {
  lcd.setCursor(0,0);        
  lcd.print("Set to:     ");
  lcd.setCursor(12,0);
  lcd.print(SetTempTarget); 
  if(-1 < SetTempTarget <= 10) {   //needed to avoid displaying trailing 0 for one digit values
    lcd.print(" ");                //
    lcd.setCursor(14,0);           //
  }
  lcd.print((char)223); lcd.print("C");
  lcd.setCursor(0,1);
  lcd.print("TargetT.:   ");
  lcd.setCursor(12,1);
  lcd.print(TargetTemp); 
  if(-1 < TargetTemp <= 10) {     //needed to avoid displaying trailing 0 for one digit values
    lcd.print(" ");               //
    lcd.setCursor(14,1);          //
  }
  lcd.print((char)223); lcd.print("C");
}

//This displays heatsink temperatures
void display_2() {
  lcd.setCursor(0,0);        
  lcd.print("OutSink:  ");
  lcd.setCursor(10,0);
  lcd.print(OutHeatsinkTemp); 
  if(-1 < SetTempTarget <= 10) {   //needed to avoid displaying trailing 0 for one digit values
    lcd.print(" ");                //
    lcd.setCursor(14,0);           //
  }
  lcd.print((char)223); lcd.print("C");
  lcd.setCursor(0,1);
  lcd.print("InSink:   ");
  lcd.setCursor(10,1);
  lcd.print(InHeatsinkTemp); 
  if(-1 < TargetTemp <= 10) {     //needed to avoid displaying trailing 0 for one digit values
    lcd.print(" ");               //
    lcd.setCursor(14,1);          //
  }
  lcd.print((char)223); lcd.print("C");
}

//This displays chamber probe temperatures
void display_3() {
  lcd.setCursor(0,0);        
  lcd.print("Probe 1:    ");
  lcd.setCursor(10,0);
  lcd.print(ChamberTemp_1); 
  if(-1 < SetTempTarget <= 10) {   //needed to avoid displaying trailing 0 for one digit values
    lcd.print(" ");                //
    lcd.setCursor(14,0);           //
  }
  lcd.print((char)223); lcd.print("C");
  lcd.setCursor(0,1);
  lcd.print("Probe 2:    ");
  lcd.setCursor(10,1);
  lcd.print(ChamberTemp_2); 
  if(-1 < TargetTemp <= 10) {     //needed to avoid displaying trailing 0 for one digit values
    lcd.print(" ");               //
    lcd.setCursor(14,1);          //
  }
  lcd.print((char)223); lcd.print("C");
}

//This displays ambient temperature
void display_4() {
  lcd.setCursor(0,0);        
  lcd.print("Ambient:    ");
  lcd.setCursor(10,0);
  lcd.print(AmbientTemp); 
  if(-1 < SetTempTarget <= 10) {   //needed to avoid displaying trailing 0 for one digit values
    lcd.print(" ");                //
    lcd.setCursor(14,0);           //
  }
  lcd.print((char)223); lcd.print("C");
  lcd.setCursor(0,1);
  lcd.print("                ");
}
//this displays time and date ####
void display_5() {
  lcd.setCursor(0,0);
  lcd.print("Time    ");
  lcd.print(hour >> 4);
  lcd.print(hour & 0x0F);
  lcd.print(":");
  lcd.print(minute >> 4);
  lcd.print(minute & 0x0F);
  lcd.print(":");
  lcd.print(second >> 4);
  lcd.print(second & 0x0F);
  lcd.setCursor(0,1);
  lcd.print("Date  20");
  lcd.print(year >> 4);
  lcd.print(year & 0x0F);
  lcd.print("-");
  lcd.print(month >> 4);
  lcd.print(month & 0x0F);
  lcd.print("-");
  lcd.print(dayOfMonth >> 4);
  lcd.print(dayOfMonth & 0x0F);
}
//###########

I think I fixed it. I think if no SD card was inserted then the setup routine stopped fore some reason and all code that came after the SD card initialization command was not run. I believe the return; command was responsible for that and it terminated the setup function.

Solution would be to remove the return or leave the SD card initialization as the last thing in the setup routine.