LordUlrich
Well-Known Member
I figured being as I have finally finished my DIY fermentation temperature controller, I might as well share what I have done.
This is solely what I have one, I make no assurance or warranty or even suggest anyone else try this (but I will answer any questions anyone has). I also get no kick backs or profit on anything I have posted here.
I designed my own circuit board and had it manufactured using the OSHpark service (great service, 3 boards made in about a week, at $5 per sq in)
http://oshpark.com/shared_projects/GSwiuFKu
The PCB parts are all available from Digi-Key with a few extra parts still needed (such as enclosure, outlet power cord, power supply (or transformer). Total Dig-key parts are about $30, although it can be brought down by buying in quantity (10 or 100 of a part is cheaper than 8 sometimes)
The board acts as an Arduino UNO, although there is no USB interface on board. The program I have, while it has some bugs, lets me set target temperature, allowable temp range and a delay between changes in state. In theory the settings are saved to the EEPROM, but that seems to not work yet. The code is here:
So there you go
This is solely what I have one, I make no assurance or warranty or even suggest anyone else try this (but I will answer any questions anyone has). I also get no kick backs or profit on anything I have posted here.
I designed my own circuit board and had it manufactured using the OSHpark service (great service, 3 boards made in about a week, at $5 per sq in)
http://oshpark.com/shared_projects/GSwiuFKu
The PCB parts are all available from Digi-Key with a few extra parts still needed (such as enclosure, outlet power cord, power supply (or transformer). Total Dig-key parts are about $30, although it can be brought down by buying in quantity (10 or 100 of a part is cheaper than 8 sometimes)
The board acts as an Arduino UNO, although there is no USB interface on board. The program I have, while it has some bugs, lets me set target temperature, allowable temp range and a delay between changes in state. In theory the settings are saved to the EEPROM, but that seems to not work yet. The code is here:
Code:
//*********************Libraries********************************
#include <EEPROM.h>
#include <SevSeg.h>
#include <OneWire.h>
#include <DallasTemperature.h>
//*******************Operational Paramaters**********************
//Min Setpoint
float TargetMin=40.0;
//Max Setpoint
float TargetMax=95.0;
//Max allowable Range
float RangeMax=9.9;
//Max allowable Wait Time
unsigned int waitMax=90;
//Debounceing time
byte udLimit=20;
//Delay to reduce display flashing
byte DispDelay=200;
//EEPROM addresses
byte setAdd=0;
byte rangeAdd=2;
byte timeAdd=4;
//*******************Pin Declerations****************************
//setup display
SevSeg Display;
int displayType = COMMON_ANODE; //Your display is either common cathode or common anode
int numberOfDigits = 4; //Do you have a 1, 2 or 4 digit display?
//Declare what pins are connected to the digits (anode)
int digit1 = 9; //Pin 12 on my 4 digit display
int digit2 = 11; //Pin 9 on my 4 digit display
int digit3 = 17; //Pin 8 on my 4 digit display
int digit4 = 15; //Pin 6 on my 4 digit display
//Declare what pins are connected to the segments
int segA = 3; //Pin 11 on my 4 digit display
int segB = 10; //Pin 7 on my 4 digit display
int segC = 2; //Pin 4 on my 4 digit display
int segD = 12; //Pin 2 on my 4 digit display
int segE = 14; //Pin 1 on my 4 digit display
int segF = 18; //Pin 10 on my 4 digit display
int segG = 13; //Pin 5 on my 4 digit display
int segDP= 16; //Pin 3 on my 4 digit display
//Input Pins
int enter_pin=5;
int up_pin=4;
int dn_pin=6;
// one wire sensor pin
#define ONE_WIRE_BUS A5
//Output Pins
#define HeatPin 7
#define CoolPin 8
//***********************Global Variables********************
// Current Temp
float tempF;
// Target Temp
float TargetFloat=69.0;
// Allowable Temp Range
float RangeFloat=0.5;
// Time Between Control Changes
unsigned int waitTime=1;
//Control States
boolean heat_state=false;
boolean cool_state=false;
//Display mode
byte dispMode = 0;
//Counter to reduce display flash (delays temp read)
byte DispCount=0;
// Counter for debounce
int udTime=0;
// variable for debounce
boolean enter_state=false;
//Time control state can be changed
unsigned int time_clear=0;
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// arrays to hold device address
DeviceAddress DSAddress;
//**************************Functions**************************
void startOneWire(){
//setup one wire
sensors.begin();
sensors.getAddress(DSAddress, 0);
sensors.setWaitForConversion(false);
sensors.requestTemperatures(); // Send the command to get temperatures
}
float ReadEEPROM(byte Add){
word wrd;
byte byteH, byteL;
float floatvalue;
byteH=EEPROM.read(Add);
byteL=EEPROM.read(Add+1);
wrd=word(byteH,byteL);
floatvalue=wrd;
return floatvalue;
}
void WriteEEPROM(float value, byte Add){
word wrd;
wrd=word(value);
EEPROM.write( highByte(wrd), Add);
EEPROM.write( lowByte(wrd), Add+1);
}
void SetPins(){
pinMode(HeatPin, OUTPUT);
pinMode(CoolPin, OUTPUT);
digitalWrite(HeatPin, LOW);
digitalWrite(CoolPin, LOW);
pinMode(enter_pin, INPUT);
pinMode(up_pin, INPUT);
pinMode(dn_pin, INPUT);
}
void StartDisplay(){
Display.Begin(displayType, numberOfDigits, digit1, digit2, digit3, digit4, segA, segB, segC, segD, segE, segF, segG, segDP);
Display.SetBrightness(50); //Set the display brightness level
Display.DisplayString("8888", 0);
}
float GetTemp(){
float temp;
temp=sensors.getTempF(DSAddress); //get first temp
sensors.requestTemperatures(); // Send the command to get temperatures
return temp;
}
void printFloat10(float value, char leading){
char dispStr[5];
float dispFlt=value*10;
int dispInt=int(dispFlt);
String tempStr = String(dispInt);
if (value < 10){
tempStr="0"+tempStr;
}
if (value <1){
tempStr="0"+tempStr;
}
tempStr=leading + tempStr;
tempStr.toCharArray(dispStr,5);
Display.DisplayString(dispStr, 3);
}
void printFloat0 (float value, char leading){
char dispStr[5];
int dispInt=int(value);
String tempStr = String(dispInt);
if (value < 100){
tempStr="0"+tempStr;
}
if (value <10){
tempStr="0"+tempStr;
}
tempStr=leading + tempStr;
tempStr.toCharArray(dispStr,5);
Display.DisplayString(dispStr, 0);
}
float adjFloat(float input, float mn, float mx, int factor, float inc){
float output;
output=input + inc * float(factor);
output=max(output, mn);
output=min(output, mx);
return output;
}
//*************************Operating System***********************
void setup(){
SetPins();
StartDisplay();
startOneWire();
//Get values from EEPROM
// TargetFloat=ReadEEPROM(setAdd)/10.0;
// RangeFloat=ReadEEPROM(rangeAdd)/10.0;
// waitTime=ReadEEPROM(timeAdd);
//check for temp conversion
while (sensors.isConversionAvailable(DSAddress)==false){
Display.DisplayString("8888", 0);
}
tempF=GetTemp();
}
void loop(){
//Update current temp
if (DispCount >= DispDelay){
tempF=GetTemp();
DispCount=0;
if (millis()>=time_clear){
if (heat_state) {
if (tempF > TargetFloat +( RangeFloat/2.0)){
digitalWrite(HeatPin,LOW);
heat_state=false;
time_clear=millis()+(waitTime*60000);
}
}
else if (cool_state){
if (tempF < TargetFloat -( RangeFloat/2.0)){
digitalWrite(CoolPin,LOW);
cool_state=false;
time_clear=millis()+(waitTime*60000);
}
}
else {
if (tempF < TargetFloat -( RangeFloat/2.0)){
digitalWrite(HeatPin,HIGH);
heat_state=true;
time_clear=millis()+(waitTime*60000);
}
else if (tempF > TargetFloat +( RangeFloat/2.0)){
digitalWrite(CoolPin,HIGH);
cool_state=true;
time_clear=millis()+(waitTime*60000);
}
}
}
}
DispCount++;
//read "ENTER" button
if (digitalRead(enter_pin)==HIGH){
if (enter_state==false){
enter_state=true;
switch (dispMode){
case 0:
// displaying current temp- change to setpoint
dispMode=1;
break;
case 1:
//change to range
dispMode=2;
// WriteEEPROM(TargetFloat*10, setAdd);
break;
case 2:
//change to delay
dispMode=3;
// WriteEEPROM(RangeFloat*10, rangeAdd);
break;
case 3:
// change to current temp
dispMode=0;
// WriteEEPROM(waitTime, timeAdd);
break;
}
}
}
else {
int factor=0;
enter_state=false;
//read up or down press
if (digitalRead(up_pin)==HIGH){
udTime++;
if (udTime == udLimit){
factor=1;
udTime=0;
}
}
else if (digitalRead(dn_pin)==HIGH){
udTime--;
if (udTime <= (-1*udLimit)){
factor=-1;
udTime=0;
}
}
else {
udTime=0;
}
switch (dispMode){
case 1:
//adj target
TargetFloat=adjFloat(TargetFloat, TargetMin, TargetMax, factor, 0.5);
break;
case 2:
//adj range
RangeFloat=adjFloat(RangeFloat, 0.5 , RangeMax, factor, 0.5);
break;
case 3:
//adj wait
waitTime=adjFloat(waitTime, 0, waitMax, factor, 1);
break;
}
}
switch (dispMode){
case 0:
//display temp
printFloat10(tempF, 32);
break;
case 1:
printFloat10(TargetFloat,116);
break;
case 2:
printFloat10(RangeFloat, 114);
break;
case 3:
printFloat0(waitTime, 100);
break;
}
}
So there you go