temperature control variable

Hello

A seed propagator, how could I make the on temperature variable. The actual coding for switching wouldn't be a problem but I'm a bit lost as how to hardware wise change the value of the variable. The range would be 10ºC to 30ºC Any ideas

As always with my requests its best to think 'idiot proof' if answering

Use a watertight DS18B20. That allows you to measure the temperature of the soil or the air or both.

It has 3 wires 0, 5V + data. The Dallas Temperature Library has examples that can be copied almost 1 to 1 for your project

the main control loop could look like this

void setup()
{
  Serial.begin(115200);
  Serial.println("Start ");
}

void loop()
{
  int t = random(0, 50); // should be readTemperature
  Serial.print(t);
  Serial.print("\t");

  switch (t)
  {
    case 13 ... 27:
      Serial.println("Within parameters");
      // heater = false;
      // cooler = false;
      break;
    case 10 ... 12:
      Serial.println("Yellow Alert");
      // heater = true;
      break;
    case 28 ... 30:
      Serial.println("Yellow Alert");
      // cooler = true;
      break;
    default:
      Serial.println("Red Alert");
      break;
  }
  delay(500);
}

If you include a display of some kind and a few buttons you could allow the user to change the temperature setting.

Based on my personal experience I use a temperature sensor (DHT22, using robtillaart's library) outside the insulated 'incubator' that I use to house my propagators, heater, etc. The heater is controller using PWM and I increase the frequency based on the external temperature. I also have a similar sensor within the incubator to record the inside temperature to SD card. I ran it for a few weeks without plants to establish a formula for the temperature / PWM settings.

Thanks for the replys

The DS18B20 is what 'll be using and the switch code (hadn't actually thought this far ahead) will work well. It's the actual 'few buttons' bit i'm stuck on, 20 or 10 ( 1º or 2º steps) separate buttons to cover the range is doable but is there a better way

dannable - just seen your reply you seem to be doing more than i was intending, dont suppose you've got more info so i can see if i want to do the extra

There are SO many ways of achieving this. Maybe the simplest to implement (but not necessarily the most practical) would be to simply edit the sketch and upload it again when you want to change your selected temperature.

You could have a potentiometer that gets read by your sketch and uses the map function to convert it’s reading into your target temperature.

If you want an interactive user interface you’d need to include a display of some kind.

More in what sense?

To calibrate it I set the PWM to a value, ran it for 24 / 48 hours and examined the results. I could see that as the temperature outside the incubator dropped so did that inside, and from that derived a formula to increase/decrease the PWM as necessary.

The incubator is made from polystyrene with a winemakers heating tray to provide the heat. The propagators sit on wire cooling trays supported above the heater, resting on strips of polystyrene running along the inside edge of the propagator. Naturally it has a transparent cover.

I forgot to add that I also have two small 5v fans from a 'lap top cooler' to circulate the air around the propagators, keeping it even.

As the plants are in there for about two weeks I hard code the temperature as KenF suggests.

KenF Hard coding it wasn't top of my + list. Yes I will have a display. I'd prefer it to be real-time user interactive and to be able to up/down inclement the switch variable, that would mean only two buttons needed. Will that be difficult ? never having tried it before i'm not sure how it to do it.

dannable Thats clearer, dont think I'll be looking at the outside temp, looking at the temp inside of the propagator should be ok. I was thinking of including a couple of fans, one to circulate and one to push air outside if the thing should overheat. The DHT22 you used also does humidity, did you use that in anyway. A way extra bit would be recording to a SD card, how did you manage that.

Hi IGRAHAM,
My first seed propagator was based on a Picaxe (years ago), but resently I built a prototype with a Uno and the final with a Nano to save space… I used a waterproof DS18b20 (Cheap from China via eBay, also my relay module came from there too). I also use a DS1307 RTC for time, etc.

I used a fixed TEMP variable? this changed according to the light level and the time, as there is little point in keeping seedlings too warm without the right light levels (as most growers know). But I now have a 10K pot in the CDS sensor circuit, so this can also give me some control of daytime temps, also many do not need a constant temp, some daytime/nightime variation is needed.

Sure there’s more to say, perhaps later, in the meantime here’s my code and a picture.

#include <FastIO.h>
#include <I2CIO.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>

/*
Connections:
 Heater1 pin 3
 Heater2 pin 4
 SDA to Arduino Analog pin 4
 SCL to Arduino Analog pin 5
 LightPin Analog pin A7
 TempPin pin 12
 */

#define DS1307_I2C_ADDRESS 0x68
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3, POSITIVE);  // Set the LCD I2C address 

//*****constants*****
int Light,LightPin=A7,TargetTemp,TEMP,PTemp,Heater1=3,Heater2=4,TempPin=12;
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;

void setup()
{
	TargetTemp=23;  //Set Normal/Target temp to 23c
	pinMode(Heater1,OUTPUT);
	pinMode(Heater2,OUTPUT);
	pinMode(13,OUTPUT);
	Wire.begin();
	lcd.begin(20,4); // tells Arduino the LCD dimensions
}
//------------End of Setup loop------------------------
//--------------Start of Main loop------------------
void loop()  
{
	GetTime();
	GetTemp();
	TestIt();
	digitalWrite(13,HIGH);
	delay(100);
	digitalWrite(13,LOW);
}
//---------------------------------------------------------------------------------
void GetTime()
{
	byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
	getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
	//if (second <=5)
	{
		//lcd.clear(); // clear LCD screen
		lcd.setCursor(0,0);
		lcd.print(" ");
		lcd.print(hour, DEC);
		lcd.print(":");
		if (minute<10)
		{
			lcd.print("0");
		}
		lcd.print(minute, DEC);
		lcd.print(":");
		if (second<10)
		{
			lcd.print("0");
		}
		lcd.print(second, DEC);
		lcd.print(" ");
		lcd.print(dayOfMonth, DEC);
		lcd.print("/");
		lcd.print(month, DEC);
		lcd.print("/");
		lcd.print("20");
		lcd.print(year, DEC);
		//delay(1000);
	}
}
//------------------------------------------------------------------------------------------
//http://sheepdogguides.com/arduino/ar3ne1tt.htm


