Fermentation Temperature Controller


The optimal temperature for the fermentation of beer is around 20°C, depending on the yeast strain. Let the beer ferment at too high a temperature and off-flavours will be produced, too cold and the fermentation may stall.  Realistically, you can leave the beer to ferment in a room which is roughly the right temperature and make good beer.  However, with a little effort, it’s possible to convert a fridge or freezer into the ideal fermentation temperature controller.

The Design

Many people simply hook one of these up to fridge and tube heater.  Put your fermentation bucket inside the fridge and the TC-10 will switch the fridge on when its too hot and switch the heater on when it’s too cold.  The main problem with the TC-10 and other similar devices (other than their high price tag!) is that they don’t log temperature over time.

With this in mind, I designed my own temperature controller, based on the TC-10, but with the added feature of temperature logging.

At the heart of my design is a PIC16F88 microcontroller.  This reads the temperature from the digital DS18B20+ thermometer, saves the temperature to a 512Kb EEPROM, displays the temperature to an LCD display and finally controls two relays to switch the heating and cooling circuits using a simple on-off control scheme.  A MAX232 is used to send EEPROM data over RS232 serial to a computer.

Here are the circuit diagram and single sided PCB:

(These can be downloaded in Eagle format here).

Writing the PIC Firmware

The PIC firmware is written in C, using the Hi-Tech compiler.  Hi-Tech provide some libraries for common tasks, which for the most part, proved useful.  I used the lcd.c library to control the LCD (with some modification to allow connection to any combination of IO pins) and the 1wire library for communication with the DS18B20+ thermometer.

The only problem was the I²C library provided by Hi-Tech, needed to communicate with the EEPROM.  After many hours of hair pulling (and coming extremely close to purchasing a Logic Analyser!), I discovered a bug in the I²C library itself.

Here’s the i2c_Stop function copied from the library.  Take a look at the spec here… this code is clearly wrong! SDA should transition from low to high, so the second line is wrong.

void i2c_Stop(void)
/* don't assume SCL is high on entry */

SDA_LOW();                    /* ensure data is low first */

SCL_DIR = I2C_INPUT;        /* float clock high */
SDA_HIGH();                    /* the low->high data transistion */
__delay_us(I2C_TM_BUS_FREE);    /* bus free time before next start */
SDA_DIR = I2C_INPUT;        /* float data high */


The fix is simple:

/* don't assume SCL is high on entry */

SDA_LOW();                    /* ensure data is low first */
SCL_LOW();                    /* ensure clock is low first */

SCL_DIR = I2C_INPUT;        /* float clock high */
SDA_HIGH();                    /* the low->high data transistion */
__delay_us(I2C_TM_BUS_FREE);    /* bus free time before next start */
SDA_DIR = I2C_INPUT;        /* float data high */


With that fixed, the rest was reasonably straightforward.  A Real Time Clock (RTC) was programmed using interrupts (on testing, it loses roughly a second every hour, which is fine for my purposes!) and care was taken to save state parameters (such as current time, the EEPROM pointer etc.) to the PIC’s internal EEPROM to protect against power cuts.

Using the RTC, the firmware performs on-off control with a period 8 minutes.  This is to ensure the fridge/freezer isn’t turned on and off too rapidly, which may shorten it’s life as well as the life of the relays.  Temperature and relay state is saved to EEPROM every 4 minutes, which allows up to 45 days of logging.

The On-Off Control Scheme

The following C code implements on-off control.

void control_temp(void)
//only control every 8 minutes
if(minutes%8 != 0 || minutes == minutes_when_checked_temp)

minutes_when_checked_temp = minutes;

if(temp > 30 || temp < 5)    //if erroneous measurement, switch everything off!

if(temp > setpoint + 0.5)
else if(temp < setpoint - 0.5)

Note there is a hysteresis of ±0.5°C.  This parameter might need tweaking depending on the performance of the system.

Download the firmware here.

Reading the EEPROM Temperature Log

The MAX232 allows connection of the PIC16F88 to the serial port of a computer.  The PIC is set to interrupt on each received byte.  If the byte read is ASCII ‘A’ (0×41), it will read and transmit the contents of the EEPROM over the serial port.  I wrote a small C# application to to send this control byte, parse the received output and save the result to a CSV file which can then be opened in Excel.

