Pages: [1] 2   Go Down
Author Topic: Brewing thermostat  (Read 8874 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm not sure if this is the best place to put this topic, but I couldn't really see a better one. Anyway, I'm building a thermostat for brewing beer. I looked around at other people's projects for a bit and found that was no standalone thermostat, they all featured a permanent serial or network connection of some sort. I have no use for this feature after debugging is complete, so I left it out. Here is my first prototype. Any comments or suggestions would be welcomed!
Code:
/* This is a thermostat (originally) intended for homebrewing beer without having to worry about temperature. It has no connection to the internet, or in fact,
even to a computer once debugging is complete. It doesn't need it.

The circuit is simple, 1 LED for visual feedback, 2 relays connected through BC548 transistors, a bigger relay for the heating device, and a piezo buzzer for audible feedback.
A schematic diagram can be found at http://frazer-makingstuffup.blogspot.com/2011/04/homebrew-homebrewing-thermostat.html

*/


int HEAT =2;                         // to BC548 controlling a reed relay, which in turn drives a relay capable of switching 240V
int INDICATE = 3;                   //visual feedback
int ALARM = 4;                      //audible feedback
int pin = 0;                           // analog pin
int raw_temp = 0;                 //from sensor
int tempc = 0;                      // temperature variable
int too_cold = 17;                  // set minimum temperature acceptable
int cold = 21;                        // set low range
int right = 22;                      // set desired temperature  
int too_hot = 24;                  // set maximum acceptable temperature


void setup()
{
  Serial.begin(9600);
  pinMode( HEAT, OUTPUT);          //all digital pins are outputs
  pinMode(INDICATE, OUTPUT);
  pinMode(ALARM, OUTPUT);
  analogReference(INTERNAL);
}

void loop()
{  

raw_temp = analogRead(pin);          // get reading from LM35
tempc = ((100* raw_temp)/1024.0);    // convert to whole decimal degrees

 
Serial.println(tempc);               //serial print used for debugging,can be left out in the final installation, but can't hurt to leave it in


if(tempc <= too_cold )                // if temperature is less than or equal to the minimum temperature acceptable
{
  digitalWrite(HEAT, HIGH);           // turn on the heater and the audible feedback
  digitalWrite(INDICATE, HIGH);      
  digitalWrite(ALARM, HIGH);          //also flash the visual feedback
                                      
  delay(100);                      
                                    
  digitalWrite(HEAT, HIGH);          
  digitalWrite(INDICATE, LOW);      
 digitalWrite(ALARM, [HIGH);          

}
elseif(tempc <= cold)                // if temperature is colder than the desired temperature, but warmer than the minimum                        
{
  digitalWrite(HEAT, HIGH);          // turn on the heater                            
  digitalWrite(INDICATE, HIGH);      // provide static visual feedback                          
  digitalWrite(ALARM, LOW);          // no audible feedback                      
}

 else if(tempc == right)             // if the desired temperature has been reached
 {
  
   digitalWrite(HEAT, LOW);           // no heating  
   digitalWrite(INDICATE, LOW);       // no visual feedback        
   digitalWrite(ALARM, LOW);          // no audible feedback  
 }
 
 else if(tempc >= too_hot)         // if temperature is too high    
 {                    
   digitalWrite(HEAT, LOW);          // no heating        
   digitalWrite(INDICATE, HIGH);      // audible feedback          
   digitalWrite(ALARM, HIGH);         // visual feedback flashing      
  
   delay(100);                        //  
  
   digitalWrite(HEAT, LOW);          
   digitalWrite(INDICATE, LOW);  
   digitalWrite(ALARM, HIGH);    
 
}
  
  

 tempc = 0;                          // reset tempc to 0

delay(1000);                         // delay 1 second before re-looping
}

« Last Edit: April 19, 2011, 08:09:35 am by bowlerhatman » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

P.S.

How do I do that thing where the code comes up in an internal window with all the normal Arduino IDE formatting? I tried the 'copy to forum' option, but when I put it in, the page filled up with HTML tags as well, and they carried over into the proper post.
Logged

Lancashire, UK
Offline Offline
Edison Member
*
Karma: 9
Posts: 1991
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
Highlight the code and click on the '#' button
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Pluggy.
Logged

New Jersey
Offline Offline
Faraday Member
**
Karma: 65
Posts: 3643
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Looks fine. The only change I'd make would be to replace this:
Code:
else if(tempc == right)

with this:
Code:
else if(tempc < too_hot)

It's highly unlikely in a brewing scenario, given one temperature sample a second that you would miss the 22 degree setting, but if you did, the heater would stay on until you reached too_hot, which wouldn't do your beer any favours.

With a gun to my head and asked to find other things to complain about, I could find these:
The constants such as too_hot should either be declared const or done with #define
When it is too cold, you turn on the heat and the audible twice - no need
Setting temp_c=0 at the end of loop is unnecessary

finally, with nitpick mode set to the max, you only use raw_temp once, so this:
Code:
raw_temp = analogRead(pin);          // get reading from LM35
tempc = ((100* raw_temp)/1024.0);    // convert to whole decimal degrees

could be this:
Code:
tempc = ((100* analogRead(pin))/1024.0);
Saving you a whole 2 bytes!  smiley-wink

 
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48569
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
tempc = ((100* analogRead(pin))/1024.0);
What happens if the analogRead() returns a value greater than 327? 328 * 100 = 32800, which won't fit in an int. The output from analogRead needs to be cast to a long, and multiplied by a long, to avoid overflow.

Code:
tempc = ((100L * (long)analogRead(pin))/1024.0);
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Paul, you've just answered a question that I had. When the thermostat reached 32 degrees, it would flip over to -31 degrees. That would be the overflow of which you speak. With that change to a long, I'm happily reading 69 degrees. The sensor has a range up to 100,and can read up to 99, which is a range of 100.


Wildbill, thanks for the suggestions, I've put them in place. I'm still pretty new to programming, so they were quite valuable tips. The suggestion about tempc == right vs. tempc < too_hot was particularly good, I hadn't even thought of that.
« Last Edit: April 19, 2011, 08:46:03 am by bowlerhatman » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The thermostat is now running on my vat in the shed, keeping a nice dark ale at 22 degrees. I've got a working prototype of a new model with easily adjustable temperature setting and a display that reads the set temperature, the actual temperature, and the status of the heater. Here is the code:
Code:

/*
 
  The circuit:
 * LCD RS pin to digital pin 8
 * LCD Enable pin to digital pin 9
 * LCD D4 pin to digital pin 10
 * LCD D5 pin to digital pin 11
 * LCD D6 pin to digital pin 12
 * LCD D7 pin to digital pin 13
 * 10K resistor:
   * ends to +5V and ground
   * wiper to LCD VO pin (pin 3)
 
 *relay connected to D0 to control heating element
 *LED connected to D4 as quick visual indicator
 *LM35 temperature sensor to A0
 *1K Linear pot to A5 for adjustment
 
 */

// include the library code:
#include <LiquidCrystal.h>

int des = 0;   //set temperature variable
int pin = 1;   //LM35 input
int tempc = 0; //temperature variable
int pot = 5;   //temperature adjust input

int heat = 0;
int indicate = 4;

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);

void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.print("SET: ACT: HEAT?");  // Print headings the LCD.
  analogReference(INTERNAL);     
  pinMode(heat, OUTPUT);
  pinMode(indicate, OUTPUT);
  }

