/* Simple Light Show A light show that is controllable via serial downlink Scott Lawrence 2006 December Arduino is wired up: for each digital pin 2-12: (only 2-9 are in use) Arduino<--------/\/ 220 ohm /\/----[LED]---->>GND for each analog pin 1-3: [ right pin of 10k pot]---->>+5 power Arduino<-------[center pin of 10k pot] [ left pin of 10k pot]---->>GND */ /* NOTE: this should really use #include const int pattern[10][23] PROGMEM = { ... } then use memcpy_P to copy the pattern into a ram buffer to allow for more patterns/bigger data the current design only allows for the following 10 patterns. anything more causes... problems. ref: http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html */ const char pattern[10][23] = { { 13, 0x60, 0x60, 0xf8, 0x3d, 0x1f, 0xdc, 0xdc, 0x1d, 0xdd, 0xdf, 0x18, 0x0, 0x0 }, /* llama */ { 3, 0x49, 0x92, 0x24 }, /* marquee 3 */ { 2, 0x55, 0xaa }, /* marquee */ { 2, 0xff, 0x0 }, /* blink */ { 22, 0x10, 0x20, 0x40, 0x40, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x2, 0x1, 0x1, 0x1, 0x2, 0x2, 0x4, 0x8 }, /* sine */ { 14, 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40 }, /* cylon */ { 6, 0x81, 0x42, 0x24, 0x18, 0x24, 0x42 }, /* double cylon */ { 14, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x7f, 0x3f, 0x1f, 0xf, 0x7, 0x3 }, /* build Break */ { 16, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0x7f, 0x3f, 0x1f, 0xf, 0x7, 0x3, 0x1, 0x0 }, /* roll */ { 8, 0x7, 0xe, 0x1c, 0x38, 0x70, 0xe0, 0xc1, 0x83 }, /* chaser */ }; void printPattern( int pat ) { Serial.print( "P:" ); Serial.print( pat, DEC ); switch( pat ){ case( 0 ): Serial.println( " Llama" ); break; case( 1 ): Serial.println( " Marquee3" ); break; case( 2 ): Serial.println( " Marquee2" ); break; case( 3 ): Serial.println( " Blink" ); break; case( 4 ): Serial.println( " Sine" ); break; case( 5 ): Serial.println( " Cylon" ); break; case( 6 ): Serial.println( " Double Cylon" ); break; case( 7 ): Serial.println( " Build & Break" ); break; case( 8 ): Serial.println( " Roll" ); break; case( 9 ): Serial.println( " Chaser" ); break; default: Serial.println( " ?" ); break; } }; int cs = 1; /* current step */ int cp = 2; /* current pattern */ int d = 100; /* delay */ int flip = 0; int invert = 0; /* configuration of the above bits to arduino digital lines */ int leds[8] = { 9, 8, 7, 6, 5, 4, 3, 2 }; int speedKnob = 0; int patternKnob = 1; int effectKnob = 2; int incButton = 10; int decButton = 11; void setup() { for( int i=2 ; i<13 ; i++ ) { pinMode(i, OUTPUT); } randomSeed( millis() ); Serial.begin( 9600 ); Serial.println( ": DARNIT 2K6 v1.00 Scott Lawrence http://umlautllama.com" ); } int np; int idx, v; int effect; void loop() { /* determine the delay from the speed knob */ d = (1024 - analogRead( speedKnob ))/2; delay( d ); /* advance to the next pattern frame, or loop around */ if( ++cs > pattern[cp][0] ) { /* item 0 is the pattern length */ cs = 1; } /* figure out the pattern from the knob */ np = (analogRead( patternKnob ) * 10)/1024; if( np != cp ) { newPattern( np ); printPattern( np ); cp = np; } /* poll for user input */ serialControl(); /* effect */ effect = (analogRead( effectKnob ) * 7 / 1024 ); switch( effect ) { case( 0 ): outputSolidFrame( HIGH ); return; /* on */ case( 1 ): outputSolidFrame( LOW ); return; /* off */ case( 2 ): flip = 0; invert = 0; break; /* normal */ case( 3 ): flip = 1; invert = 0; break; /* flip */ case( 4 ): flip = 1; invert = 1; break; /* flip and invert */ case( 5 ): flip = 0; invert = 1; break; /* invert */ case( 6 ): outputRandomFrame(); return; /* random */ } /* output the current frame otherwise */ v = 0x01; for( int i = 0; i<8 ; i++ ) { idx = i; if( flip ) { idx = 7-i; } if( pattern[cp][cs] & v ) { if( invert ) digitalWrite( leds[idx], LOW ); else digitalWrite( leds[idx], HIGH ); } else { if( invert ) digitalWrite( leds[idx], HIGH ); else digitalWrite( leds[idx], LOW ); } v = v<<1; } } /* random bits! */ void outputRandomFrame() { for( int j=0 ; j<8 ; j++ ) { if( random( 100 ) > 50 ) { digitalWrite( leds[j], HIGH ); } else { digitalWrite( leds[j], LOW ); } } } /* zeroes */ void outputSolidFrame( int state ) { for( int j=0 ; j<8 ; j++ ) { digitalWrite( leds[j], state ); } } /* select a new pattern, reset the current step */ void newPattern( int p ) { cp = p; cs = 1; } /* handle user input */ void serialControl() { int startD = d; int key = Serial.read(); while( key != -1 ) { if( key >= '0' && key <='9' ) { cp = key - '0'; newPattern( cp ); printPattern( cp ); } switch( key ) { case( 'i' ): if( invert == 1 ) { invert = 0; } else { invert = 1; } Serial.println( "INV" ); break; case( 'f' ): if( flip == 1 ) { flip = 0; } else { flip = 1; } Serial.println( "FLIP" ); break; case( ']' ): d += 10; break; case( '[' ): d -= 5; break; case( 'r' ): flip = 0; invert = 0; d = 100; break; case( 'p' ): newPattern( cp ); break; case( 'q' ): Serial.println( ":DARNIT 2K6 v1.00" ); Serial.print( ":" ); printPattern( cp ); Serial.print( ":S:" ); Serial.println( d, DEC ); Serial.print( ":F:" ); Serial.println( flip, DEC ); Serial.print( ":I:" ); Serial.println( invert, DEC ); if( effect == 0 ) { Serial.print( ":E:1" ); } if( effect == 1 ) { Serial.print( ":E:0" ); } if( effect == 6 ) { Serial.print( ":E:R" ); } break; case( 'h' ): Serial.println( ":DARNIT 2K6 v1.00" ); Serial.println( ": [ ] adj speed" ); Serial.println( ": r reset speed" ); Serial.println( ": p reset pat" ); Serial.println( ": f flip" ); Serial.println( ": i invert" ); Serial.println( ": 0..9 select pat:" ); for( int i=0; i<=9 ; i++ ) { Serial.print( ": " ); printPattern( i ); } } d = constrain( d, 0, 5000 ); /* make sure speed is valid */ if( d != startD ) { Serial.print( "S" ); Serial.println( d ); } key = Serial.read(); } }