// void OneWireReset(int Pin);//See Note 2
// void OneWireOutByte(int Pin, byte d);
// byte OneWireInByte(int Pin);

void GetTemp()
{
	OneWireReset(TempPin);
	OneWireOutByte(TempPin, 0xcc);
	OneWireOutByte(TempPin, 0x44); // perform temperature conversion, strong pullup for one sec

	OneWireReset(TempPin);
	OneWireOutByte(TempPin, 0xcc);
	OneWireOutByte(TempPin, 0xbe);

	LowByte = OneWireInByte(TempPin);
	HighByte = OneWireInByte(TempPin);
	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
	TEMP = Tc_100 / 100;  // separate off the whole and fractional portions
	Fract = Tc_100 % 100;
	PTemp = Tc_100 % 100;

}

void OneWireReset(int Pin) // reset.  Should improve to act as a presence pulse
{
	digitalWrite(Pin, LOW);
	pinMode(Pin, OUTPUT); // bring low for 500 us
	delayMicroseconds(500);
	pinMode(Pin, INPUT);
	delayMicroseconds(500);
}

void OneWireOutByte(int Pin, byte d) // output byte d (least sig bit first).
{
	byte n;

	for(n=8; n!=0; n--)
	{
		if ((d & 0x01) == 1)  // test least sig bit
		{
			digitalWrite(Pin, LOW);
			pinMode(Pin, OUTPUT);
			delayMicroseconds(5);
			pinMode(Pin, INPUT);
			delayMicroseconds(60);
		}
		else
		{
			digitalWrite(Pin, LOW);
			pinMode(Pin, OUTPUT);
			delayMicroseconds(60);
			pinMode(Pin, INPUT);
		}

		d=d>>1; // now the next bit is in the least sig bit position.
	}
}

byte OneWireInByte(int Pin) // read byte, least sig byte first
{
	byte d, n, b;

	for (n=0; n<8; n++)
	{
		digitalWrite(Pin, LOW);
		pinMode(Pin, OUTPUT);
		delayMicroseconds(5);
		pinMode(Pin, INPUT);
		delayMicroseconds(5);
		b = digitalRead(Pin);
		delayMicroseconds(50);
		d = (d >> 1) | (b<<7); // shift d to right and insert b in most sig bit position
	}
	return(d);
}
//-----------------------------------------------------------------------------------------------------------
void TestIt()
{
	Light=analogRead(LightPin);
	Light=Light/4;
	if(Light>200)
	{
		TargetTemp=25;
	}
	if(Light>160 && Light<200)
	{
		TargetTemp=18;
	}
	if(Light<160)
	{
		TargetTemp=14;
	}
	// Set Temp******

	lcd.setCursor(1,1);
	lcd.print("Target Temp:");
	lcd.print(TargetTemp);
	lcd.print(".00c ");
	lcd.setCursor(1,2);
	lcd.print("Current Temp:");
	lcd.print(TEMP); 
	lcd.print(".");
	if(PTemp <10)
	{
		lcd.print("0");
	}
	lcd.print(PTemp);
	lcd.print("c ");

	if (TEMP < TargetTemp)
	{
		digitalWrite(Heater1,LOW);    //Heater ON
		digitalWrite(Heater2,LOW);
		lcd.setCursor(1,3);
		lcd.print("Heater ON ");
		lcd.print(Light);
		lcd.print("  ");
	}
	if (TEMP > TargetTemp)
	{
		digitalWrite(Heater1,HIGH);
		digitalWrite(Heater2,HIGH);  //Heater OFF
		lcd.setCursor(1,3);
		lcd.print("Heater OFF ");
		lcd.print(Light);
		lcd.print("  ");
		//lcd.clear();
	}
	//delay(5000);
}
//*************************************************************************************************************

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
	return ( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
	return ( (val/16*10) + (val%16) );
}
// Gets the date and time from the ds1307
void getDateDs1307
(
byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
	// Reset the register pointer
	Wire.beginTransmission(DS1307_I2C_ADDRESS);
	Wire.write(0);
	Wire.endTransmission();
	Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
	// A few of these need masks because certain bits are control bits
	*second = bcdToDec(Wire.read() & 0x7f);
	*minute = bcdToDec(Wire.read());
	*hour = bcdToDec(Wire.read() & 0x3f); // Need to change this if 12 hour am/pm
	*dayOfWeek = bcdToDec(Wire.read() &0x07);
	*dayOfMonth = bcdToDec(Wire.read());
	*month = bcdToDec(Wire.read());
	*year = bcdToDec(Wire.read());
}

Feel free to copy and use anything or part you can.
Hope it helps.

Regards

Mel.

I just use one of the inexpensive SPI SD card modules. But I have a certain memory card I use with it as I don't think they use level shifters which means in the long term they will probably damage the memory card.

For examples of how to use it look under File -> Examples -> SD in the IDE.

Hi dannable, You can get cheap SPI SD modules, the first I got did'ent have the level shifter and I had a real struggle with it, gave up, then found the right thing at about the same price... Where would we be without China??

Regards

Mel.

Hi cactusFace,

Given what I paid for the modules, delivered, I certainly won’t trust the SD card with anything important! I think mine rely on resistors to drop the voltage, it may even be a divider, but I’ve never worried about it. I have got a better one on order in case I need it but the ones I’ve got have lasted a few years.