void loop(){
  analogRead(pin);
  delay(5);
  tempc = (100* (long)analogRead(pin)/1024.0);  //save temperature reading as 'tempc'
  delay(5);
  analogRead(pot);
  delay(5);
  des =  analogRead(pot)/34.14;     //saves pot reading as 'des'
                                    //gives a range of about 30
 
     
  lcd.setCursor(1, 1);
  lcd.print("  ");     //clear field
  lcd.setCursor(1, 1);
  lcd.print(des);     //print set temperature
   
  lcd.setCursor(6,1);
  lcd.print("  ");    //clear field
  lcd.setCursor(6,1);
  lcd.print(tempc );  //print actual temperature
   
 
  if(tempc <= des){                 //if actual temperature is less than
    digitalWrite(heat, HIGH);       //or equal to the set temperature, turn the heater on
    digitalWrite(indicate, HIGH);
    lcd.setCursor(11,1);
    lcd.print("ON ");
}
  else  if(tempc > des){             //otherwise leave the heater off
    digitalWrite(heat, LOW);
    digitalWrite(indicate, LOW);
    lcd.setCursor(11,1);
    lcd.print("OFF");
}
delay(100);
}


I would like to have a button that enters into a 'temperature set' mode so that the potentiometer won't affect the settings unless intended to, but I can't get that working. I'll play with it a bit more and post a bit later.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is my most recent code, using up/down buttons instead of a pot for temperature control. I still can't get the 'if buttonpress == true, enter set mode' function to happen though, but this is close enough for the moment:
Code:
/*
 
  The circuit:
 * LCD RS pin to digital pin 8
 * LCD Enable pin to digital pin 9
 * LCD D4 pin to digital pin 10
 * LCD D5 pin to digital pin 11
 * LCD D6 pin to digital pin 12
 * LCD D7 pin to digital pin 13
 * 10K resistor:
   * ends to +5V and ground
   * wiper to LCD VO pin (pin 3)
 
 *relay connected to D0 to control heating element
 *LED connected to D4 as quick visual indicator
 *LM35 temperature sensor to A0
 *up and down buttons to D1 and D2
 
 */



