Difference between revisions of "LED christmas tree"

From Hackerspace ACKspace
Jump to: navigation, search
m (minor format/interpunction change)
m (fixed media location using filepath)
 
(11 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
{{Project
 
{{Project
|State=Active
+
|State=Completed
 
|Members=Vicarious, Xopr
 
|Members=Vicarious, Xopr
 
|Description=Blinken lights!
 
|Description=Blinken lights!
 +
|Picture=LED_christmas_tree_Picture.jpg
 
}}
 
}}
=== synopsis ===
+
=== 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.''
+
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.  
  
=== implementation ===
+
''I hereby declare freedom of firmware for the tree; change to whatever you want it; this was just a kick-start.''
Since the tree was already made two years ago, but the code (and/or Arduino) got lost, [[User:Xopr|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 )'''.
+
=== implementation  ===
 +
 
 +
Since the tree was already made two years ago, but the code (and/or Arduino) got lost, [[User:Xopr|Xopr]] took his [[Andon light]] arduino, and did an ugly rush job on making the leds identifiable.  
  
 
Actually, I think writing about it on the wiki costs more time than actually pimping the tree, so here it is.
 
Actually, I think writing about it on the wiki costs more time than actually pimping the tree, so here it is.
  
=== pics ===
+
The current (2014) Arduino Mega placed in the stem belongs to the space. Yes, using a Mega is overkill, but at least it has (almost) enough hardware PWM ports for a neat effect with easy programming.
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 <strike>goatse</strike> tree up here.
+
=== pics ===
 +
 
 +
Pics (or vid) or it didn't happen!  
 +
 
 +
==== 2014 - 2015 version ====
 +
This [[#v3|version]] adds fade-per-color, and festoon fade mode
 +
{{#widget:YouTube|id=IbCswmdqI1M}}
 +
 
 +
==== 2013 version ====
 +
This is the 2013 version which had 3 modes: rotate, upsweep and random. You can also see a part of the [[DE-DP14116|led marquee]]:
 +
{{#widget:Html5media
 +
|url={{filepath:Christmas_tree_and_message_ticker.mov}}
 +
|width=640
 +
|height=360
 +
}}
 +
 
 +
=== code  ===
 +
 
 +
==== v3 ====
 +
Latest version, somewhat cleaned, but 100% arduino code instead of avr-gcc compatible
 +
<pre>// Arduino pins mapped in this order to the tree leds
 +
byte g_arduino[4][4] = {
 +
  {  2,  1,  4,  3 }, // Row 1, blue(2)  ORANGE(1) red(4)  green(3)
 +
  {  5,  8,  7,  6 }, // Row 2, orange(5) red(8)    green(7) blue(6)
 +
  { 12, 10, 11,  9 }, // Row 3, red(12)  green(10) blue(11) orange(9)
 +
  { 13, 13, 13, 13 }, // Top;  orange(13); yes it is only one led, so one pin
 +
};
 +
 
 +
// Arduino pins mapped in this order to the colors
 +
byte g_red[]    = { 4, 8, 12 };
 +
byte g_orange[] = { 1, 5,  9, 13 };
 +
byte g_green[]  = { 3, 7, 10 };
 +
byte g_blue[]  = { 2, 6, 11 };
 +
 
 +
// Brightness lookup table to make the increments linear
 +
static const byte s_fadeValues[]      = { 0, 1, 2 ,3, 4, 6, 8, 12, 16, 23, 32, 45, 64, 90, 128, 180, 255 };
  
=== code ===
 
The current code running is the one pasted here (with some preparations on doing PWM)
 
Arduino code (portable to plain avr-gcc):
 
<pre>
 
 
void setup()
 
void setup()
 +
{
 +
    // TODO: define pins as output
 +
}
 +
 +
void loop()
 +
{
 +
  colorFade( 2 );
 +
 +
  for ( byte n = 0; n < 2; n++ )
 +
    softLayer();
 +
   
 +
  for ( byte n = 0; n < 2; n++ )
 +
    guirlande();
 +
 +
  for ( byte n = 0; n < 7; n++ )
 +
    horizontalBlink();
 +
 +
  for ( byte n = 0; n < 7; n++ )
 +
    verticalBlink();
 +
 +
  for ( byte n = 0; n < 100; n++ )
 +
    randomBlink();
 +
   
 +
  for ( byte l = 0; l < 4; l++ )
 +
    pinArrayValue( g_arduino[ l ], 4, 0 );
 +
 +
}
 +
 +
void colorFade( byte _amount )
 +
{
 +
  // Cycle all colors slowly
 +
  byte n;
 +
  byte half = sizeof( s_fadeValues ) >> 1;
 +
 +
  // Halfway fade in blue
 +
  for ( n = 0; n < half; n++ )
 +
  {
 +
    pinArrayValue( g_blue, sizeof( g_blue ), s_fadeValues[ n ] );
 +
    delay( 100 );
 +
  }
 +
 
 +
  for ( byte l = 0; l < _amount; l++ )
 +
  {
 +
    // Fade out blue while fade in orange
 +
    for ( n = 0; n < half; n++ )
 +
    {
 +
      pinArrayValue( g_blue, sizeof( g_blue ), s_fadeValues[ half - n - 1] );
 +
      pinArrayValue( g_orange, sizeof( g_orange ), s_fadeValues[ n ] );
 +
      delay( 100 );
 +
    }
 +
 +
    // fade in orange
 +
    for ( n = 0; n < half; n++ )
 +
    {
 +
      pinArrayValue( g_orange, sizeof( g_orange ), s_fadeValues[ half + n + 1 ] );
 +
      delay( 100 );
 +
    }
 +
    delay( 3000 );
 +
    // fade out orange
 +
    for ( n = 0; n < half; n++ )
 +
    {
 +
      pinArrayValue( g_orange, sizeof( g_orange ), s_fadeValues[ ( half << 1 ) - n ] );
 +
      delay( 100 );
 +
    }
 +
 +
    // Fade out orange while fade in green
 +
    for ( n = 0; n < half; n++ )
 +
    {
 +
      pinArrayValue( g_orange, sizeof( g_orange ), s_fadeValues[ half - n - 1 ] );
 +
      pinArrayValue( g_green, sizeof( g_green ), s_fadeValues[ n ] );
 +
      delay( 100 );
 +
    }
 +
 +
    // fade in green
 +
    for ( n = 0; n < half; n++ )
 +
    {
 +
      pinArrayValue( g_green, sizeof( g_green ), s_fadeValues[ half + n + 1] );
 +
      delay( 100 );
 +
    }
 +
    delay( 3000 );
 +
    // fade out green
 +
    for ( n = 0; n < half; n++ )
 +
    {
 +
      pinArrayValue( g_green, sizeof( g_green ), s_fadeValues[ ( half << 1 ) - n ] );
 +
      delay( 100 );
 +
    }
 +
 +
    // Fade out green while fade in red
 +
    for ( n = 0; n < half; n++ )
 +
    {
 +
      pinArrayValue( g_green, sizeof( g_green ), s_fadeValues[ half - n - 1 ] );
 +
      pinArrayValue( g_red, sizeof( g_red ), s_fadeValues[ n ] );
 +
      delay( 100 );
 +
    }
 +
   
 +
    // fade in red
 +
    for ( n = 0; n < half; n++ )
 +
    {
 +
      pinArrayValue( g_red, sizeof( g_red ), s_fadeValues[ half + n + 1 ] );
 +
      delay( 100 );
 +
    }
 +
    delay( 3000 );
 +
    // fade out red
 +
    for ( n = 0; n < half; n++ )
 +
    {
 +
      pinArrayValue( g_red, sizeof( g_red ), s_fadeValues[ ( half << 1 ) - n ] );
 +
      delay( 100 );
 +
    }
 +
 +
    // Fade out red while fade in blue
 +
    for ( n = 0; n < half; n++ )
 +
    {
 +
      pinArrayValue( g_red, sizeof( g_red ), s_fadeValues[ half - n - 1 ] );
 +
      pinArrayValue( g_blue, sizeof( g_blue ), s_fadeValues[ n ] );
 +
      delay( 100 );
 +
    }
 +
   
 +
    // fade in blue
 +
    for ( n = 0; n < half; n++ )
 +
    {
 +
      pinArrayValue( g_blue, sizeof( g_blue ), s_fadeValues[ half + n + 1 ] );
 +
      delay( 100 );
 +
    }
 +
    delay( 3000 );
 +
    // fade out blue
 +
    for ( n = 0; n < half; n++ )
 +
    {
 +
      pinArrayValue( g_blue, sizeof( g_blue ), s_fadeValues[ ( half << 1 ) - n ] );
 +
      delay( 100 );
 +
    }
 +
 +
  }
 +
 
 +
  // Fade out blue
 +
  for ( n = 0; n < half; n++ )
 +
  {
 +
    pinArrayValue( g_blue, sizeof( g_blue ), s_fadeValues[ half - n - 1 ] );
 +
    delay( 100 );
 +
  }
 +
 
 +
}
 +
 +
void softLayer()
 +
{
 +
  // Fade in per layer bottom to top
 +
  for ( byte l = 0; l < 4; l++ )
 +
  {
 +
    for ( byte b = 0; b < sizeof( s_fadeValues ); b++ )
 +
    {
 +
      pinArrayValue( g_arduino[ l ], 4, s_fadeValues[ b ] );
 +
      delay( 50 );
 +
    }
 +
      delay( 500 );
 +
  }
 +
 +
  delay( 3000 );
 +
 +
  // Fade in per layer top to bottom
 +
  // Fade in per layer bottom to top
 +
  for ( byte l = 0; l < 4; l++ )
 +
  {
 +
    for ( byte b = 0; b < sizeof( s_fadeValues ); b++ )
 +
    {
 +
      pinArrayValue( g_arduino[ 3 - l ], 4, s_fadeValues[ sizeof( s_fadeValues ) - b - 1 ] );
 +
      delay( 50 );
 +
    }
 +
      delay( 500 );
 +
  }
 +
 +
  delay( 2000 );
 +
 +
}
 +
 +
void guirlande()
 +
{
 +
  // Fade in per pixel, slowly to the top
 +
  for ( byte y = 0; y < 4; y++ )
 +
  {
 +
    for ( byte x = 0; x < 4; x++ )
 +
    {
 +
      for ( byte b = 0; b < sizeof( s_fadeValues ); b++ )
 +
      {
 +
        analogWrite( g_arduino[ y ][ ( x + 1 ) % 4 ], s_fadeValues[ b ] );
 +
        delay( 50 );
 +
      }
 +
    }
 +
  }
 +
 +
  // Fade in per pixel, slowly to the top
 +
  for ( byte y = 0; y < 4; y++ )
 +
  {
 +
    for ( byte x = 0; x < 4; x++ )
 +
    {
 +
      for ( byte b = 0; b < sizeof( s_fadeValues ); b++ )
 +
      {
 +
        analogWrite( g_arduino[ y ][ ( x + 1 ) % 4 ], s_fadeValues[ sizeof( s_fadeValues ) - b - 1 ] );
 +
        delay( 50 );
 +
      }
 +
    }
 +
  }
 +
 +
}
 +
 +
 +
void pinArrayValue( byte* _arrPin, byte _nLength, byte _nValue )
 +
{
 +
  for ( byte n = 0; n < _nLength; n++ )
 +
    analogWrite( _arrPin[ n ], _nValue );
 +
}
 +
 +
void horizontalBlink()
 +
{
 +
  for ( byte x = 0; x < 4; x++ )
 +
  {
 +
    for ( byte y = 0; y < 4; y++ )
 +
    {
 +
      digitalWrite( g_arduino[ y ][ x ], HIGH );
 +
    }
 +
    delay( 100 );
 +
  }
 +
  for ( byte x = 0; x < 4; x++ )
 +
  {
 +
    for ( byte y = 0; y < 4; y++ )
 +
    {
 +
      digitalWrite( g_arduino[ y ][ x ], LOW );
 +
    }
 +
    delay( 100 );
 +
  }
 +
 +
}
 +
 +
void verticalBlink()
 +
{
 +
  for ( byte y = 0; y < 4; y++ )
 +
  {
 +
    for ( byte x = 0; x < 4; x++ )
 +
    {
 +
      digitalWrite( g_arduino[ y ][ x ], HIGH );
 +
    }
 +
    delay( 100 );
 +
  }
 +
  for ( byte y = 0; y < 4; y++ )
 +
  {
 +
    for ( byte x = 0; x < 4; x++ )
 +
    {
 +
      digitalWrite( g_arduino[ y ][ x ], LOW );
 +
    }
 +
    delay( 100 );
 +
  }
 +
 +
}
 +
 +
void randomBlink()
 +
{
 +
  byte x = random( 4 );
 +
  byte y = random( 4 );
 +
  if ( random( 2 ) )
 +
      digitalWrite( g_arduino[ y ][ x ], HIGH );
 +
  else
 +
      digitalWrite( g_arduino[ y ][ x ], LOW );
 +
  delay( 100 );
 +
}</pre>
 +
 +
 +
==== v2 ====
 +
This code running is the one pasted here (with some preparations on doing PWM) Arduino code (portable to plain avr-gcc):
 +
<pre>void setup()
 
{
 
{
 
   // Set tree pins as output
 
   // Set tree pins as output
Line 70: Line 369:
 
// Mapping
 
// Mapping
 
byte g_mappedTree[4][4] = {
 
byte g_mappedTree[4][4] = {
   { 12,  9, 21, 13 }, // Row 1, Da Syntax helped me calculating the number 21 ;)
+
   { 12,  9, 21, 13 }, // Row 1, Da Syntax helped me calculating the number 21&nbsp;;)
 
   { 11, 29, 28, 27 }, // Row 2
 
   { 11, 29, 28, 27 }, // Row 2
 
   {  6,  4,  5, 30 }, // Row 3
 
   {  6,  4,  5, 30 }, // Row 3
Line 78: Line 377:
 
void loop()
 
void loop()
 
{
 
{
   for ( byte n = 0; n < 10; n++ )
+
   for ( byte n = 0; n &lt; 10; n++ )
 
     horizontalBlink();
 
     horizontalBlink();
   for ( byte n = 0; n < 10; n++ )
+
   for ( byte n = 0; n &lt; 10; n++ )
 
     verticalBlink();
 
     verticalBlink();
   for ( byte n = 0; n < 100; n++ )
+
   for ( byte n = 0; n &lt; 100; n++ )
 
     randomBlink();
 
     randomBlink();
 
}
 
}
Line 92: Line 391:
  
 
   // Horizontal
 
   // Horizontal
   for ( byte x = 0; x < 4; x++ )
+
   for ( byte x = 0; x &lt; 4; x++ )
 
   {
 
   {
 
     // Vertical
 
     // Vertical
     for ( byte y = 0; y < 4; y++ )
+
     for ( byte y = 0; y &lt; 4; y++ )
 
     {
 
     {
 
       setLed( x, y );
 
       setLed( x, y );
Line 102: Line 401:
 
   }
 
   }
 
   // Horizontal
 
   // Horizontal
   for ( byte x = 0; x < 4; x++ )
+
   for ( byte x = 0; x &lt; 4; x++ )
 
   {
 
   {
 
     // Vertical
 
     // Vertical
     for ( byte y = 0; y < 4; y++ )
+
     for ( byte y = 0; y &lt; 4; y++ )
 
     {
 
     {
 
       clearLed( x, y );
 
       clearLed( x, y );
Line 120: Line 419:
  
 
   // Vertical
 
   // Vertical
   for ( byte y = 0; y < 4; y++ )
+
   for ( byte y = 0; y &lt; 4; y++ )
 
   {
 
   {
 
   // Horizontal
 
   // Horizontal
     for ( byte x = 0; x < 4; x++ )
+
     for ( byte x = 0; x &lt; 4; x++ )
 
     {
 
     {
 
       setLed( x, y );
 
       setLed( x, y );
Line 130: Line 429:
 
   }
 
   }
 
   // Vertical
 
   // Vertical
   for ( byte y = 0; y < 4; y++ )
+
   for ( byte y = 0; y &lt; 4; y++ )
 
   {
 
   {
 
   // Horizontal
 
   // Horizontal
     for ( byte x = 0; x < 4; x++ )
+
     for ( byte x = 0; x &lt; 4; x++ )
 
     {
 
     {
 
       //setLed( x, y );
 
       //setLed( x, y );
Line 170: Line 469:
 
   byte mappedPort = g_mappedTree[ _y ][ _x ];
 
   byte mappedPort = g_mappedTree[ _y ][ _x ];
 
   // Determine the bit index (lower three bits)
 
   // Determine the bit index (lower three bits)
   byte shiftBit = mappedPort & 7;
+
   byte shiftBit = mappedPort &amp; 7;
  
 
   // Find which port it is (shift out the lower three bits and get the index)
 
   // Find which port it is (shift out the lower three bits and get the index)
 
   // And set the given bit
 
   // And set the given bit
   switch ( mappedPort >> 3 )
+
   switch ( mappedPort &gt;&gt; 3 )
 
   {
 
   {
 
     case 0:
 
     case 0:
       PORTB |= (1 << shiftBit);
+
       PORTB |= (1 &lt;&lt; shiftBit);
 
       break;
 
       break;
 
        
 
        
 
     case 1:
 
     case 1:
       PORTE |= (1 << shiftBit);
+
       PORTE |= (1 &lt;&lt; shiftBit);
 
       break;
 
       break;
 
        
 
        
 
     case 2:
 
     case 2:
       PORTG |= (1 << shiftBit);
+
       PORTG |= (1 &lt;&lt; shiftBit);
 
       break;
 
       break;
  
 
     case 3:
 
     case 3:
       PORTH |= (1 << shiftBit);
+
       PORTH |= (1 &lt;&lt; shiftBit);
 
       break;
 
       break;
 
   }
 
   }
Line 202: Line 501:
 
   byte mappedPort = g_mappedTree[ _y ][ _x ];
 
   byte mappedPort = g_mappedTree[ _y ][ _x ];
 
   // Determine the bit index (lower three bits)
 
   // Determine the bit index (lower three bits)
   byte shiftBit = mappedPort & 7;
+
   byte shiftBit = mappedPort &amp; 7;
  
 
   // Find which port it is (shift out the lower three bits and get the index)
 
   // Find which port it is (shift out the lower three bits and get the index)
 
   // And clear the given bit
 
   // And clear the given bit
   switch ( mappedPort >> 3 )
+
   switch ( mappedPort &gt;&gt; 3 )
 
   {
 
   {
 
     case 0:
 
     case 0:
       PORTB &= ~(1 << shiftBit);
+
       PORTB &amp;= ~(1 &lt;&lt; shiftBit);
 
       break;
 
       break;
 
        
 
        
 
     case 1:
 
     case 1:
       PORTE &= ~(1 << shiftBit);
+
       PORTE &amp;= ~(1 &lt;&lt; shiftBit);
 
       break;
 
       break;
 
        
 
        
 
     case 2:
 
     case 2:
       PORTG &= ~(1 << shiftBit);
+
       PORTG &amp;= ~(1 &lt;&lt; shiftBit);
 
       break;
 
       break;
  
 
     case 3:
 
     case 3:
       PORTH &= ~(1 << shiftBit);
+
       PORTH &amp;= ~(1 &lt;&lt; shiftBit);
 
       break;
 
       break;
  
Line 227: Line 526:
 
}
 
}
 
</pre>
 
</pre>
 +
 +
Location: [[Location::hACKspace]] (on top of the wall-cabinet next to the slACKspace)
 +
[[Category:Arduino]]
 +
[[Category:LEDs]]

Latest revision as of 11:33, 19 December 2016

Project: LED christmas tree
Featured:
State Completed
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.

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

The current (2014) Arduino Mega placed in the stem belongs to the space. Yes, using a Mega is overkill, but at least it has (almost) enough hardware PWM ports for a neat effect with easy programming.

pics

Pics (or vid) or it didn't happen!

2014 - 2015 version

This version adds fade-per-color, and festoon fade mode

2013 version

This is the 2013 version which had 3 modes: rotate, upsweep and random. You can also see a part of the led marquee:

code

v3

Latest version, somewhat cleaned, but 100% arduino code instead of avr-gcc compatible

// Arduino pins mapped in this order to the tree leds
byte g_arduino[4][4] = {
  {  2,  1,  4,  3 }, // Row 1, blue(2)   ORANGE(1) red(4)   green(3)
  {  5,  8,  7,  6 }, // Row 2, orange(5) red(8)    green(7) blue(6)
  { 12, 10, 11,  9 }, // Row 3, red(12)   green(10) blue(11) orange(9)
  { 13, 13, 13, 13 }, // Top;   orange(13); yes it is only one led, so one pin
};

// Arduino pins mapped in this order to the colors
byte g_red[]    = { 4, 8, 12 };
byte g_orange[] = { 1, 5,  9, 13 };
byte g_green[]  = { 3, 7, 10 };
byte g_blue[]   = { 2, 6, 11 };

// Brightness lookup table to make the increments linear
static const byte s_fadeValues[]      = { 0, 1, 2 ,3, 4, 6, 8, 12, 16, 23, 32, 45, 64, 90, 128, 180, 255 };

void setup()
{
    // TODO: define pins as output
}

void loop()
{
  colorFade( 2 );

  for ( byte n = 0; n < 2; n++ )
    softLayer();
    
  for ( byte n = 0; n < 2; n++ )
    guirlande();

  for ( byte n = 0; n < 7; n++ )
    horizontalBlink();

  for ( byte n = 0; n < 7; n++ )
    verticalBlink();

  for ( byte n = 0; n < 100; n++ )
    randomBlink();
    
  for ( byte l = 0; l < 4; l++ )
    pinArrayValue( g_arduino[ l ], 4, 0 );

}

void colorFade( byte _amount )
{
  // Cycle all colors slowly
  byte n;
  byte half = sizeof( s_fadeValues ) >> 1;

  // Halfway fade in blue
  for ( n = 0; n < half; n++ )
  {
    pinArrayValue( g_blue, sizeof( g_blue ), s_fadeValues[ n ] );
    delay( 100 );
  }
  
  for ( byte l = 0; l < _amount; l++ )
  {
    // Fade out blue while fade in orange
    for ( n = 0; n < half; n++ )
    {
      pinArrayValue( g_blue, sizeof( g_blue ), s_fadeValues[ half - n - 1] );
      pinArrayValue( g_orange, sizeof( g_orange ), s_fadeValues[ n ] );
      delay( 100 );
    }

    // fade in orange
    for ( n = 0; n < half; n++ )
    {
      pinArrayValue( g_orange, sizeof( g_orange ), s_fadeValues[ half + n + 1 ] );
      delay( 100 );
    }
    delay( 3000 );
    // fade out orange
    for ( n = 0; n < half; n++ )
    {
      pinArrayValue( g_orange, sizeof( g_orange ), s_fadeValues[ ( half << 1 ) - n ] );
      delay( 100 );
    }

    // Fade out orange while fade in green
    for ( n = 0; n < half; n++ )
    {
      pinArrayValue( g_orange, sizeof( g_orange ), s_fadeValues[ half - n - 1 ] );
      pinArrayValue( g_green, sizeof( g_green ), s_fadeValues[ n ] );
      delay( 100 );
    }

    // fade in green
    for ( n = 0; n < half; n++ )
    {
      pinArrayValue( g_green, sizeof( g_green ), s_fadeValues[ half + n + 1] );
      delay( 100 );
    }
    delay( 3000 );
    // fade out green
    for ( n = 0; n < half; n++ )
    {
      pinArrayValue( g_green, sizeof( g_green ), s_fadeValues[ ( half << 1 ) - n ] );
      delay( 100 );
    }

    // Fade out green while fade in red
    for ( n = 0; n < half; n++ )
    {
      pinArrayValue( g_green, sizeof( g_green ), s_fadeValues[ half - n - 1 ] );
      pinArrayValue( g_red, sizeof( g_red ), s_fadeValues[ n ] );
      delay( 100 );
    }
    
    // fade in red
    for ( n = 0; n < half; n++ )
    {
      pinArrayValue( g_red, sizeof( g_red ), s_fadeValues[ half + n + 1 ] );
      delay( 100 );
    }
    delay( 3000 );
    // fade out red
    for ( n = 0; n < half; n++ )
    {
      pinArrayValue( g_red, sizeof( g_red ), s_fadeValues[ ( half << 1 ) - n ] );
      delay( 100 );
    }

    // Fade out red while fade in blue
    for ( n = 0; n < half; n++ )
    {
      pinArrayValue( g_red, sizeof( g_red ), s_fadeValues[ half - n - 1 ] );
      pinArrayValue( g_blue, sizeof( g_blue ), s_fadeValues[ n ] );
      delay( 100 );
    }
    
    // fade in blue
    for ( n = 0; n < half; n++ )
    {
      pinArrayValue( g_blue, sizeof( g_blue ), s_fadeValues[ half + n + 1 ] );
      delay( 100 );
    }
    delay( 3000 );
    // fade out blue
    for ( n = 0; n < half; n++ )
    {
      pinArrayValue( g_blue, sizeof( g_blue ), s_fadeValues[ ( half << 1 ) - n ] );
      delay( 100 );
    }

  }
  
  // Fade out blue
  for ( n = 0; n < half; n++ )
  {
    pinArrayValue( g_blue, sizeof( g_blue ), s_fadeValues[ half - n - 1 ] );
    delay( 100 );
  }
  
}

void softLayer()
{
  // Fade in per layer bottom to top
  for ( byte l = 0; l < 4; l++ )
  {
    for ( byte b = 0; b < sizeof( s_fadeValues ); b++ )
    {
      pinArrayValue( g_arduino[ l ], 4, s_fadeValues[ b ] );
      delay( 50 );
    }
      delay( 500 );
  }

  delay( 3000 );

  // Fade in per layer top to bottom
  // Fade in per layer bottom to top
  for ( byte l = 0; l < 4; l++ )
  {
    for ( byte b = 0; b < sizeof( s_fadeValues ); b++ )
    {
      pinArrayValue( g_arduino[ 3 - l ], 4, s_fadeValues[ sizeof( s_fadeValues ) - b - 1 ] );
      delay( 50 );
    }
      delay( 500 );
  }

  delay( 2000 );

}

void guirlande()
{
  // Fade in per pixel, slowly to the top
  for ( byte y = 0; y < 4; y++ )
  {
    for ( byte x = 0; x < 4; x++ )
    {
      for ( byte b = 0; b < sizeof( s_fadeValues ); b++ )
      {
        analogWrite( g_arduino[ y ][ ( x + 1 ) % 4 ], s_fadeValues[ b ] );
        delay( 50 );
      }
    }
  }

  // Fade in per pixel, slowly to the top
  for ( byte y = 0; y < 4; y++ )
  {
    for ( byte x = 0; x < 4; x++ )
    {
      for ( byte b = 0; b < sizeof( s_fadeValues ); b++ )
      {
        analogWrite( g_arduino[ y ][ ( x + 1 ) % 4 ], s_fadeValues[ sizeof( s_fadeValues ) - b - 1 ] );
        delay( 50 );
      }
    }
  }

}


void pinArrayValue( byte* _arrPin, byte _nLength, byte _nValue )
{
  for ( byte n = 0; n < _nLength; n++ )
    analogWrite( _arrPin[ n ], _nValue );
}

void horizontalBlink()
{
  for ( byte x = 0; x < 4; x++ )
  {
    for ( byte y = 0; y < 4; y++ )
    {
      digitalWrite( g_arduino[ y ][ x ], HIGH );
    }
    delay( 100 );
  }
  for ( byte x = 0; x < 4; x++ )
  {
    for ( byte y = 0; y < 4; y++ )
    {
      digitalWrite( g_arduino[ y ][ x ], LOW );
    }
    delay( 100 );
  }
 
}

void verticalBlink()
{
  for ( byte y = 0; y < 4; y++ )
  {
    for ( byte x = 0; x < 4; x++ )
    {
      digitalWrite( g_arduino[ y ][ x ], HIGH );
    }
    delay( 100 );
  }
  for ( byte y = 0; y < 4; y++ )
  {
    for ( byte x = 0; x < 4; x++ )
    {
      digitalWrite( g_arduino[ y ][ x ], LOW );
    }
    delay( 100 );
  }
 
}

void randomBlink()
{
  byte x = random( 4 );
  byte y = random( 4 );
  if ( random( 2 ) )
      digitalWrite( g_arduino[ y ][ x ], HIGH );
  else
      digitalWrite( g_arduino[ y ][ x ], LOW );
  delay( 100 );
}


v2

This 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;

  }
}

Location: hACKspace (on top of the wall-cabinet next to the slACKspace)