Arduino Development Thread

Australia & New Zealand Homebrewing Forum

Help Support Australia & New Zealand Homebrewing Forum:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.
I'll see how they go. Not the end of the world if I need to move to SSR's but I really like the I2C interface to these.
 
Edak said:
I would still recommend against mechanical relays for pid because of the electrical noise and associated glitches you will face. That is a lot of EMI and a Shitload of clicking noise!

Also if you are using 3x PID then you will use a lot more code space than the rest of us who use only one. I would go with the previous version of the mega, which you can source really cheaply these days. DX.com
EMI Causes lots of issues with Arduinos (I know from recent 1st hand experience). Even the 12v solenoid through an opto isolated relay board caused EMI. First thing to go on Arudino is serial comms when EMI is around making it a bugger to debug.

If you have any EMI issues go to Jaycar and buy a few "MS4001" for $5 each , place them near your load. Our you could spend weeks making RC snubbers and go mad
 
made a brauduino shield into a simple fermentation controller
SANY1642_zps0a32b87f.jpg



inside_zps508f224c.jpg


/*
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.
 
Hey Guys, I´m new here and eletronics stuffs, I´m from Brazil! Let me ask something. I have to change anything in the board to connect 2 pumps, 2 thermo heater? Or, I have to connect directly those pumps in the same conector.
 
vortex said:
I'll see how they go. Not the end of the world if I need to move to SSR's but I really like the I2C interface to these.
So I ended up getting some cheap SSRs and de-soldering some of the mechanical relays:


Relay board by auvortex, on Flickr

****** up one of the traces by getting it too hot when desoldering, and it came away from the board. Fortunately it was just the ground, so if my dodgy fix doesn't work I can just solder to another ground point pretty easily at least!

Flickr image above doesn't work, just click the link. Have the new seppo overlords nuked external images?
 
matho said:
made a brauduino shield into a simple fermentation controller
I'm interested in something like this (I think, not much of a programmer so very much muddling through it). What I'm after is a device to control a ferment temp with ranges for example start ferment at 18 degrees, let naturally warm to 21 then keep it steady there till finish.

Was considering using an rpi but am more than happy to kit up an arduino for it for sure. Any tips greatly appreciated.
 
Arduino can do that pretty easily at a basic level. Otherwise you could just use an STC1000, which will be easier and about the same cost. Depends if you actually want to get your hands dirty in code or not I guess.

If you're still interested in building, look for DS18B20 temp sensors, and for relays they can be controlled easily with the onboard pins.
 
vortex said:
Arduino can do that pretty easily at a basic level. Otherwise you could just use an STC1000, which will be easier and about the same cost. Depends if you actually want to get your hands dirty in code or not I guess.

If you're still interested in building, look for DS18B20 temp sensors, and for relays they can be controlled easily with the onboard pins.
I'm looking to more automate the entire process from pitching basically, so have something sitting there watching the temp from initial until it hits the target on it's own then kick on, rather than me have to turn something on, constantly check an stc etc.

I'm willing to learn code for it but at this stage don't really have a great deal of knowledge on it. More the hardware production side of things normally.
 
My guess around the $90: Raspberry is $50 odd, then an arduino say $10-15, so bling factor and the no f#*king around with multiple boards, cables, and power supplies, costs $30, oh and for the brewpi project I was looking at a usb hub to break out a second board for 2nd ferm chamber, this would skip that, as it has 4 host ports instead of 2 on the pi. I supose we'll see early next year.
 
I really like the idea of spark core, I wish they had been around when building controllers for fermenting fridge and keezer. No more dismantling boxes to reprogram.
 
I don't like the Tre. Seems like a hack to try and win back some of the RasPi crowd back to an Arduino based device.

My Arduinos basically went in the bin when I got my RasPi's and BeagleBone's (white and black) and I don't see them ever coming out again. Doesn't make sense to me to plug an Arduino into a RasPi like in BrewPi when the RasPi can do everything the Arduino can do..
 
lael said:
Be nice if they included wifi on it like the spark core!
Has a dedicated wireless port ... Xbee I think was mentioned though I don't know what protocols that uses

Ed. I do agree wifi should have been included on board and was a glaring omission on the Raspberrypi for the very reasons Edak mentions, even if you just want a standalone device, the ease of reprogramming is obvious
 
The benefit of having Arduino connected to raspberry pi is that a more complex system is more likely to fail and thus in the event of failure or lock up of the processor, the low level operations will always run and control beer comfortably.
 
Back
Top