This is the first program I’ve written in C#, but I found it to be a fairly painless experience.  I based the program on the SerialPort example by Noah Coad.

The only interesting part of the code is handling the quirky float implementation of Hi-Tech’s C compiler for the PIC.  Hi-Tech base their implementation on the IEEE-754 floating pointing standard, but truncate the first byte (presumably to save space and speed up performance – the PIC has no FPU, so floats have to be implemented in software!).  The example below shows the hex representation of 24.5 in Hi-Tech and IEEE-754:

//float: 24.500000, hex: 00 C4 41 (Hi-Tech truncated format)
//float: 24.500000, hex: 00 00 C4 41 (IEEE-754)

Once the format is understood (took me some time to find out this info!), the conversion in software is simple. In fact, this truncated format is actually quite handy, as it saves precious EEPROM space.

Here’s a screenshot of the program:

As soon as you open the COM port, you start receiving output from the PIC, which continually sends the time from the RTC and occasionally some debug information.  When the ‘Go’ button is pressed, the ‘A’ command is sent.  The PIC then sends all the EEPROM data.  This is parsed and the log file saved.

Download the Data Retrieval Source Code

Building the Controller

The PCB was etched using the method explained in my previous post.  Here are a few pictures of the PCB after soldering:

Note the relays can handle up to 12A at mains voltage, more than enough for a fridge/freezer.  I also added a thick layer of solder to the traces carrying mains current to ensure resistance is low (wouldn’t want to start a fire!).

Here are a few pictures of the circuit mounted in an ABS plastic box:

The wire to the left provides 5V DC to power the electronics.  The three wires at the top are mains power in and heater and cooler power out.  The thin wire to the right is the temperature probe.  The buttons on the front allow the desired temperature to be set.

I purchased a DS18B20+ digital thermometer packaged in waterproof steel probe.  Here’s a close up of the end of the probe:

Close up of the temperature probe.

The controller needs two power connections:

Power. Left is power to heater/cooler, right is 5V power for electronics.

For cooling, I used an old freezer.  This also provides good insulation.  A hard-wired incandescent light bulb is used for heating, which is cheaper than, but just as effective as, a tubular heater.

Light bulb (for heating) and the temperature probe inside the freezer.

The freezer plugs into a trailing socket, thus requiring no modification of the freezer itself (whether or not the internal thermostat needs disabling remains to be seen):

Black trailing socket which the freezer plugs into.

The fermentation controller is now complete!  It’s time for testing.

Testing the Fermentation Temperature Controller

I initially tested the system by just placing the probe in the freezer, setting the desired temperature to 20°C and letting it run.  The light bulb came on (it was only 11°C in the garage!) and quickly heated the air in the freezer to over 25°C in under 5 minutes.  After the 8 minute period had elapsed, the freezer would have immediately switched on, had it been plugged in.  Obviously this behaviour is very inefficient!

One way to solve this problem would be to reduce the period of the on-off control, but this would quickly wear out the relays (and possibly break the freezer compressor), as previously mentioned.  Instead, I tried putting the probe in a glass of water:

This seemed to work better.  It took 16 minutes to raise the temperature of the water from 18°C to 20°C.

The First Fermentation

I was happy enough with the above results to give a real fermentation a go.  So after a days brewing it was time to test it for real!  I set it up as before – the sensor placed in a glass of water (this time mixed with some steriliser) and a 100W light bulb.  I decided not to place the sensor in the beer itself, as it’s just one more source of possible infection.

Here’s the brew after the first night fermenting:

I downloaded the temperature log in the morning using the data retrieval software previously explained with a laptop and a RS232 to USB converter cable:

And made a plot of the temperature against time:

This actually came as a bit of a surprise.  The desired temperature was set to 20°C.  Hour zero represents the time at which the beer went into the fermenter (I had left it running empty before putting the beer in to get it up to temperature and then reset the time).  The beer actually went in a bit cool, at 18°C.  After an hour, the glass of water and the sensor had cooled to 19.5°C, so the light came on.  However, it also seems that the fermentation started to kick off at roughly the same time.  The combination of the heat from the bulb and the heat generated from fermentation (the yeast is currently in the aerobic stage) caused a spike with peak 22.2°C.

