LED christmas tree

From Hackerspace ACKspace
Revision as of 02:01, 21 December 2013 by Xopr (talk | contribs) (oops, broken wiki link. Think it's bed time now)
Jump to: navigation, search
Project: LED christmas tree
Featured:
State Active
Members Vicarious, Xopr
GitHub No GitHub project defined. Add your project here.
Description Blinken lights!
Picture
LED christmas tree Picture.jpg

synopsis

Create a christmas tree out of cartboard, leds, some RJ45 wire, tiny experiment print, headers, solder, Scotch-tape, a brown plastic instant-coffee container and an arduino.

I hereby declare freedom of firmware for the tree; change to whatever you want it; this was just a kick-start.

implementation

Since the tree was already made two years ago, but the code (and/or Arduino) got lost, Xopr took his Andon light arduino, and did an ugly rush job on making the leds identifiable.

After identifying which port pin was which LED, I wrote some shifting logic to be able to call setLed( x, y ) and clearLed( x, y ).

Actually, I think writing about it on the wiki costs more time than actually pimping the tree, so here it is.

pics

Pics (or vid) or it didn't happen! I had to leave in a hurry, but hey, it's a wiki; anyone can put a goatse tree up here.

code

The current code running is the one pasted here (with some preparations on doing PWM) Arduino code (portable to plain avr-gcc):

void setup()
{
  // Set tree pins as output
  DDRB = B11110000;
  DDRH = B01111000;
  DDRE = B00111010;
  DDRG = B00100000;

  // All lights on
  PORTB = B11110000;
  PORTE = B00111010;
  PORTG = B00100000;
  PORTH = B01111000;
  delay( 2000 );

  // All lights off
  PORTB = 0;
  PORTE = 0;
  PORTG = 0;
  PORTH = 0;
  delay( 1000 );
}

/*
  // Mapping of the pins on the tree are as followed (reverse-lookup pins from Arduino mega 1280):
  // {Port-and-pin-number}: {light-on-the-tree} {port-as-index-number,pin-number}: {resulting-mapping-index}
  PORTB7: top  0,7: 7
  PORTB6: 3a   0,6: 6
  PORTB5: 3c   0,5: 5
  PORTB4: 3b   0,4: 4

  PORTH6: 3d   3,6: 30
  PORTH5: 2b   3,5: 29
  PORTH4: 2c   3,4: 28
  PORTH3: 2d   3,3: 27

  PORTE5: 1d   1,5: 13
  PORTE4: 1a   1,4: 12
  PORTE3: 2a   1,3: 11
  PORTE2: 1b   1,1: 9

  PORTG5: 1c   2,5: 19
*/

// Mapping
byte g_mappedTree[4][4] = {
  { 12,  9, 21, 13 }, // Row 1, Da Syntax helped me calculating the number 21 ;)
  { 11, 29, 28, 27 }, // Row 2
  {  6,  4,  5, 30 }, // Row 3
  {  7,  7,  7,  7 }, // Top; yes it is only one led, so one pin
};

void loop()
{
  for ( byte n = 0; n < 10; n++ )
    horizontalBlink();
  for ( byte n = 0; n < 10; n++ )
    verticalBlink();
  for ( byte n = 0; n < 100; n++ )
    randomBlink();
}

void horizontalBlink()
{
  // Add vertical strips of light: switch on clock wise
  // When all lights are on, switch them off clock wise

  // Horizontal
  for ( byte x = 0; x < 4; x++ )
  {
    // Vertical
    for ( byte y = 0; y < 4; y++ )
    {
      setLed( x, y );
    }
    delay( 100 );
  }
  // Horizontal
  for ( byte x = 0; x < 4; x++ )
  {
    // Vertical
    for ( byte y = 0; y < 4; y++ )
    {
      clearLed( x, y );
    }
    delay( 100 );
  }
 
}

void verticalBlink()
{
  // In four steps, light a ring from bottom to top
  // When all lights are on, switch them off bottom to top

  // Vertical
  for ( byte y = 0; y < 4; y++ )
  {
   // Horizontal
    for ( byte x = 0; x < 4; x++ )
    {
      setLed( x, y );
    }
    delay( 100 );
  }
  // Vertical
  for ( byte y = 0; y < 4; y++ )
  {
   // Horizontal
    for ( byte x = 0; x < 4; x++ )
    {
      //setLed( x, y );
      clearLed( x, y );
    }
    delay( 100 );
  }
 
}

void randomBlink()
{
  // Pick a random row and column, a random state,
  // and apply that state to the indexed led
  // This is somewhat similar as the original tree had

  byte x = random( 4 );
  byte y = random( 4 );
  if ( random( 2 ) )
    setLed( x, y );
  else
    clearLed( x, y );
  delay( 100 );
}


void setLed( byte _x, byte _y )
{
  // This function does the led magic: it deduces the bit and port index from the mapping number
  // like this: xxxppbbb, there the lowest 3 bits are values 0-7, indicating the bit we're after
  // and the two bits after that determine the port

  // Yes, I could use the arduino port index, but this is faster

  // Fetch the mapping index for the given coordinate
  byte mappedPort = g_mappedTree[ _y ][ _x ];
  // Determine the bit index (lower three bits)
  byte shiftBit = mappedPort & 7;

  // Find which port it is (shift out the lower three bits and get the index)
  // And set the given bit
  switch ( mappedPort >> 3 )
  {
    case 0:
      PORTB |= (1 << shiftBit);
      break;
      
    case 1:
      PORTE |= (1 << shiftBit);
      break;
      
    case 2:
      PORTG |= (1 << shiftBit);
      break;

    case 3:
      PORTH |= (1 << shiftBit);
      break;
  }
}

void clearLed( byte _x, byte _y )
{
  // Same as setLed, except for the port bit banging
  // Yes, these functions can be combined, but the whole program was a quick hack

  // Fetch the mapping index for the given coordinate
  byte mappedPort = g_mappedTree[ _y ][ _x ];
  // Determine the bit index (lower three bits)
  byte shiftBit = mappedPort & 7;

  // Find which port it is (shift out the lower three bits and get the index)
  // And clear the given bit
  switch ( mappedPort >> 3 )
  {
    case 0:
      PORTB &= ~(1 << shiftBit);
      break;
      
    case 1:
      PORTE &= ~(1 << shiftBit);
      break;
      
    case 2:
      PORTG &= ~(1 << shiftBit);
      break;

    case 3:
      PORTH &= ~(1 << shiftBit);
      break;

  }
}