August 25, 2011

How long until Christmas?

I have kids. They have questions. One of their big questions, all year long it seems, is "How long until Christmas?" Here's one way to answer that question.


The circuit consists of three main elements: Arduino Pro Mini, DS3231 real-time clock (RTC) breakout board, and a standard 2x16 LCD. 

The Arduino Pro Mini takes power (raw) from the 9V battery through the toggle switch. The Vcc output  of the Arduino's regulator (5V) is used to drive the LCD and the clock. Here's the program on that Arduino. The program reads the time from the RTC, calculates the number of seconds between 'now' and a hard-coded 'targetDate', then from that time differential calculates and displays the number of days/hours/minutes/seconds remaining. It does this roughly 4x/second, which makes a nice ticking-second countdown. When the countdown reaches zero, it displays "Merry Christmas!" and goes to sleep.

The Arduino uses I2C to communicate with the RTC. I used a homemade DS3231 breakout board with a battery backup for my RTC, but one could use the more standard Sparkfun DS1307 breakout as well. In either case, my DS3231 library works fine. The code provided above does not set the clock: it assumes the clock has been set previously. I used the setClock.pde sketch from my DS3231 library to set the clock using the serial port, and no hardware changes are required to make that program set the clock on this circuit.

The LCD is a standard 2x16 LCD with the HD44780 driver, as shown here.

Nothing particularly fancy, but I just happened to have all the necessary parts sitting on my workbench anyway so I threw it together one evening. You can of course change the target date and message in the software so it works for any other event you might want. At this point in the semester, I'm leaning towards counting the seconds until the Physics 202B final...

August 3, 2011

Simple Arduino data-collection

At this year's "Arduinos in the Physics Lab" workshop at the AAPT meeting, one of the participants asked for a simple way of using the Arduino as a tethered A/D converter for data collection direct to a computer. This is my quick & dirty demonstration solution.

Here's the code for the Arduino. It waits for a single byte 'N' to arrive on the serial port, then once that byte arrives it sends out N data pairs formatted as tab-separated millis() and analogRead() values. The readings are separated by roughly 10 milliseconds. This version of the code only reports the values of analog pin 0 (A0), but it can be easily modified to return other (or more) ports.

For the computer end, I used Python: here's the code. This was done on a Macintosh, with Pylab installed so I can use matplotlib to handle the plotting nicely. On Linux or Windows the port will be described differently, and if the program fails for you on the line 'import pylab as pl' then ... well, install pylab on your system. It's a great wrapper package for scipy, numpy, and matplotlib. The program expects two arguments: the number of points to collect and the filename where points should be saved.

Here's a sample output plot, showing relatively meaningless data from a light sensor.
One glitch I found was that there needs to be a short delay between starting the serial communications to the Arduino and sending the request for N data points. I do not know whether this is a problem with the Arduino in general, or with the Arduino Uno I was using as a testbed, or with the pyserial library, or with the Macintosh implementation of pyserial... It was a mess trying to figure out what was going on, though, because when in interactive mode everything would work perfectly but the exact same commands in a Python script would not work. The difference of course is that I would take several seconds to type commands in interactive mode, and it took me a long time to figure out what was causing the problem! The solution I used is in line 37 of the code:
    time.sleep(1.5)
The sleep value (1.5 seconds) was determined by trial and error. ser.flush() should work also, but I did not find this to be the case.