#include <LiquidCrystal.h>

int des = 20;           //set temperature variable
int lastdes = 0;
int tempc = 0;          //temperature variable
int Counter1 = 0;       // counter for the number of button presses
int Counter2 = 0;       // counter for the number of button presses
int State1 = 0;         // current state of the button
int State2 = 0;         // current state of the button
int lastState1 = 0;     // previous state of the button
int lastState2 = 0;
int val = 0;





int pin = 1;            //LM35 input
const int set1 = 1;     //temp up and temp down buttons
const int set2 = 2;
int heat = 0;           //output to heater control
int indicate = 4;       //visual indicator output


LiquidCrystal lcd(8, 9, 10, 11, 12, 13);   // initialize the library with the numbers of the interface pins

void setup() {
  lcd.begin(16, 2);
  lcd.print("SET: ACT: HEAT?");  // Print headings to the LCD.
  analogReference(INTERNAL);    
  pinMode(heat, OUTPUT);
  pinMode(indicate, OUTPUT);
  pinMode(set1, INPUT);
  pinMode(set2, INPUT);

}

void loop() {
 State1 = digitalRead(set1);
  State2 = digitalRead(set2);  
  if (State1 != lastState1) {
        if (State1 == HIGH && des!= 100) {      //if up button is pressed, add 1 to des
        des++;
     }
    
  }
  
  if (State2 != lastState2) {  //if down button is pressed, subtract 1 from des
       if (State2 == HIGH && des != 0) {
       des--;
    }
  }
  analogRead(pin);
  delay(10);
  tempc = (100* (long)analogRead(pin)/1024.0);  //save temperature reading as 'tempc'
  delay(1);                                     //gives a range of about 30
  
  lcd.setCursor(1, 1);
  lcd.print("    ");     //clear field
  lcd.setCursor(1, 1);
  lcd.print(des);     //print set temperature
  
   delay(50);
  lcd.setCursor(6,1);
  lcd.print("  ");    //clear field
  lcd.setCursor(6,1);
  lcd.print(tempc );  //print actual temperature
  
delay(50);
  if(tempc <= des){                 //if actual temperature is less than
    digitalWrite(heat, HIGH);       //or equal to the set temperature, turn the heater on
    digitalWrite(indicate, HIGH);
    lcd.setCursor(11,1);
    lcd.print("ON ");
    delay(50);
}
  else  if(tempc > des){             //otherwise leave the heater off
    digitalWrite(heat, LOW);
    digitalWrite(indicate, LOW);
    lcd.setCursor(11,1);
    lcd.print("OFF");
  
  }
}
« Last Edit: April 29, 2011, 07:07:09 am by bowlerhatman » Logged

