Brewing thermostat

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!

/* 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
}

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.

Highlight the code and click on the '#' button

Thanks Pluggy.

Looks fine. The only change I'd make would be to replace this:

 else if(tempc == right)

with this:

 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:

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

could be this:

tempc = ((100* analogRead(pin))/1024.0);

Saving you a whole 2 bytes! :wink:

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.

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

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.

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:

/*
 
  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.

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:

/*
 
  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");
  
  }
}

If you're still looking for coding input, this doesn't look quite right:

  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.

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

Looks cool..:slight_smile:

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 Solid State Relay - 8A - COM-10636 - SparkFun Electronics with a pot to adjust pwm in to the relay. I'll be using one of these Thermistor 10K - SEN-00250 - SparkFun Electronics 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?

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.

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 :D, 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#

Thanks for that, if I have any questions I'll be sure to come to you! That would actually be great if you could ship me some of those, I'll PM you. I'm not sure why they don't ship to Australia, but I tried to get some things from them a while ago and they refused to send to me.

With boxing it up, I was referring to the electronics rather than the whole system, but when I have room I intend to hack an old fridge as an insulated brew-box.

I've been doing the hardware side of things since I was 12, so I can offer you some help there if you like, though it is just a hobby of mine, my main pursuit being Classical History.

You can't get more classical history than brewing your own beer. Much like killing an antelope with a stick you sharpened on a rock and eating it raw...... well maybe not that dramatic, but you get the point :stuck_out_tongue:

compuslave:
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

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

Howdy, have you tried these little babies yet? I was planning on a gas RIMS system - couldn't be bothered with a stainless steel electric system) so was wondering how you got on with these.

I'm heading over to the states soon, so might order a few to have waiting for me when I get there.

Still trying to get this damned thing to work, the whole thing works perfectly on the breadboard, but as soon as I try to migrate it to vero board or a PCB, it fails. I'm up to my second PCB design, I gave up on vero board after 3 failures, I have absolutely no clue what is going wrong. Does anyone have any ideas? I've checked and double-checked my connections, there are no short circuits that I've found. The one error I have found I have corrected. Any ideas would be greatly appreciated.

One of the electronics wizards can probably help you, but they'll need a bit more detail. Some pictures might help.