Difficulty Level = 5 [What’s this?]
Like many parents, we make hand-made costumes for our kids instead of buying cheaply-made (and expensive) costumes based on licensed characters. This year, my youngest son wanted to be a robot. My wife did a great job making the costume, but I just had to add some cool electronics to take it to the next level.
The electronics are nothing fancy — a simple Atmel ATtiny13 microcontroller that interfaces with two 74HC595 shift registers to light up LEDs randomly. The technical details are below, but in the process of building this, I was really struck by how electronics and computing are being embedded into everything. This week I was making a TODO list and one of the items was “finish source code for robot costume”.
OMG, now the costumes we make have source code.
This is a great example of how technology is becoming increasingly ubiquitous. Ten years ago, this would have been far beyond my reach. But in 2010 I can build this easily. The microcontroller cost $1.04, the shift register chips are $0.25 each, the resistors are a penny each, and the LEDs probably average $0.20 each. Definitely less than $5 for everything.
Technical Details
Here’s the schematic:
And finally, the simple source code that runs on the chip. I use CrossPack for AVR development. I use avrdude and a Bus Pirate to upload the code onto the ATtiny13 chip.
/*
 * ATtiny13 driving two 74HC595 shift registers
 *
 * Randomly turns on/off output pins of the shift
 * register ICs.
 * A random number of outputs are set high, then
 * a random time delay occurs.  Then the cycle
 *  repeats.
 *
 */
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#define DATA PB0
#define CLOCK PB1
#define LATCH PB2
int main(void) {
  int d;
  char n;
  char i;
  // set DATA, LATCH and CLOCK pins to OUTPUT
  DDRB |= (1 << DATA);
  DDRB |= (1 << LATCH);
  DDRB |= (1 << CLOCK);
  PORTB = 0;
  for(;;) {
    // choose number of LEDs to light up.
    // n will be between 4 and 16
    n = 4 + (random() % 13);
    for(i=0;i<16;i++) {
      // for each LED, probability of it being lit
      // is n/16
      if ((random() % 16) <= n) {
	PORTB |= (1 << DATA);  // set DATA pin high
      } else {
	PORTB &= ~(1 << DATA); // set DATA pin low
      }
      // toggle shift register clock pin
      PORTB |= (1 << CLOCK);
      _delay_ms(2);
      PORTB &= ~(1 << CLOCK);
    }
    // once we've shifted out all 16 values, toggle
    // the latch pin.
    PORTB |= (1 << LATCH);
    _delay_ms(2);
    PORTB &= ~(1 << LATCH);
    // delay random amount of time between
    // 100ms and 500ms
    d = 100 + (random() % 400);
    for(i=0;i<d;i++) {
      // _delay_ms function must be called with a
      // constant value, not a variable!
      _delay_ms(1);
    }
  }
  return 0; // not reached
}
					


This looks very interesting!