How to make Halloween creepy blinking eyes with an ATmel AVR microcontroller

Printer-friendly version

An ATtiny2313 chip, some C code, a bunch of LEDs and other components - that's your DIY Halloween decoration this year. I'll show you how to do it, and there's a video at the end of this page showing the digital creepiness in action.

The project is based on the ATmel 8-bit RISC AVR ATtiny2313 processor. I just needed an excuse to learn how to program it, and a little toy for Halloween seemed perfect for that purpose.

The kids built, out of cardboard boxes, two characters from the Minecraft video game: a spider and a creeper, with eyes made of red LEDs. There were some unintended side-effects, such as when the kids painted the spider using the ultra-flat black Krylon spray which I was saving for optical instruments, instead of using the regular flat black Rust-Oleum. But that's okay, at least the spider looks really really black. :) And I'll have to buy another can of Krylon.

The purpose of the AVR chip was to make the eyes blink - with a twist: the eyes are supposed to blink randomly, as if these were live creatures.

I whipped up a quick driver circuit based on the AVR chip and a few components. You can see the schematics below; nothing fancy, just a simple output stage for each LED pair. The output actually has 5 channels, so it could drive 5 pairs of "eyes" blinking independently, but I only represented 1 channel here, connected to pin 12; the other 4 are identical and are connected to pins 13 ... 16.

And here comes the interesting part, and the whole purpose of this exercise - the C code. Programming an AVR chip is just what you would expect from low-level programming a small RISC processor: it's terse and ugly, but efficient. Programming an Arduino (which is based on an AVR chip) feels much more comfortable by comparison, but doesn't offer access to all the low-level features of the chip. Here, with a "naked" AVR, we can do anything - the hard way. Here's the code I came up with:

#define F_CPU 1000000UL        /* Clock Frequency = 1Mhz */

#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>

#define LED_BIT 0

int main(void)

    int led[5] = { 1, 1, 1, 1, 1 };
    int decay[5];
    int quant = 10;        // loop pause in ms
    int max_open = 700;        // how many loops
    int min_open = 100;
    int close = 15;
    int i;

    DDRB = 0b00011111;        // these pins are OUTPUT
    PORTB = 0b00011111;    // they all start ON

    for (i = 0; i <= 4; i++) {
    // each pin stays ON a random time
    decay[i] =
        min_open +
        (int) ((double) rand() / ((double) RAND_MAX + 1) * max_open);

    for (;;) {
    for (i = 0; i <= 4; i++) {
        if (decay[i] < 0) {
        decay[i] = 0;

        if (decay[i] == 0) {
        switch (led[i]) {
        case 1:
            led[i] = 0;
            decay[i] = close;    // the OFF duration is fixed
        case 0:
            led[i] = 1;
            decay[i] =
            min_open +
            (int) ((double) rand() /
                   ((double) RAND_MAX + 1) * max_open);

    PORTB =
        16 * led[4] + 8 * led[3] + 4 * led[2] + 2 * led[1] + led[0];

As you can see, we setup Port B for output: first we declare 5 of its bits (pins 12 ... 16) as output, and we initialize them with HIGH level. After that the algorithm is like this:

For each pin, choose a random long duration during which the pin stays HIGH. When that duration has passed, flip the pin to LOW, and keep it LOW a fixed and short duration (the blink). After that, flip it HIGH again. Repeat. At the end of each cycle, dump the 5 bits on Port B, so that the status of the LEDs is actualized.

This is the driver circuit, with batteries, in a plastic box (all 5 channels were built, but we only used 3 of them):

This is the whole thing (you'll notice the spider has two sets of eyes):

And here's the result - watch the "creepy" Halloween eyes blink randomly:

Happy Halloween!