made a brauduino shield into a simple fermentation controller
/*
brauduino semi automated single vessel RIMS
created by s.mathison
using part code orginal developed by Michael Pilcher 2/9/2010
Copyright (C) 2012 Stephen Mathison
compiled on Arduino V1.0
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.*/
//libraries
#include <EEPROM.h>
#include <LiquidCrystal.h>
#include <OneWire.h>
#include <avr/pgmspace.h>
OneWire ds(11);
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
// push buttons
const char Button_up = A3;
const char Button_dn = A2;
const char Button_prev = A1;
const char Button_nxt = A0;
// outputs
const int Heat = 9;
const int Cool = 8;
const int Buzz = 10;
//Global Variables
unsigned long convStartTime,displayTime,start,buttonPress;
float Temp_c,setTemp,hyst;
byte data[2];
byte firstNumber;
byte secondNumber;
byte remainder;
byte second;
byte minute;
byte hour;
byte day;
byte compDelay;
byte compTime;
const byte gBigFontShapeTable[] PROGMEM = {
//* LT[8] =
B00111,
B01111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
//* UB[8] =
B11111,
B11111,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000,
//* RT[8] =
B11100,
B11110,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
//* LL[8] =
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B01111,
B00111,
//* LB[8] =
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111,
//* LR[8] =
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11110,
B11100,
//* UMB[8] =
B11111,
B11111,
B11111,
B00000,
B00000,
B00000,
B11111,
B11111,
//* LMB[8] =
B11111,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111
};
const byte gBigFontAsciiTable[] PROGMEM = {
0, 1, 2, 3, 4, 5, // 0x30 0
1, 2, 32, 32, 255, 32, // 0x31 1
6, 6, 2, 3, 7, 7, // 0x32 2
6, 6, 2, 7, 7, 5, // 0x33 3
3, 4, 2, 32, 32, 5, // 0x34 4
255, 6, 6, 7, 7, 5, // 0x35 5
// 0, 6, 6, 7, 7, 5, // 0x35 5
0, 6, 6, 3, 7, 5, // 0x36 6
1, 1, 2, 32, 0, 32, // 0x37 7
0, 6, 2, 3, 7, 5, // 0x38 8
0, 6, 2, 32, 32, 255, // 0x39 9
};
boolean Conv_start = false;
boolean run = false;
boolean cool_on = false;
boolean showlp = false;
//***********Start of the Functions***************
static void BigNumber_SendCustomChars(void)
{
uint8_t customCharDef[10];
uint8_t ii;
int jj;
for (ii=0; ii<8; ii++)
{
for (jj=0; jj<8; jj++)
{
customCharDef[jj] = pgm_read_byte_near(gBigFontShapeTable + (ii * 8) + jj);
}
lcd.createChar(ii, customCharDef);
}
}
// 1 second button press
int Button_1sec_press (int Button_press){
if (digitalRead(Button_press)==0){
delay (1000);
if (digitalRead(Button_press)==0){
lcd.clear();
while(digitalRead(Button_press)==0){
}
return 1;
}
}
return 0;
}
// repeat button press
int Button_repeat (int Button_press){
if (digitalRead(Button_press)==0){
delay(200);
return 1;
}
return 0;
}
// holds whilst button pressed
int Button_hold_press (int Button_press){
if (digitalRead (Button_press)==0){
delay(50);
while (digitalRead (Button_press)==0){
}
return 1;
}
return 0;
}
void display_lcd (int pos , int line ,const char* lable){
lcd.setCursor(pos,line);
lcd.print(lable);
}
// reads the DS18B20 temerature probe
void Temperature(void){
// start conversion and return
if (!(Conv_start)){
ds.reset();
ds.skip();
ds.write(0x44,0);
Conv_start = true;
convStartTime = millis();
return;
}
// check for conversion if it isn't complete return if it is then convert to decimal
if (Conv_start){
if ((millis()-convStartTime)<1000){
return;
}
ds.reset();
ds.skip();
ds.write(0xBE);
for ( int i = 0; i < 2; i++) { // we need 2 bytes
data
= ds.read();
}
unsigned int raw = (data[1] << 8) + data[0];
unsigned int whole = (raw >>4);
unsigned int remain = (raw & 0X000f);
Temp_c = (raw) * 0.0625;
firstNumber = whole/10;
secondNumber = whole%10;
remainder = (remain * 10)/16;
Conv_start = false;
return;
}
}
//************************************************************************
//* returns the width of the character
static int DrawBigChar(byte theChar , int xLocation)
{
int offset;
int ii;
byte theByte;
offset = theChar *6;
lcd.setCursor(xLocation, 0);
for (ii=0; ii<3; ii++)
{
theByte = pgm_read_byte_near(gBigFontAsciiTable + offset + ii);
lcd.write(theByte);
}
lcd.setCursor(xLocation, 1);
offset += 3;
for (ii=0; ii<3; ii++)
{
theByte = pgm_read_byte_near(gBigFontAsciiTable + offset + ii);
lcd.write(theByte);
}
}
// displays large font numbers
void PrintDegC(void){
lcd.setCursor(13,0);
lcd.print("o");
lcd.setCursor(8,1);
lcd.write(4);
lcd.setCursor(14,1);
lcd.write(8);
lcd.write(6);
}
//Prints current Temperature in large font
void displayBigTemp(){
DrawBigChar(firstNumber,0);
DrawBigChar(secondNumber,4);
lcd.setCursor(8,1);
lcd.write(4);
DrawBigChar(remainder,10);
PrintDegC();
}
//Timing of the fermentation
void ferment_timing()
{
if ((millis()-start)>1000){ // timing routine
start = millis();
second++;
if (second>59){
second = 0;
minute++;
if(minute>59){
minute = 0;
hour++;
if(hour>23){
hour=0;
day++;
}
}
}
}
}
float change_temp(float& temp_change,int upper_limit,int lower_limit)
{
// Increase set temp
if (Button_repeat(Button_up)){
temp_change+=0.1;
if (temp_change > upper_limit)temp_change = upper_limit;
}
// decrease temp
if (Button_repeat(Button_dn)){
temp_change-=0.1;
if ( temp_change < lower_limit) temp_change = lower_limit;
}
}
void heatOff(){
digitalWrite(Heat,LOW);
}
void heatOn(){
digitalWrite(Heat,HIGH);
}
void coolOff(){
digitalWrite(Cool,LOW);
if (cool_on){
compTime = minute;
cool_on =false;
}
}
void coolOn(){
if ((minute - compTime)>= compDelay){
digitalWrite(Cool,HIGH);
cool_on= true;
}
}
void save_settings (int addr,int data)
{
EEPROM.write(addr,highByte(data));
EEPROM.write((addr+1),lowByte(data));
}
void save_settings (int addr,byte data){
EEPROM.write(addr,data);
}
int change_set(byte& set_change,int upper_limit,int lower_limit,int step_size)
{
// Increase set temp
if (Button_repeat(Button_up)){
set_change+=step_size;
display_lcd(0,1," ");
}
if (set_change > upper_limit)set_change = upper_limit;
// decrease temp
if (Button_repeat(Button_dn))
{
set_change-=step_size;
display_lcd(0,1," ");
}
if ( set_change < lower_limit) set_change = lower_limit;
}
// settings for the unit
void set(){
for(int i=0;i<3;i++){
boolean setLoop = true;
byte setting;
float settingFloat;
int settingWord;
if (i==0){
setTemp= word(EEPROM.read(50),EEPROM.read(51));
setTemp=setTemp/10.0;
while (setLoop){
display_lcd (0,0,"Set Temp = ");
lcd.print(setTemp);
change_temp(setTemp,35,2);
if(Button_hold_press(Button_nxt)){
setTemp=setTemp * 10;
settingWord = word(setTemp);
save_settings(50,settingWord);
setLoop = false;
}
}
}
if (i==1){
setting = (EEPROM.read(52));
display_lcd(0,0," ");
while (setLoop){
settingFloat =setting/10.0;
display_lcd (0,0,"Hyst = ");
lcd.print(settingFloat);
change_set(setting,20,1,1);
if(Button_hold_press(Button_nxt)){
save_settings(52,setting);
setLoop = false;
}
}
}
if (i==2){
setting = EEPROM.read(53);
display_lcd(0,0," ");
while (setLoop){
display_lcd (0,0,"Comp Delay = ");
lcd.print(setting);
change_set(setting,9,2,1);
if(Button_hold_press(Button_nxt)){
save_settings(53,setting);
setLoop = false;
setTemp = word(EEPROM.read(50),EEPROM.read(51));
setTemp = setTemp/10.0;
lcd.clear();
}
}
}
}
}
void loadSettings(){
setTemp = word(EEPROM.read(50),EEPROM.read(51))/10.0;
hyst = EEPROM.read(52)/10.0;
compDelay = EEPROM.read(53);
}
//control process
void control(){
loadSettings();
while (run){
Temperature();
if (showlp){
display_lcd(0,0,"Time=");
lcd.print(day);
lcd.print(":");
lcd.print(hour);
lcd.print(":");
lcd.print(minute);
lcd.print(":");
if(second<10)lcd.print("0");
lcd.print(second);
display_lcd(0,1,"S/A=");
lcd.print(setTemp);
lcd.print("/");
lcd.print(Temp_c);
change_temp(setTemp,35,2);
if (Button_hold_press(Button_nxt)){
lcd.clear();
showlp =false;
}
}
else displayBigTemp();
ferment_timing();
if (Temp_c>=setTemp)heatOff();
if (Temp_c<=setTemp)coolOff();
if (Temp_c<=(setTemp-hyst))heatOn();
if (Temp_c>=(setTemp-hyst))coolOn();
if (Button_hold_press(Button_nxt)){
showlp = true;
lcd.clear();
}
if (Button_1sec_press(Button_prev))run= false;
}
}
void setup(){
lcd.begin(16,2);
pinMode (Button_up,INPUT);
pinMode (Button_dn,INPUT);
pinMode (Button_prev,INPUT);
pinMode (Button_nxt,INPUT);
pinMode (Heat,OUTPUT);
pinMode (Cool,OUTPUT);
pinMode (Buzz,OUTPUT);
// assignes each segment a write number
BigNumber_SendCustomChars();
setTemp = word(EEPROM.read(50),EEPROM.read(51));
setTemp = setTemp/10.0;
}
void loop(){
if (Button_1sec_press(Button_prev)){
run = true;
control();
}
if (Button_1sec_press(Button_nxt)){
set();
}
digitalWrite(Heat,LOW);
digitalWrite(Cool,LOW);
second = 0;
minute = 0;
hour = 0 ;
day = 0;
display_lcd(1,0,"Ferment Control");
display_lcd(1,1,"Set Temp = ");
lcd.print(setTemp);
}
I'm thinking I might merge the two codes as they share a fair bit and make an all in one controller. I had the LCD scramble when switching the fridge so I put a 2200uF 16v electrolytic cap across the 12v supply to de-couple it a bit more, it has seemed to fix the problem.