New Jersey
Offline Offline
Faraday Member
**
Karma: 65
Posts: 3643
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you're still looking for coding input, this doesn't look quite right:
Code:
  if (State1 != lastState1) {
        if (State1 == HIGH && des!= 100) {      //if up button is pressed, add 1 to des
        des++;
     }

You never do anything with lastState1, it's always 0. It looks like part of a debounce routine, but isn't debouncing at the moment - I assume the delays later in loop are actually taking care of the bounce issue, whether intended or not.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks, that was indeed leftover code from debouncing that proved redundant.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Looks cool..smiley
Logged

Hyperspace
Offline Offline
Jr. Member
**
Karma: 0
Posts: 60
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm a homebrewer too, and plan on a project like this soon. Rather than arduino-ify the fermentation portion of the process, I am leaning more towards the mash. American science surplus has these cool little heaters from coffee pots right now and they are dirt cheap (2 for $1.25) I got 4 or them and plan on pump the mash liquor around them (in copper tubing of course) to give me a fully programmable and consistent step up and possibly even programmable decotion mashing.  How about an update? How's it working for you?

The heaters I was talking about http://www.sciplus.com/recommend.cfm/recommendid/4157

My plan is to use this relay http://www.sparkfun.com/products/10636 with a pot to adjust pwm in to the relay. I'll be using one of these http://www.sparkfun.com/products/250 to monitor temperature and would very much like to add my http://www.sparkfun.com/products/10168 to the project for visual feedback since it's doing little more than occupying space in my parts box right now. But, as of now this project is beyond my capability.

It does seem easy enough, I just have to learn , ie get these guys to help me, to do it.

What a great site, I love this place! Who needs school when you got all these brilliantly deviant minds in one spot on teh interwebz?

 
Logged

Never judge a man until you walk a mile in his shoes. But, by that time you're a mile away and you got his shoes, so screw em'

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

One day when I'm a genius I'll get up to all-grain brews, at which point I 'll experiment with a similar project, but for now the brewing stage is a good start. The main motivation for it was that I don't have much space, so I wanted to put my vat in the shed, which gets awfully cold. I'm in the process of trying to box it all up into an enclosure at the moment, but I've done something wrong in the transition and I can't for the life of me figure out what. The feedback-free prototype has been working very effectively for the past week-and-a-bit though, and I'll be bottling on Saturday. I love the look of those heaters, but alas, American Science & Surplus don't ship to Australia, otherwise I would jump on that.

You're right, it is quite easy, this is my first project that incorporates programming of any description, and with the help of these fellows and some books, it has been a rewarding challenge, though eminently possible.
Logged

Hyperspace
Offline Offline
Jr. Member
**
Karma: 0
Posts: 60
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

First of all, you have no need for genius to brew with all grain. It's the oldest form of brewing there is and quite simple. I made a video of me brewing an all grain batch that many people really enjoyed, but google just removed it along with all the other videos they hosted. As soon as I find another host I will upload it and post the link here (It's too big for youtube, apparently) so you can see just how easy it is. With your shed being so cold you should brew a lager. Being here in the states we have to build things or buy gadgets for freezers to brew lagers. Brew a couple lagers and forget about them. Go about your ale making and in a few months you'll have homebrewed perfection waiting on. I can't be much help with electronics as I am here to learn from the very beginning almost, but as far as brewing I'll help you any way I can. Also, if you really want one of those heaters I'll ship you a couple. Is it crazy expensive to ship or something? I'm not even worried about you paying me for them. I think I can spare $1.25  smiley-grin, it's the shipping that might scare me.

You were talking about boxing your whole thing up, google "son of a fermentation chamber". Instead of cooling, just change the chillings bits to heating bits. Super cheap and easy to build.

Edit:Holy crap! It appears the video is still up for the moment! Enjoy!
http://video.google.com/videoplay?docid=-8400604593450308344#

Logged

Never judge a man until you walk a mile in his shoes. But, by that time you're a mile away and you got his shoes, so screw em'

Pages: [1] 2   Go Up
Jump to: