January 14, 2010

Clock Update

I've posted an updated version of the "overkill clock" code.

This update takes care of a major bug in the alarm-sensing code that made any day's alarm go off every day. There's also a couple of minor code-cleanups and the addition of a time-out on the DealWithButton() function. (Without the time-out, accidentally bumping the button in the night prevented the alarm from going off in the morning. Now you have to accidentally bump it twice for the same effect.) One could add the same sort of time-out mechanism to the rest of the user interface code in SetAlarm() and SetClock(), but I chose not to.

January 1, 2010

Alarm Clock Overkill


I don't get up at the same time every day, so I thought it'd be nice to have an alarm clock that would drag me out of bed at different times on different days. That was the initial idea: things got out of hand, of course, and this is the result.

What it does:
1) It displays the time, day, and date. It also keeps track of the year, leap years, and adjusts automatically for daylight savings time.
2) It displays the temperature.
3) It has seven independent alarms, each of which can be set for different days of the week. For example, one alarm can go off at 5am on Tuesday, Wednesday, and Friday while another can go at 6am Monday and Thursday and a third can allow me to sleep until 7 on weekends.
4) In the event of power failure, the clock keeps time anyway. The alarms and display don't work when the power's off of course, but when power comes back on the time will be correct and it remembers the alarm settings.
5) It announces special events. Today is New Year's Day, so the bottom line of the display alternates between day/date (shown above) and the message shown below.

There are over 150 of these special events programmed into the clock, including family birthdays, oddball holidays (Squirrel Appreciation Day, anyone?) and so on. On my kids' birthdays it even tells me the age of the kid. (A useful bit of information that sometimes escapes the geek mind, as you probably have noticed —or forgotten— already.)

How it does it:

The brains of the unit are supplied by an ATMega328 Boarduino  (Arduino clone). This keeps the display up to date, turns alarms on and off, and runs the user interface. It also stores and displays the various special events for the year.

Accurate timekeeping is provided by a DS1307 real-time-clock chip. This chip also has 56 bytes of spare EEPROM which I use to store the alarm information in the event of power loss. Communication with the microcontroller is via I2C bus.

The alarm beeper itself is a simple piezo buzzer from Radio Shack, driven off the 9V supply line with a 3904 NPN transistor. The Boarduino can make the buzzer sound without the help of the transistor, but the goal is to not just sound the buzzer but get me out of bed!

Temperature sensing is via an LM35 temperature-sensitive zener diode. This is a great little component! Put in 5V, and the signal line puts out 10mV/°C. It's that easy. I use these, or the similar LM335, in my physics lab quite often.

User input is via a pushbutton/quadrature knob. The user presses the knob to select an action or set a number, and turns the knob to dial in the option of his choosing. Much better than the usual 4-button combination on the top of most alarm clocks.

Here's a cut-down version of the code. I trimmed the getMessage() function in this sample code to just show an example of how the "special events" code works — you'll have to put in the special events of your own choosing. (Or you can email me and I'll send the uncut version.)

Notes about the hardware:
1) The 2x16 character LCD uses the standard Hitachi HD44780 driver and the LiquidCrystal.h library. With some modification you could make it work with other LCDs, although this code is optimized for 16-character lines.
2) I put 0.1µF caps to ground on each of the three switch lines on the rotary switch, in addition to the usual 10k pull-up resistors. This combination nicely debounces the quadrature signal.
3) The DS1307 clock chip requires 3V on the "battery backup" line. It will not work without this.
4) I soldered the crystal directly to the DS1307 chip to minimize any clock error due to crappy breadboard connections.
5) As written, the code requires an ATMega328 or larger microcontroller. The "stock" ATMega168 does not have enough memory to run this program unless you get rid of the alarms or most of the daily specials.

Next:
It needs an appropriate case of some kind. I'm planning to etch a small batch of boards for these, driven with bare ATMega328's instead of the Boarduino I used for this prototype, and I'm thinking some sort of retro-steampunk case. I'll post pictures when it's done.

Want to build one yourself?
Download the code here. The hardware is very straightforward, here's an electrical diagram. I don't recommend this as a first Arduino project, though!



December 19, 2009

Using a quadrature encoder (rotary switch) with Arduino

I've found several sites and posts explaining how to use a quadrature encoder with an Arduino, but wasn't completely satisfied with any of the methods used. Perhaps part of the problem is with the encoder I'm using: it's part #COM-09117 at Sparkfun.com.

This encoder has twelve detents per rotation, and each detent covers one complete cycle of Gray code. This means that the most common method of reading the knob counts four steps per detent, which isn't what I wanted.

So, backing up a bit... Here's how one of these things works. Instead of separate pins for each position as the knob turns, there are two pins (A and B) that produce offset pulses. The direction of the offset indicates the direction of the rotation.
As you can see from the diagram, as you rotate the knob clockwise, the pulses from A lead the pulses from B. Rotating counterclockwise, the pulses from B come first.

