Go Down

Topic: Brewing thermostat (Read 9 times) previous topic - next topic

bowlerhatman

Apr 17, 2011, 07:14 am Last Edit: Apr 19, 2011, 03:09 pm by bowlerhatman Reason: 1
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: [Select]

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



bowlerhatman

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.

pluggy

Code: [Select]
Highlight the code and click on the '#' button
http://pluggy.is-a-geek.com/index.html

bowlerhatman


wildbill

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

else if(tempc == right)


with this:
Code: [Select]

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: [Select]

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


could be this:
Code: [Select]

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

Saving you a whole 2 bytes!  ;)


PaulS

Code: [Select]
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: [Select]
tempc = ((100L * (long)analogRead(pin))/1024.0);

bowlerhatman

#6
Apr 19, 2011, 03:31 pm Last Edit: Apr 19, 2011, 03:46 pm by bowlerhatman Reason: 1
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.

bowlerhatman

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: [Select]


/*

  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.

bowlerhatman

#8
Apr 29, 2011, 01:52 pm Last Edit: Apr 29, 2011, 02:07 pm by bowlerhatman Reason: 1
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: [Select]

/*

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


wildbill

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

  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.

bowlerhatman

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

shanemiller


compuslave

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?


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'

bowlerhatman

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.

compuslave

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#

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'

Go Up