Due to the good insulation of the freezer, the heat generated from the fermentation maintained the temperature at roughly 21°C throughout the night.  Note that the controller was trying to turn the cooling circuit on (the blue line), but I had disconnected the freezer, as I had assumed it wouldn’t be needed due to an ambient temperature of just 12°C.


The hardware itself seems to be working well.  The response of the freezer still needs some testing though.

The result of the first fermentation is reasonably satisfactory – it’s already a huge improvement over just leaving it in a warm room and crossing your fingers.  It’s definitely the healthiest fermentation I’ve had yet and it looks set to finish in just a few days, whereas previously it has taken over a week.  However, the response of the on-off control could definitely be improved.

Once this first fermentation is complete, I will measure the thermal conductivity and cooling power of the freezer.  I will also research calculating heat produced by respiration. The will allow a proper model of the system to be formed such that sensible variables, such as bulb power and on-off period, can be chosen.  I may also experiment with putting the sensor in the beer itself (this is probably wise, but more effort in terms of cleaning and sterilising).  A goal of achieving less than ±0.5C error seems reasonable.


Eagle PCB
PIC Firmware
Data Retrieval Software

PID Temperature Controlled Boiler/HLT and Wireless Remote Dislay

During the beer brewing process (for a brief description, click here) the temperature of water for use in the mash must be within a few degrees Celcius to achieve a consistent flavour between batches.

My boiler/HLT consists of a large plastic container with two kettle elements screwed in.  Before creating the PID temperature controller, temperature of the water was controlled by manually reading the temperature with a thermometer and turning on and off each element at the mains socket.  Clearly, after a few brews, this becomes extremely tedious!  Hence I set about the created of the temperature controller.

The Specification

  • AVR microcontroller programmed in C++ using the Arduino libraries.
  • Digital DS1820 temperature sensor.
  • PID control scheme.
  • Solid State Relays for mains switching.
  • LCD display.
  • Wireless remote.

PID Control

PID control offers many advantages over a simple thermostat design (on-off control), i.e. ‘if the temperature is below 65°, turn the heaters on, else turn the heaters off’. Possibly the greatest problem with on-off control is overshoot – due to the time delay between switching the heaters on and measuring a change in temperature, an output such as is shown below would be expected.

PID control, on the other hand, allows the following output to be obtained in the ideal case:

Clearly this is more desirable.  Implementing PID control was also quite simple, due to the excellent PIDLibrary for Arduino by Brett Beauregard.  In fact, the availability of this Arduino library was the main reason the Arduino platform was chosen.

Solid State Relays (SSRs)

Some may well have already thought: “wait a minute… PID requires analogue output, but you’re using relays to switch the heaters?!”

Pulse Width Modulation is used to achieve a pseudo-analogue output.  A PWM period of 1.5 seconds is used. Switching a traditional relay this quickly would not only make a racket, but also wear the poor thing out; hence the choice of SSRs, which allow rapid switching.

During testing, it was found that switching both 1.5kW kettle elements on at exactly the same time caused the lights in the house to flicker(!).  This problem was alleviated by staggering the switching to ensure the elements never both come on at the same time.

The Wireless Remote

A wireless remote was created, which displays the temperature of the water remotely.  As I brew in a detached garage, the remote allows me to conveniently monitor the temperature from the house.

The remote.

The remote.

The remote uses an LCD screen salvaged from an old Nokia phone.  A PIC16F88 is used to receive serial data from the wireless module and print it to the screen.  Once I find the time, I’ll etch a PCB and stick it in a box…

A cause of great hassle were the cheap wireless modules purchased from Sure Electronics.  The main problem was the practically indecipherable datasheet which was apparently translated from Chinese to English using Google Translate.  If anyone reading this is struggling with these modules, take heed of this note hidden at the end of the data sheet:
‘Since the performance of voltage ascending slope that the radio frequency chip of this
module requires is too high when power supply is connected, something unwanted like PLL locking tolerance which causes communication failure may happen when some LDO chips of low adjustment rate are used or some bigger filter capacitors are exist in circuit.’

It then suggests a circuit to alleviate the problem. Don’t be lazy – use the circuit!

The Final Result

The rest of the design is all pretty straight forward.  Take a look at the gallery below to see the final result.