Just as a challenge I wanted to emulate the effect using ordinary white LEDs and a microcontroller. After some trial and error I got the firmware working. I'm sure it could be improved upon and different variations could be implemented. For instance as in the second vid above, the cascade could be made without PWM, leaving fading for the very last LED.
So here's a vid of the breadboarded circuit. The firmware that drives it follows. If anyone will be so kind enough to donate a real video cam the pic quality can be greatly enhanced :-)
/* Cascading (Snowfall or Meteor) LED Lights October 16 2011 processor = PIC16F1827 compiler = mikroC v5.0.0 (configuration settings -- copied from mikroC's "Edit Project" window) CONFIG1 :$8007 : 0x0F84 CONFIG2 :$8008 : 0x1613 */ // if using different PORT pins just change the assignments below // the firmware does not need to be edited #define led1 LATA.f1 // led1 is the first LED to be lit (topmost LED of the cascade) #define led2 LATA.f0 #define led3 LATA.f7 #define led4 LATA.f6 #define led5 LATB.f7 #define led6 LATB.f6 #define led7 LATB.f5 #define led8 LATB.f4 #define led9 LATB.f3 #define led10 LATB.f2 #define led11 LATB.f1 #define led12 LATB.f0 #define led13 LATA.f4 #define led14 LATA.f3 #define led15 LATA.f2 // led15 is the last LED to be lit (bottom LED of the cascade) #define lastled led15 // this is used in the Twinkle() function // following used for twinkle effect #define fadeintime 2 // number of PWM periods for each pulse width during fade in from min to max brightness #define fadeouttime 7 // number of PWM periods for each pulse width during fade out from max to min brightness #define twinkle_delay 1 // deciseconds between the end of the cascade and beginning of twinkle effect // during this time led15 is off #define cascade_delay 20 // deciseconds between cascades. during this time all LEDs are off // time begins after Twinkle() #define t0_ini 256-128 // TMR0 initialize value every time it overflows #define t1h_ini 256-98 // TMR1H initialize value every time it overflows #define cascadetime 10 // number of cycles (PWM periods) per stage #define maxstage 22 // maximum number of stages // a stage is when a set of LEDs are lit // each successive stage moves the cascade by one LED #define int1 bit #define int8 unsigned char #define int16 unsigned int #define int32 unsigned long #define on 1 #define off 0 // ================================================================================================================== void IniReg() { OSCCON = 0b1110000; // 8MHz TRISA = 0; TRISB = 0; ANSELA = 0; ANSELB = 0; LATA = 0; LATB = 0; T1CON = 0b110000; // prescale = 1:8, timer1 off // given 8MHz, TMR1H = 98 counts, prescale = 1:8, timer1 tick = ~100ms } // void IniReg() // During the start of each PWM period the LEDs that will be "PWMed" for that stage are turned on. void IniLEDs(int8 STAGE) { switch (STAGE) { case 1: led1 = on; break; case 2: led1 = on; led2 = on; break; case 3: led1 = on; led2 = on; led3 = on; break; case 4: led1 = on; led2 = on; led3 = on; led4 = on; break; case 5: led1 = on; led2 = on; led3 = on; led4 = on; led5 = on; break; case 6: led1 = on; led2 = on; led3 = on; led4 = on; led5 = on; led6 = on; break; case 7: led1 = on; led2 = on; led3 = on; led4 = on; led5 = on; led6 = on; led7 = on; break; case 8: led1 = on; led2 = on; led3 = on; led4 = on; led5 = on; led6 = on; led7 = on; led8 = on; break; case 9: led2 = on; led3 = on; led4 = on; led5 = on; led6 = on; led7 = on; led8 = on; led9 = on; break; case 10: led3 = on; led4 = on; led5 = on; led6 = on; led7 = on; led8 = on; led9 = on; led10 = on; break; case 11: led4 = on; led5 = on; led6 = on; led7 = on; led8 = on; led9 = on; led10 = on; led11 = on; break; case 12: led5 = on; led6 = on; led7 = on; led8 = on; led9 = on; led10 = on; led11 = on; led12 = on; break; case 13: led6 = on; led7 = on; led8 = on; led9 = on; led10 = on; led11 = on; led12 = on; led13 = on; break; case 14: led7 = on; led8 = on; led9 = on; led10 = on; led11 = on; led12 = on; led13 = on; led14 = on; break; case 15: led8 = on; led9 = on; led10 = on; led11 = on; led12 = on; led13 = on; led14 = on; led15 = on; break; case 16: led9 = on; led10 = on; led11 = on; led12 = on; led13 = on; led14 = on; led15 = on; break; case 17: led10 = on; led11 = on; led12 = on; led13 = on; led14 = on; led15 = on; break; case 18: led11 = on; led12 = on; led13 = on; led14 = on; led15 = on; break; case 19: led12 = on; led13 = on; led14 = on; led15 = on; break; case 20: led13 = on; led14 = on; led15 = on; break; case 21: led14 = on; led15 = on; break; case 22: led15 = on; break; default: break; } // switch (STAGE) } //void IniLEDs() // Within the PWM period, LEDs are turned off when their particular pulse width has been reached. void SwitchLEDs(int8 STAGE, int8 PWEXP) { switch (PWEXP) { case 0: switch (STAGE) { case 8: led1 = off; break; case 9: led2 = off; break; case 10: led3 = off; break; case 11: led4 = off; break; case 12: led5 = off; break; case 13: led6 = off; break; case 14: led7 = off; break; case 15: led8 = off; break; case 16: led9 = off; break; case 17: led10 = off; break; case 18: led11 = off; break; case 19: led12 = off; break; case 20: led13 = off; break; case 21: led14 = off; break; case 22: led15 = off; break; default: break; } break; case 1: switch (STAGE) { case 7: led1 = off; break; case 8: led2 = off; break; case 9: led3 = off; break; case 10: led4 = off; break; case 11: led5 = off; break; case 12: led6 = off; break; case 13: led7 = off; break; case 14: led8 = off; break; case 15: led9 = off; break; case 16: led10 = off; break; case 17: led11 = off; break; case 18: led12 = off; break; case 19: led13 = off; break; case 20: led14 = off; break; case 21: led15 = off; break; default: break; } break; case 2: switch (STAGE) { case 6: led1 = off; break; case 7: led2 = off; break; case 8: led3 = off; break; case 9: led4 = off; break; case 10: led5 = off; break; case 11: led6 = off; break; case 12: led7 = off; break; case 13: led8 = off; break; case 14: led9 = off; break; case 15: led10 = off; break; case 16: led11 = off; break; case 17: led12 = off; break; case 18: led13 = off; break; case 19: led14 = off; break; case 20: led15 = off; break; default: break; } break; case 3: switch (STAGE) { case 5: led1 = off; break; case 6: led2 = off; break; case 7: led3 = off; break; case 8: led4 = off; break; case 9: led5 = off; break; case 10: led6 = off; break; case 11: led7 = off; break; case 12: led8 = off; break; case 13: led9 = off; break; case 14: led10 = off; break; case 15: led11 = off; break; case 16: led12 = off; break; case 17: led13 = off; break; case 18: led14 = off; break; case 19: led15 = off; break; default: break; } break; case 4: switch (STAGE) { case 4: led1 = off; break; case 5: led2 = off; break; case 6: led3 = off; break; case 7: led4 = off; break; case 8: led5 = off; break; case 9: led6 = off; break; case 10: led7 = off; break; case 11: led8 = off; break; case 12: led9 = off; break; case 13: led10 = off; break; case 14: led11 = off; break; case 15: led12 = off; break; case 16: led13 = off; break; case 17: led14 = off; break; case 18: led15 = off; break; default: break; } break; case 5: switch (STAGE) { case 3: led1 = off; break; case 4: led2 = off; break; case 5: led3 = off; break; case 6: led4 = off; break; case 7: led5 = off; break; case 8: led6 = off; break; case 9: led7 = off; break; case 10: led8 = off; break; case 11: led9 = off; break; case 12: led10 = off; break; case 13: led11 = off; break; case 14: led12 = off; break; case 15: led13 = off; break; case 16: led14 = off; break; case 17: led15 = off; break; default: break; } break; case 6: switch (STAGE) { case 2: led1 = off; break; case 3: led2 = off; break; case 4: led3 = off; break; case 5: led4 = off; break; case 6: led5 = off; break; case 7: led6 = off; break; case 8: led7 = off; break; case 9: led8 = off; break; case 10: led9 = off; break; case 11: led10 = off; break; case 12: led11 = off; break; case 13: led12 = off; break; case 14: led13 = off; break; case 15: led14 = off; break; case 16: led15 = off; break; default: break; } break; // for PWEXP = 7, no led need be switched off since it's duty cycle will be gradually decreased anyway in the next STAGE // therefore there's no need for a separate case statement. // The default option below will automatically "catch" the case when PWEXP = 7 default: break; } // switch (PULSEWIDTH) } // void SwitchLEDs() /* The particular LEDs to be lit and their pulse width depends on the current STAGE. At the start of each PWM period all LEDs for the particular stage are turned on. Then one by one, beginning with the LED that has the least pulse width, they're turned off. After the second TMR0 overflow, the prescale value of timer0 is changed every TMR0 overflow as shown in the table below. Every time TMR0 overflows it is re-initialized with t0_ini (128decimal). The total time elapsed is the pulse width of the LEDs. The change in PW between the LEDs is exponential. The lead LED has a duty cycle of 100%. PWN period = 8.192ms Fosc = 8Mhz t0 tick = (TMR0 count)*(prescale)/(Fosc/4) t0_ini TMR0 count prescale t0 tick (us) total time elapsed (us) 128 128 1 64 64 128 128 1 64 128 128 128 2 128 256 128 128 4 256 512 128 128 8 512 1024 128 128 16 1024 2048 128 128 32 2048 4096 128 128 64 4096 8192 */ void Cascade() { // OPTREG[] lookup table contains values to be successively loaded into OPTION register during one PWM period // timer0 prescale values are {1,1,2,4,8,16,32,64} // to obtain timer0 prescale value = 1, prescaler is NOT assigned to timer0 // timer0 initial value is kept constant at 128decimal const int8 OPTREG[] = {0b1000, 0b1000, 0b0, 0b1, 0b10, 0b11, 0b100, 0b101}; int8 STAGE; // at which stage the cascade is currently int8 PWEXP; // exponent (with base = 2) of the pulse width int8 TOTALTIME; // records number of PWM periods PWEXP = 0; for (STAGE = 1; STAGE <= maxstage; STAGE++) { TOTALTIME = 0; while (TOTALTIME <= cascadetime) { if (!PWEXP) // initialize (turn on) LEDs only when it's the start of a PWM period IniLEDs(STAGE); OPTION_REG = OPTREG[PWEXP]; TMR0 = t0_ini; INTCON.T0IF = 0; while (!INTCON.T0IF) ; SwitchLEDs(STAGE, PWEXP); // turn off the LED if (++PWEXP > 7) { PWEXP = 0; TOTALTIME++; } } // while (TOTALTIME <= cascadetime) } // for (STAGE=1; STAGE<= maxstage; STAGE++) } // void Cascade() // PWM routine for the twinkle effect void Dim(int8 EXP, int8 FADETIME) { // pulse width (output high = led on) in terms of the value of TMR0, given a fixed timer0 period of 8.192ms const int8 PW[] = {1, 2, 4, 8, 16, 32, 64, 128, 255}; int8 TOTALTIME = 0; int8 PULSEWIDTH; TMR0 = 0; INTCON.T0IF = 0; PULSEWIDTH = PW[EXP]; while (TOTALTIME++ <= FADETIME) { lastled = on; while (TMR0 < PULSEWIDTH); lastled = off; while (!INTCON.T0IF); INTCON.T0IF = 0; } } // twinkle effect where fade in time and fade out time are or can be different void Twinkle() { int8 i; OPTION_REG = 0b10000101; // timer0 prescale = 1:64 for (i = 0; i <= 8; i++) Dim(i, fadeintime); for (i = 7; i > 0; i--) Dim(i, fadeouttime); lastled = off; } // void Twinkle() // delay in deciseconds // as an alternative timer0 can be used instead of timer1 if, say, using an MCU with only one timer void DelayDsec(int8 dsec) { int8 i; TMR1L = 0; T1CON.TMR1ON = 1; for (i = 0; i < dsec; i++) { TMR1H = t1h_ini; PIR1.TMR1IF = 0; while (!PIR1.TMR1IF); } T1CON.TMR1ON = 0; } // void DeadTime() void main() { IniReg(); while(1) { Cascade(); DelayDsec(twinkle_delay); Twinkle(); DelayDsec(cascade_delay); } } // void main()
----
November 23 2011 Addendum
Here's the schematic for the cascading lights circuit. As you can see it's just one MCU and LEDs on all the pins except for pin#4 (RA5) which is an input-only pin. Resistors can be as low as, oh about, 180 ohms for a power supply of 5 volts. You have to watch out for the maximum rating of each pin (25mA if I remember correctly) and the maximum for each PORT.
----
Schematic when using a PIC16F84A