Recently, Kevin over at Beer and Coding in Eugene got me into homebrewing beer. I have been looking for an excuse to build something out of an Arduino for some time now so I decided to build something that could monitor my fermenting brew while I am out of the house. There are lots of things that can adversely affect beer while it ferments, so I thought it would be interesting to have a log of exactly what conditions my beer was exposed to.
I started with a simple design: An Arduino Duemilanove hooked up to a DS18B20 One Wire digital temperature sensor and a GP1A57HRJ00F Photo Interrupter. The temperature sensor would monitor what temperature my beer was fermenting at, and the photo interrupter would be connected to the air lock on my fermentor in such a way that it would trigger whenever the airlock bubbled. I planned on writing software for the Arduino that would interface with the sensors and send the resulting data to my netbook using the Arduino's USB port. Another piece of software I wrote would be running on the netbook to parse the incoming information from the Arduino and log it to disk so that I could review it later. This seemed like a good, functional design. Then I spent some time browsing the cool stuff available over at Spark Fun...
I decided to design around the Proto Shield that Spark Fun offers. An Arduino shield is a circuit board that is designed to plug into the top of the Arduino. This particular shield passes all of the Arduino's pins up to the top and gives you plenty of protoboard to prototype with. I chose to get a Mini Breadboard with an adhesive back so that I could stick it to the prototyping area. A breadboard significantly speeds up prototyping by allowing you to plug jumpers and components into sockets instead of connecting them all up with solder. The proto shield allows me to design the entire circuit as a module that plugs into the top of the Arduino, leaving the Arduino itself unmodified should I decide to use it in another project.
I decided that it would be nice to have a Serial Enabled LCD hooked up so that I can show real-time data on the device itself so I incorporated one into my design. If I'm going to have a display, I should probably have a way to receive input from the user, so I decided to add a Quadratic Rotary Encoder as well.
I eventually ordered up all the parts that I would need. When I got them I decided to start by getting the display working. I needed the Arduino's internal UART to communicate with my netbook so I initially decided to drive the display using the New Software Serial Library by Mikal Hart. After a bit of trial and error I was able to get it up and running, but sending control codes to the display for positioning the cursor and clearing it seemed like a good candidate for abstraction. I decided to build a new display library by inheriting the New Software Serial Library. With a little OO magic I had a display object that was very easy to use.
The rotary encoder that I picked up ended up being a little more complicated than I had assumed it would be. I decided that it would also benefit from its own library and ended up with a nice self-contained object that you don't need to understand Gray Code to use. This particular encoder doubles as a momentary switch, so I wrote support for it into the library as well.
The Atmega328 chip that is the heart of the Arduino only has two interrupts. I need one of those interrupts for the photo interrupter, so I don't have enough to bind my input mechanisms to interrupts. This means I have to rely on polling. If polling is going to work, I cannot have any waits or excessively long loops in my code or I will miss input signals. Because I need things to happen on schedules for this application, I decided to write a simple timer library. This library allows you to set up timers with specific intervals. Then you just call their check functions every loop. If you are returned false, the timer is still ticking away. If you get true, it means the interval has elapsed and you should take whatever action you were waiting to do. If you configured your timer to be recurring it will automatically reset itself when you read a true so that you can just keep on calling check.
Because the photo interrupter is so simple, I declined to write a library for it. Its signal pin is high when the gate is clear, and low when the gate is obstructed. I bound the signal pin to trigger an interrupt when the signal goes from high to low. When the interrupt is triggered I set a flag so that on the next loop a byte will be sent over the USB cable and some internal variables will be updated to reflect the airlock activity.
There is already an excellent library available for the One Wire temperature sensor written by Miles Burton. I did have to modify it slightly for my application, though. When you ask one of these sensors to measure the temperature, you have to give it enough time to make the measurement and do the necessary conversions to end up with a number that you can understand. The amount of time this takes varies depending on how many bits of resolution you are asking for. Miles' library suspends the Arduino using the wait command to make sure you don't request the temperature before the sensor is ready. While this is understandable, it is a problem if your design relies on there being no artificial waiting. I added a function to the library that you can call to disable the waits. I use my timer library to make sure I don't ask for the temperature before the sensor is ready without locking the whole board up.
When I originally designed this, one of its features was going to be temperature control. I planned on building an insulated box to house my fermentor and my sensors. I was going to have a heating element of some sort in the box so that when temperatures got below a certain threshold a relay would be tripped to turn on the heat. After my first beer had finished fermenting it was pretty clear that keeping things warm is not an issue at the moment, so I elected to go without a relay for now. I decided to go ahead and write the software to support temperature control anyway. I just hooked the relay pin to an LED instead of a relay. Toggling a relay too quickly is dangerous, so I put controls in place to limit how often the relay switches states. I also decided to factor in the chance that I could get a false read, so temperatures have to stay below the threshold for multiple reads before we turn anything on or off.
I took all of these components and came up with a functioning program. Initially everything was plugged directly into the proto board. The trouble with this was that I had to leave my netbook locked up in the closet with my fermentor. I eventually started to regret not having my netbook around, so I decided to come up with a way to read the sensors from a distance. I didn't want to invest in some of the expensive wireless chips that are available for this sort of thing, so I decided to build the sensors their own board.
I picked up a protoboard and a pair of RJ-45 Keystone Jacks from Radio Shack to use as a base. I had some male and female pin headers left over from my Spark Fun order, so I cut off one 8 pin section from the male headers and two 8 pin sections from the female. I sacrificed an old Cat5 cable for the good of the project and cut off a pair of short lengths. Each length of cable got punched down to a keystone jack on one end. One of the cables had an 8 pin length of female pin header soldered to the other end. The other had an 8 pin length of male pin header soldered to it. I soldered the other length of female pin headers onto the board. I cut some jumpers to length for the board and soldered in connections for the first two pins to the vcc and ground traces on the board. I then cut and soldered jumpers for the next two pins connecting them each to their own trace on the grid. I cut up the last of my remaining male pin headers into two three pin sections. I soldered these onto the board so that that they each had a vcc pin, a ground pin, and the third pin connected to one of the other wires that were jumped to there own traces.
Earlier I had soldered the photo interrupter onto a breakout board with a three pin male header. I cut a length off of my donor Cat5 cable to serve as a probe. I cut two three pin sections of female pin header and soldered one to each end of the probe cable. Now I could plug the cable into one of the three pin headers on the board, and plug the other end into the three pin header on the photo interrupter. I did the same thing for the temperature sensor, although I only used the signal pin and the ground pin as I am running the sensor in parasite mode. It gets the voltage it needs to operate from the signal pin. The temperature sensor is in a through hole, three lead package so I plugged it straight into the female pin header on the end of its probe.
When I was going through my old component box looking for parts for this project I found an old photo resistor. Light can damage beer, and I still had 4 open signal pins on my sensor board, so I decided to hook up it up. I ran out of pin headers (I suggest you stock up if you are doing something like this, you will be surprised how often you use them) so I ended up just soldering the photo resistor directly to the board. I soldered it high without trimming the leads so that I will be able to replace it with a header/probe when I get some more.
What I have at this point is a board full of sensors that is wired to a Cat5 jack, and a Cat5 jack that is wired to a length of female pin header. I use jumpers to connect 5v, ground, the signal pin for the temperature sensor, the signal pin for the photo interrupter and the analog pin for the photo resistor to the female pin header. Then I plug an off the shelf Cat5 cable into each of the jacks. Now I can have the arduino and the computer in one location, and have the beer and all the sensors in another location. I am using a 25 foot Cat5 cable right now and it works great. I suspect that I could use a much longer cable without any issues.
Having the hardware all working like I want it to, it is time to work on the interface. This has gone through several iterations. Currently, it is driven by a simple finite state machine. Clicking the button on the encoder moves you to the next state. There is a state for configuring the minimum temperature threshold. You simply turn the encoder to adjust the value to the desired temperature. There is also a state for the maximum temperature that works the same way. Another state allows you to adjust the backlight of the display. Outside of these three configuration states is the main state. The main state has two independently configurable lines. You can set the top line and/or the bottom line to any one of these options:
Temperature in degrees Fahrenheit
Temperature in degrees Celsius
The amount of time that passed between the last two airlock bubbles
How long it has been since the last airlock bubble
The rate of airlock activity
The level of ambient light that the sensor board is exposed to
To set which line displays what in the main state, you hold the button down for at least one second. Then the top line will start to blink. You can rotate the encoder to cycle through all of the available states. When you settle on the one you want, you push the button and the second line will start blinking. You use the same process to select what you would like it to display, then push the button to lock in your decision.
Wow, this ended up being a wall of text. Expect an update soon with pictures and a description of how the software running on the netbook works. I also plan on making all of the source code I wrote for this project publically available sometime soon.
Questions or comments are always welcome.
-Jesse