The detent spacing is marked on the diagram as "one notch", and if you just keep track of changes on  A and B there are four steps between detent positions. There is an event that happens only once per detent, though: that is a falling (or rising) edge on either A or B. So what I did is run an interrupt on the falling edge of A. Clockwise, B is high when A has its falling edge (at point 1) and counterclockwise B is low when A has its falling edge (at point 2). The interrupt routine just reads B, and adjusts the recorded position of the knob accordingly.

I connected one quadrature pin to Arduino pin 2 and the other to Arduino pin 3. Pin 2 is interrupt 0 for the Arduino. Here's my code:

/* knobtest.pde
Test of optical encoder (Gray scale)
Eric Ayars
*/

byte Blinker = 13;
int Delay = 250;
byte A = 2;        // One quadrature pin
byte B = 3;        // the other quadrature pin
volatile int Rotor = 0;

void setup() {

    // set DIO pins
    pinMode(Blinker, OUTPUT);
    pinMode(A, INPUT);
    pinMode(B, INPUT);

    // Turn on pullup resistors
    digitalWrite(A, HIGH);
    digitalWrite(B, HIGH);

    // Attach interrupt to pin A
    attachInterrupt(0, UpdateRotation, FALLING);

    // Use serial port to keep user informed of rotation
    Serial.begin(9600);
}

void loop() {
    // Basic blink program here: interrupt comes in as needed.
    digitalWrite(Blinker, HIGH);
    delay(Delay);
    digitalWrite(Blinker, LOW);
    delay(Delay);
}

void UpdateRotation() {
    // This is the subroutine that runs every time pin 2
    // switches from high to low.

    if (digitalRead(B)) {
        Rotor++;
    } else {
        Rotor--;
    }
    Serial.println(Rotor, DEC);
}


The program blinks the LED on pin 13 at a frequency of roughly 2 Hz, but any time the knob is turned it sends the new position out the serial line and then goes back to blinking.

I wouldn't recommend this method if the exact position of the knob is critical. It works great as a user input device, though.

November 16, 2009

"Arduino for Artists" Workshop

The micro-course for art/sculpture students was fun, interesting, and generally worth the time and effort. Of course, I taught it so there may be some bias there. :-)

Here's code for the various examples we covered in the course.

And a big thank-you to Ellen Akimoto for instigating the event!

November 2, 2009

Wireless acceleration sensor!




Here's a webpage I put together a few months ago describing how to use XBee wireless transceivers as 3-axis wireless accelerometers. I'm not sure that wireless is the best way to go with this, but it worked to some degree and it made a fun summer project. One of my students is currently working on some interesting lab applications for the device, so stay tuned...

Cylon Pumpkin



This has been done before. There are several good ways to do it: most use either a 555 timer chip and decimal counter chip, or an Arduino. Stefan and I used an Arduino (Boarduino, technically) which limited our scanner to 14 LEDs. No problem --- 14 gives a nice scanning effect!

Here's how we wired it: the numbers on the Boarduino block refer to the digital lines d0--d13.

It's only necessary to have one current-limiting resistor in the circuit, rather than one on each LED, since only one LED is on at a time and the LEDs prevent current from flowing back into the Boarduino on the "off" pins.

Now for the code. It's relatively simple: just count up and down, turning on and off the count LED as you go.

// Cylon pumpkin driver
// Eric Ayars
// 10/24/09

#define MAXLIGHT 14

byte Wait = 50;        // Time each light is on, in ms
byte EndWait = 250;    // Time all lights are off at the ends

void setup() {
    // Set all pins to output
    for (byte j=0;j
        pinMode(j,OUTPUT);
    }
}

void loop() {

    // Count up from 0 to 13, setting the light
    // for each count.
    for (byte j=0;j
        digitalWrite(j,HIGH);
        delay(Wait);
        digitalWrite(j,LOW);
    }

    // Pause at the end
    delay(EndWait);

    // Count back down from 13 to 0, setting lights
    // as it goes again.
    for (int j=MAXLIGHT-1;j>=0;j--) {
        digitalWrite(j,HIGH);
        delay(Wait);
        digitalWrite(j,LOW);
    }

    // Pause at the end
    delay(EndWait);

}

Here's Stefan with the completed "eye-bar". We didn't have a section of proto-board long enough to hold the entire scanner, so we split a long piece and spliced it together in the middle with short wires. This gave us the option of bending the unit in the center, which proved handy when mounting it in the pumpkin!

If you look closely, you can see that we used two 1k-ohm resistors in parallel instead of a 500-ohm resistor for the current-limiting resistance. Whatever comes in handy...

Rather than solder the eye-bar directly to the Boarduino pins, we soldered the wires to 8-pin female headers that then connected to the Boarduino. We labeled the headers to avoid confusion. :-) One side of the Boarduino has pins 0-7, and the other side has pins 8-13 and a connection to ground.




Finally, we ran the wires/header-pins through a slit in a freezer bag, then sealed the slit with hot-melt glue. (Silicon RTV would have been a better choice than hot-melt glue, but we were out.) We could then keep the battery and Boarduino away from wet (and conductive) pumpkin guts.



We modeled the pumpkin after this guy, since Stefan declared it to be "the best-looking Cylon ever". Give him time: when he gets older he'll gain a proper appreciation for Number Six!