Difference between revisions of "LED christmas tree"
(added new version) |
m (fixed media location using filepath) |
||
(7 intermediate revisions by the same user not shown) | |||
Line 3: | Line 3: | ||
|Members=Vicarious, Xopr | |Members=Vicarious, Xopr | ||
|Description=Blinken lights! | |Description=Blinken lights! | ||
+ | |Picture=LED_christmas_tree_Picture.jpg | ||
}} | }} | ||
=== synopsis === | === synopsis === | ||
Line 14: | Line 15: | ||
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. | 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. | |
− | + | 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 === | ||
Line 22: | Line 23: | ||
Pics (or vid) or it didn't happen! | 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 | {{#widget:Html5media | ||
− | |url= | + | |url={{filepath:Christmas_tree_and_message_ticker.mov}} |
|width=640 | |width=640 | ||
|height=360 | |height=360 | ||
− | }} | + | }} |
=== code === | === code === | ||
Line 32: | Line 39: | ||
==== v3 ==== | ==== v3 ==== | ||
Latest version, somewhat cleaned, but 100% arduino code instead of avr-gcc compatible | Latest version, somewhat cleaned, but 100% arduino code instead of avr-gcc compatible | ||
− | <pre> | + | <pre>// Arduino pins mapped in this order to the tree leds |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
byte g_arduino[4][4] = { | byte g_arduino[4][4] = { | ||
{ 2, 1, 4, 3 }, // Row 1, blue(2) ORANGE(1) red(4) green(3) | { 2, 1, 4, 3 }, // Row 1, blue(2) ORANGE(1) red(4) green(3) | ||
Line 46: | Line 47: | ||
}; | }; | ||
− | + | // Arduino pins mapped in this order to the colors | |
− | // Arduino pins | ||
byte g_red[] = { 4, 8, 12 }; | byte g_red[] = { 4, 8, 12 }; | ||
byte g_orange[] = { 1, 5, 9, 13 }; | byte g_orange[] = { 1, 5, 9, 13 }; | ||
Line 53: | Line 53: | ||
byte g_blue[] = { 2, 6, 11 }; | 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 }; | static const byte s_fadeValues[] = { 0, 1, 2 ,3, 4, 6, 8, 12, 16, 23, 32, 45, 64, 90, 128, 180, 255 }; | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
void setup() | void setup() | ||
Line 78: | Line 63: | ||
void loop() | void loop() | ||
{ | { | ||
− | |||
− | |||
− | |||
− | |||
colorFade( 2 ); | colorFade( 2 ); | ||
Line 284: | Line 265: | ||
for ( byte n = 0; n < _nLength; n++ ) | for ( byte n = 0; n < _nLength; n++ ) | ||
analogWrite( _arrPin[ n ], _nValue ); | analogWrite( _arrPin[ n ], _nValue ); | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
Line 307: | Line 273: | ||
for ( byte y = 0; y < 4; y++ ) | for ( byte y = 0; y < 4; y++ ) | ||
{ | { | ||
− | + | digitalWrite( g_arduino[ y ][ x ], HIGH ); | |
} | } | ||
delay( 100 ); | delay( 100 ); | ||
Line 315: | Line 281: | ||
for ( byte y = 0; y < 4; y++ ) | for ( byte y = 0; y < 4; y++ ) | ||
{ | { | ||
− | + | digitalWrite( g_arduino[ y ][ x ], LOW ); | |
} | } | ||
delay( 100 ); | delay( 100 ); | ||
Line 328: | Line 294: | ||
for ( byte x = 0; x < 4; x++ ) | for ( byte x = 0; x < 4; x++ ) | ||
{ | { | ||
− | + | digitalWrite( g_arduino[ y ][ x ], HIGH ); | |
} | } | ||
delay( 100 ); | delay( 100 ); | ||
Line 336: | Line 302: | ||
for ( byte x = 0; x < 4; x++ ) | for ( byte x = 0; x < 4; x++ ) | ||
{ | { | ||
− | + | digitalWrite( g_arduino[ y ][ x ], LOW ); | |
} | } | ||
delay( 100 ); | delay( 100 ); | ||
Line 348: | Line 314: | ||
byte y = random( 4 ); | byte y = random( 4 ); | ||
if ( random( 2 ) ) | if ( random( 2 ) ) | ||
− | + | digitalWrite( g_arduino[ y ][ x ], HIGH ); | |
else | else | ||
− | + | digitalWrite( g_arduino[ y ][ x ], LOW ); | |
delay( 100 ); | delay( 100 ); | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
}</pre> | }</pre> | ||
Line 619: | 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 | |
Contents
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)