Pagina1 van 1

Arduino – Alle LEDStrip effecten in èèn (NeoPixel en FastLED)

Arduino – Alle LEDStrip effecten in èèn (NeoPixel en FastLED)
   24

Als je het artikel “LEDStrip effecten voor NeoPixel en FastLED” hebt gelezen, dan zul je misschien gezien hebben dat een aantal bezoekers graag een sketch hadden gezien waarbij alle effecten staan. Een aantal van de bezoekers hebben een aantal mooie resultaten bij elkaar gezet en me soms op weg geholpen naar dit eind product.

De belangrijkste uitdaging was toch wel: hoe schakel ik snel om van het ene effect naar het andere.

Vandaag dus eindelijk wat tijd gevonden en het helemaal uitgewerkt … dus veel plezier met de LED effecten!




Overzicht

Framewerk – NeoPixel of FastLED

Ik moet toegeven dat ik een FastLED fan ben – het is zo veel meer volwassen en geavanceerd in vergelijk met NeoPixel. Maar net als in het originele artikel, ga ik ook hier de code beschikbaar maken voor beiden. FastLED mag dan geavanceerder zijn, NeoPixel neemt weer minder geheugen in beslag. Je hebt dus de keuze. Op mijn Arduino Uno R3 loopt het overigens uitstekend met FastLED.

Ik kan aanraden om het originele artikel eerst te lezen “LEDStrip effecten voor NeoPixel en FastLED“, maar verplicht is het niet omdat ik hier onder de volledige code publiceer.

Installeren van FastLED of NeoPixel

De Arduino IDE is sinds het originele artikel ook verbeterd en met name de installatie van bibliotheken is eenvoudiger geworden.

De Arduino IDE kun je gratis van hun website downloaden – Er staat ook een online versie van de IDE maar die heb ik nog nooit gebruikt.

Nadat je de Arduino IDE hebt gestart, dit kan even duren, ga naar het menu en kies “SketchInclude LibraryManage Libraries“.
In het venster dat opkomt, voer je in het “filter” veld “neopixel” of “fastled” in en druk daarna op de ENTER toets.

De bibliotheek die je wilt gebruiken kun je hier kiezen (getest met v3.1.0 van FastLED en v1.1.3 van NeoPixel) en klik vervolgens op “Install“.

En dat is alles – eitje toch …?

Arduino IDE - Bibliotheek toevoegen

Arduino IDE – Bibliotheek toevoegen

Downloaden van de LEDEffect Sketches

Aan het einde van het artikel laat ik je de volledige code zien, maar bespaar jezelf het typen en/of kopiëren en plakken want je kunt het hier gewoon downloaden.

Instellingen … wel even controleren! 

Uiteraard moeten de instellingen in de code wel overeenkomen met jouw Arduino en LEDstrip.

#define PIN 5
Je moet er voor zorgen dat dit nummer (5) overeenkomt met de Din van jouw LED strip – dit kan dus b.v. pin 6 zijn.

#define NUM_LEDS 60
Zorg ervoor dat dit nummer overeenkomt met het aantal LEDs op jouw LED strip(s).

Voor wie FastLED gebruikt, zorg ervoor dat de “FastLED.addLeds” functie correct aangeroepen wordt voor jouw LED strip – ik heb een WS2811/WS218 LED stip gebruikt – controleer ook dat de kleur volgorde correct is (RGB vs GRB)!
Voor NeoPixel gebruikers, controleer de “Adafruit_NeoPixel strip” regel zodat dit overeenkomt met jouw LED strip – ook hier heb ik een WS2811/WS2812 gebruikt – controleer ook de kleur volgorde (NEO_RGB in dit geval).

Merk op :
Voor de schakelaar moet je PIN 2 gebruiken aangezien deze een interrupt toestaat. Pin 3 kan eventueel ook, maar dan moet je dus wel  #define BUTTON 2 naar #define BUTTON 3 veranderen. Al deze instellingen zijn voor een Arduino UNO R3. Andere Arduino modellen zouden een andere PIN nodig kunnen hebben.

DOWNLOAD - AllEffects LEDStrip Effect (FastLED) 

Bestand: AllEffects_FastLED.ino.zip
Versie: 1.0
Omvang: 4.6 KiB
Datum: 3 jan 2018
 Download Nu 

DOWNLOAD - AllEffects LEDStrip Effect (NeoPixel) 

Bestand: AllEffects_NeoPixel.ino.zip
Versie: 1.0
Omvang: 4.6 KiB
Datum: 3 jan 2018
 Download Nu 

LED Hardware Opzet

Omdat we effecten willen wisselen, hebben we natuurlijk een schakelaar nodig.

Merk op : In de tekening heb ik PIN 6 gebruikt, maar omdat ik PIN 6 per ongeluk beschadigd heb moest ik tussen door overschakelen op PIN, dus even de code controleren voor je gaat testen (pas #define PIN 5 aan naar #define PIN 6 of gebruik PIN 5 i.p.v. PIN 6) – sorry voor de verwarring hier.

De opzet is hetzelfde als in het originele artikel, ik heb alleen een schakelaar toegevoegd.
De schakelaar moet een druk schakelaar zijn van het type “maak contact” – dus er wordt alleen contact gemaakt als je de schakelaar ingedrukt houdt.

Arduino Hardware opstelling

Arduino Hardware opstelling

Uitleg Uitdagingen van dit project

De gebruikers die de effecten in een enkele sketch wilden zetten liepen eigenlijk allemaal tegen uitdagingen aan die soms niet zo eenvoudig op te lossen zijn. Ik probeer ze hieronder toe te lichten zodat anderen er misschien iets aan hebben.

Uitdaging 1 – Effecten die Eindeloos zijn

Een aantal effecten, en dan met de name de effecten met de stuiterballen, zijn eindeloos. Een van de bezoekers op de Engelstalige pagina, Daniel, wees me in de juiste richting om het stuiter effect te onderbreken. Ik heb dat wat verder uitgewerkt zodat het ook met meerdere ballen werkt.

In het kort, de “while”-loop zorgde ervoor dat het effect eindeloos bleef doorgaan – en dat was ook de bedoeling:


...
  while(true) {
  ...
  }
...

Voor het effect met een enkele bal, kan men het afvangen door de if ( ImpactVelocity[i] < 0.01 ) { ... } regels aan te passen. Voor meerdere ballen werkt dat echter niet tenzij je nog meer aanpassingen maakt.

De basis van de oplossing is gewoon het volgen van de status van de individuele ballen. Als ze allemaal zijn uit gestuiterd, dan kunnen we de functie verlaten.

Hieronder de uiteindelijke bouncingBalls() functie.
Ik heb een parameter toegevoegd waarmee je de functie aan kunt roepen voor een enkel stuiter effect of voor eindeloos doorgaand.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
void BouncingColoredBalls(int BallCount, byte colors[][3], boolean continuous) {
  float Gravity = -9.81;
  int StartHeight = 1;
 
  float Height[BallCount];
  float ImpactVelocityStart = sqrt( -2 * Gravity * StartHeight );
  float ImpactVelocity[BallCount];
  float TimeSinceLastBounce[BallCount];
  int   Position[BallCount];
  long  ClockTimeSinceLastBounce[BallCount];
  float Dampening[BallCount];
  boolean ballBouncing[BallCount];
  boolean ballsStillBouncing = true;
 
  for (int i = 0 ; i < BallCount ; i++) {  
    ClockTimeSinceLastBounce[i] = millis();
    Height[i] = StartHeight;
    Position[i] = 0;
    ImpactVelocity[i] = ImpactVelocityStart;
    TimeSinceLastBounce[i] = 0;
    Dampening[i] = 0.90 - float(i)/pow(BallCount,2);
    ballBouncing[i]=true;
  }

  while (ballsStillBouncing) {
    for (int i = 0 ; i < BallCount ; i++) {
      TimeSinceLastBounce[i] =  millis() - ClockTimeSinceLastBounce[i];
      Height[i] = 0.5 * Gravity * pow( TimeSinceLastBounce[i]/1000 , 2.0 ) + ImpactVelocity[i] * TimeSinceLastBounce[i]/1000;
 
      if ( Height[i] < 0 ) {                      
        Height[i] = 0;
        ImpactVelocity[i] = Dampening[i] * ImpactVelocity[i];
        ClockTimeSinceLastBounce[i] = millis();
 
        if ( ImpactVelocity[i] < 0.01 ) {
          if (continuous) {
            ImpactVelocity[i] = ImpactVelocityStart;
          } else {
            ballBouncing[i]=false;
          }
        }
      }
      Position[i] = round( Height[i] * (NUM_LEDS - 1) / StartHeight);
    }

    ballsStillBouncing = false; // assume no balls bouncing
    for (int i = 0 ; i < BallCount ; i++) {
      setPixel(Position[i],colors[i][0],colors[i][1],colors[i][2]);
      if ( ballBouncing[i] ) {
        ballsStillBouncing = true;
      }
    }
   
    showStrip();
    setAll(0,0,0);
  }
}

Uitdaging 2 – Knop indruk opvangen

De volgende uitdaging is het detecteren dat de knop wordt ingedrukt.

Uiteraard begon ik met de standaard Button tutorial op de Arduino website, tot ik kort daarna een eenvoudigere method vond. Als je de officiële tutorial volgt dan zie je dat er een weerstand wordt gebruikt. Blijkbaar kan het ook zonder – ik las een artikel waarin men sprak over gebruik maken van een interne weerstand. Dat maakt natuurlijk het opzetten eenvoudiger.

Uiteraard hebben we een PIN nodig voor de knop (je leest er meer over in de volgende uitdaging).
We hebben een PIN nodig die onze sketch kan onderbreken (interrupt) zodat het effect van het indrukken van de knop meteen iets kan doen.
De gebruikelijke manier staat dit echter niet toe, dus we moeten een van de speciale pinnen op de Arduino hiervoor gebruiken. Op de “klassieke” manier moeten we namelijk door de hele code functies plakken die controleren of de knop is ingedrukt of niet. Maar met de speciale pinnen hoeft dat niet! Het is alleen even vogelen om te zien hoe dat werkt.

Deze “interrupt” PINnen zijn voor een Arduino Uno PIN 2 en PIN 3. Volgens de uitleg of the Arduino website:

Pinnen vor Interrupts
 Uno, Nano, Mini, andere 328-gebaseerd  2, 3
 Mega, Mega2560, MegaADK  2, 3, 18, 19, 20, 21
 Micro, Leonardo, andere 32u4-gebaseerd  0, 1, 2, 3, 7
 Zero  Alle digitale pinnen, behalve pin 4
 MKR1000 Rev.1  0, 1, 4, 5, 6, 7, 8, 9, A1, A2
 Due  alle digitale pinnen
 101  2, 5, 7, 8, 10, 11, 12, 13

Om de knop te laten werken met de interne weerstand, moeten we het volgende doen in “setup()” functie:


digitalWrite (BUTTON, HIGH);  // internal pull-up resistor

Later kunnen we testen of de knop ingedrukt is (maak contact):


if (digitalRead (BUTTON) == HIGH) {
  ...
}

Uitdaging 3 – Effect onderbreken om een knop-druk af te vangen

De methode die ik hier heb gebruikt werkte het best voor mijn toepassing – maar er zijn vast betere opties.

Ik heb hiervoor een zogenaamde interrupt gebruikt, daarom moest ik dus PIN 2 gebruiken. We willen namelijk het indrukken van de knop afvangen, ongeacht vaan waar de Arduino is in de sketch – de functie “attachInterrupt()” biedt hiervoor een oplossing. Als je meer details wilt, lees dan het Arduino attachInterrupt Documentatie.

Wat we willen: als de status van de knop (BUTTON) veranderd (CHANGE), ga naar onze speciale functie (changeEffect()).

In code ziet er dat ongeveer zo uit:


attachInterrupt (digitalPinToInterrupt(BUTTON), changeEffect, CHANGE); // pressed

Als je de documentatie leest dan zul je misschien willen weten waarom ik de “CHANGE” mode heb gekozen en niet de “LOW” of “HIGH” mode. Na wat testen bleek alleen de CHANGE mode een betrouwbare oplossing voor onze toepassing. Vervolgens kijk ik dan in de eigen functie “changeEffect()” of de knop is ingedrukt. Dit gaat overigens super snel!


void changeEffect() {
  if (digitalRead (BUTTON) == HIGH) {
    selectedEffect++;
  }
}

Zoals je hier ziet, als de knop is ingedrukt dan zal de functie de variabele “selectedEffect” met 1 verhogen.

Uitdaging 4 – Starten van het nieuwe effect

OK, we kunnen de knop dus registeren als het ingedrukt wordy – mooi!
Maar hoe gaan we terug naar het begin van de “loop()” functie?

Omdat we verschillende niveaus hebben waarbij loops in loops en functies lopen, is een eenvoudige “break” of “return” geen optie.
Dus ik moest iets beters vinden om de loop() te herstarten.

Er is geen eenvoudige en voor de hand liggende methode. Ik zie veel mensen met dezelfde vraag, maar in plaats van een antwoord te geven, gaan leiden dan in de discussie waarom je dit niet zou mogen willen. Beetje raar – want ik vindt het een legitieme vraag.

Uiteindelijk vond ik dan toch een handig stukje code dat in assembler code (in tegenstelling to de C taal die de Arduino gebruikt) de Arduino reset door gewoon naar adres 0 (nul) te springen. En dat blijkt erg goed te werken.


asm volatile ("  jmp 0");

Deze regel kun je waar dan ook in een Arduino sketch zetten en de Arduino zal zichzelf resetten als dit aangeroepen wordt. Er zijn natuurlijk wat kanttekeningen bij deze methode, maar voor onze toepassing werkt het prima.

Gecombineerd met de functie die de knop druk afhandelt wordt dit dan dus:


1
2
3
4
5
6
void changeEffect() {
  if (digitalRead (BUTTON) == HIGH) {
    selectedEffect++;
    asm volatile ("  jmp 0");
  }
}

Nogmaals: Dit is gecompliceerder als dat je zou denken. Het beschadigd de Arduino niet maar een aantal ontwikkelaars zullen wel hun opmerkingen klaar hebben.

Er is echter een probleem met het resetten van de Arduino: alle variabelen gaan verloren!
Of beter gezegd: alles variabelen worden ook gereset …

Op zich geen probleem, maar we moeten natuurlijk wel weten welk effect we willen zien – en die is dus ook weer op nul gezet …

Uitdaging 5 – Variable die een reset overleeft

Je kunt je voorstellen dat ik me goed vermaakt heb vandaag met dit project, zeker omdat ik oplossingen had voor bepaalde uitdagingen.

Maar wat doen we nou om te voorkomen dat we de waarde van “selectedEffect” niet verliezen? Het is niet alsof de Arduino een harddisk of SD kaart heeft om de waarde op te slaan …
Ehm … dat is niet helemaal waar. De Arduino heeft namelijk een EEPROM – een stukje geheugen dat na stroom verlies of reset niet zijn inhoud verliest.

Gelukkige heeft de Arduino hiervoor bepaalde functies! Zie de EEPROM documentatie voor meer details.

Overigens: Je moet EEPROMs niet belachelijk vaak lezen en/of schrijven, er is een beperkt aantal keren dat dit goed gaat (EEPROM zou theoretisch kunnen falen na 100,000 read/write operaties). Dat is overigens wel een erg groot aantal klikken, dus ik maak me er op dit moment niet druk om.

Terug naar onze uitdaging, waarbij ik dus de waarde van het gekozen effect (een byte!) in de EEPROM ga opslaan.

We hebben hiervoor als eerste de EEPROM bibliotheek nodig:


#include <EEPROM.h>

Schrijven en lezen van een enkel EEPROM adres is erg eenvoudig:


// read EEPORM address 0 (1 byte)
EEPROM.get(0,selectedEffect);

// write EEPROM address 0 (also 1 byte)
EEPROM.put(0, selectedEffect);

Zoals je in de code kunt zien, definiëren we de variabele “selectedEffect” van het type byte – ik heb dat expres gedaan om het simpel te houden.
Adres “0” van de EEPROM wordt blijkbaar vaak gebruikt in voorbeelden dus ik zie geen reden om een ander adres te gaan gebruiken. Bovendien hebben niet alle Arduino’s dezelfde hoeveelheid EEPROM geheugen.

Let wel op dat we de waarden van het EEPROM adres niet in “setup()” functie kunnen definiëren, want dan zou na een reset diezelfde “setup()” functie onze waarde weer wissen.

Ik heb daarom ervoor gekozen om de waarde in de EEPROM maar te nemen zoals het is. Als we een waarde lezen die groter is dan het aantal effecten (18), dan zetten we de waarde gewoon terug op nul. Handig want dat past precies in wat we willen zodat we door de effecten kunnen klikken.

In code:


EEPROM.get(0,selectedEffect);
 
if(selectedEffect>18) {
  selectedEffect=0;
  EEPROM.put(0,0);
}

Als we dit nu in onze knop-druk functie hangen dan ziet er dat zo uit:


void changeEffect() {
  if (digitalRead (BUTTON) == HIGH) {
    selectedEffect++;
    EEPROM.put(0, selectedEffect); // store the chose effect
    asm volatile ("  jmp 0");      // reset the Arduino
  }
}

Broncode – Sketch

Je kunt de sketch hierboven downloaden, dus je hoeft ze niet te kopiëren en plakken. Maar ej kunt ze hieronder bekijken;

FastLED


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
#include "FastLED.h"
#include <EEPROM.h>
#define NUM_LEDS 60
CRGB leds[NUM_LEDS];
#define PIN 5

#define BUTTON 2
byte selectedEffect=0;

void setup()
{
  FastLED.addLeds<WS2811, PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  digitalWrite (BUTTON, HIGH);  // internal pull-up resistor
  attachInterrupt (digitalPinToInterrupt (BUTTON), changeEffect, CHANGE); // pressed
}

// *** REPLACE FROM HERE ***
void loop() {
  EEPROM.get(0,selectedEffect);
 
  if(selectedEffect>18) {
    selectedEffect=0;
    EEPROM.put(0,0);
  }
 
  switch(selectedEffect) {
   
    case 0  : {
                // RGBLoop - no parameters
                RGBLoop();
                break;
              }

    case 1  : {
                // FadeInOut - Color (red, green. blue)
                FadeInOut(0xff, 0x00, 0x00); // red
                FadeInOut(0xff, 0xff, 0xff); // white
                FadeInOut(0x00, 0x00, 0xff); // blue
                break;
              }
             
    case 2  : {
                // Strobe - Color (red, green, blue), number of flashes, flash speed, end pause
                Strobe(0xff, 0xff, 0xff, 10, 50, 1000);
                break;
              }

    case 3  : {
                // HalloweenEyes - Color (red, green, blue), Size of eye, space between eyes, fade (true/false), steps, fade delay, end pause
                HalloweenEyes(0xff, 0x00, 0x00,
                              1, 4,
                              true, random(5,50), random(50,150),
                              random(1000, 10000));
                HalloweenEyes(0xff, 0x00, 0x00,
                              1, 4,
                              true, random(5,50), random(50,150),
                              random(1000, 10000));
                break;
              }
             
    case 4  : {
                // CylonBounce - Color (red, green, blue), eye size, speed delay, end pause
                CylonBounce(0xff, 0x00, 0x00, 4, 10, 50);
                break;
              }
             
    case 5  : {
                // NewKITT - Color (red, green, blue), eye size, speed delay, end pause
                NewKITT(0xff, 0x00, 0x00, 8, 10, 50);
                break;
              }
             
    case 6  : {
                // Twinkle - Color (red, green, blue), count, speed delay, only one twinkle (true/false)
                Twinkle(0xff, 0x00, 0x00, 10, 100, false);
                break;
              }
             
    case 7  : {
                // TwinkleRandom - twinkle count, speed delay, only one (true/false)
                TwinkleRandom(20, 100, false);
                break;
              }
             
    case 8  : {
                // Sparkle - Color (red, green, blue), speed delay
                Sparkle(0xff, 0xff, 0xff, 0);
                break;
              }
               
    case 9  : {
                // SnowSparkle - Color (red, green, blue), sparkle delay, speed delay
                SnowSparkle(0x10, 0x10, 0x10, 20, random(100,1000));
                break;
              }
             
    case 10 : {
                // Running Lights - Color (red, green, blue), wave dealy
                RunningLights(0xff,0x00,0x00, 50);  // red
                RunningLights(0xff,0xff,0xff, 50);  // white
                RunningLights(0x00,0x00,0xff, 50);  // blue
                break;
              }
             
    case 11 : {
                // colorWipe - Color (red, green, blue), speed delay
                colorWipe(0x00,0xff,0x00, 50);
                colorWipe(0x00,0x00,0x00, 50);
                break;
              }

    case 12 : {
                // rainbowCycle - speed delay
                rainbowCycle(20);
                break;
              }

    case 13 : {
                // theatherChase - Color (red, green, blue), speed delay
                theaterChase(0xff,0,0,50);
                break;
              }

    case 14 : {
                // theaterChaseRainbow - Speed delay
                theaterChaseRainbow(50);
                break;
              }

    case 15 : {
                // Fire - Cooling rate, Sparking rate, speed delay
                Fire(55,120,15);
                break;
              }


              // simple bouncingBalls not included, since BouncingColoredBalls can perform this as well as shown below
              // BouncingColoredBalls - Number of balls, color (red, green, blue) array, continuous
              // CAUTION: If set to continuous then this effect will never stop!!!
             
    case 16 : {
                // mimic BouncingBalls
                byte onecolor[1][3] = { {0xff, 0x00, 0x00} };
                BouncingColoredBalls(1, onecolor, false);
                break;
              }

    case 17 : {
                // multiple colored balls
                byte colors[3][3] = { {0xff, 0x00, 0x00},
                                      {0xff, 0xff, 0xff},
                                      {0x00, 0x00, 0xff} };
                BouncingColoredBalls(3, colors, false);
                break;
              }

    case 18 : {
                // meteorRain - Color (red, green, blue), meteor size, trail decay, random trail decay (true/false), speed delay
                meteorRain(0xff,0xff,0xff,10, 64, true, 30);
                break;
              }
  }
}

void changeEffect() {
  if (digitalRead (BUTTON) == HIGH) {
    selectedEffect++;
    EEPROM.put(0, selectedEffect);
    asm volatile ("  jmp 0");
  }
}


// *************************
// ** LEDEffect Functions **
// *************************

void RGBLoop(){
  for(int j = 0; j < 3; j++ ) {
    // Fade IN
    for(int k = 0; k < 256; k++) {
      switch(j) {
        case 0: setAll(k,0,0); break;
        case 1: setAll(0,k,0); break;
        case 2: setAll(0,0,k); break;
      }
      showStrip();
      delay(3);
    }
    // Fade OUT
    for(int k = 255; k >= 0; k--) {
      switch(j) {
        case 0: setAll(k,0,0); break;
        case 1: setAll(0,k,0); break;
        case 2: setAll(0,0,k); break;
      }
      showStrip();
      delay(3);
    }
  }
}

void FadeInOut(byte red, byte green, byte blue){
  float r, g, b;
     
  for(int k = 0; k < 256; k=k+1) {
    r = (k/256.0)*red;
    g = (k/256.0)*green;
    b = (k/256.0)*blue;
    setAll(r,g,b);
    showStrip();
  }
     
  for(int k = 255; k >= 0; k=k-2) {
    r = (k/256.0)*red;
    g = (k/256.0)*green;
    b = (k/256.0)*blue;
    setAll(r,g,b);
    showStrip();
  }
}

void Strobe(byte red, byte green, byte blue, int StrobeCount, int FlashDelay, int EndPause){
  for(int j = 0; j < StrobeCount; j++) {
    setAll(red,green,blue);
    showStrip();
    delay(FlashDelay);
    setAll(0,0,0);
    showStrip();
    delay(FlashDelay);
  }
 
 delay(EndPause);
}

void HalloweenEyes(byte red, byte green, byte blue,
                   int EyeWidth, int EyeSpace,
                   boolean Fade, int Steps, int FadeDelay,
                   int EndPause){
  randomSeed(analogRead(0));
 
  int i;
  int StartPoint  = random( 0, NUM_LEDS - (2*EyeWidth) - EyeSpace );
  int Start2ndEye = StartPoint + EyeWidth + EyeSpace;
 
  for(i = 0; i < EyeWidth; i++) {
    setPixel(StartPoint + i, red, green, blue);
    setPixel(Start2ndEye + i, red, green, blue);
  }
 
  showStrip();
 
  if(Fade==true) {
    float r, g, b;
 
    for(int j = Steps; j >= 0; j--) {
      r = j*(red/Steps);
      g = j*(green/Steps);
      b = j*(blue/Steps);
     
      for(i = 0; i < EyeWidth; i++) {
        setPixel(StartPoint + i, r, g, b);
        setPixel(Start2ndEye + i, r, g, b);
      }
     
      showStrip();
      delay(FadeDelay);
    }
  }
 
  setAll(0,0,0); // Set all black
 
  delay(EndPause);
}

void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay){

  for(int i = 0; i < NUM_LEDS-EyeSize-2; i++) {
    setAll(0,0,0);
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
    showStrip();
    delay(SpeedDelay);
  }

  delay(ReturnDelay);

  for(int i = NUM_LEDS-EyeSize-2; i > 0; i--) {
    setAll(0,0,0);
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
    showStrip();
    delay(SpeedDelay);
  }
 
  delay(ReturnDelay);
}

void NewKITT(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay){
  RightToLeft(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  LeftToRight(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  OutsideToCenter(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  CenterToOutside(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  LeftToRight(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  RightToLeft(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  OutsideToCenter(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  CenterToOutside(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
}

// used by NewKITT
void CenterToOutside(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay) {
  for(int i =((NUM_LEDS-EyeSize)/2); i>=0; i--) {
    setAll(0,0,0);
   
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
   
    setPixel(NUM_LEDS-i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(NUM_LEDS-i-j, red, green, blue);
    }
    setPixel(NUM_LEDS-i-EyeSize-1, red/10, green/10, blue/10);
   
    showStrip();
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
}

// used by NewKITT
void OutsideToCenter(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay) {
  for(int i = 0; i<=((NUM_LEDS-EyeSize)/2); i++) {
    setAll(0,0,0);
   
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
   
    setPixel(NUM_LEDS-i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(NUM_LEDS-i-j, red, green, blue);
    }
    setPixel(NUM_LEDS-i-EyeSize-1, red/10, green/10, blue/10);
   
    showStrip();
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
}

// used by NewKITT
void LeftToRight(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay) {
  for(int i = 0; i < NUM_LEDS-EyeSize-2; i++) {
    setAll(0,0,0);
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
    showStrip();
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
}

// used by NewKITT
void RightToLeft(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay) {
  for(int i = NUM_LEDS-EyeSize-2; i > 0; i--) {
    setAll(0,0,0);
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
    showStrip();
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
}

void Twinkle(byte red, byte green, byte blue, int Count, int SpeedDelay, boolean OnlyOne) {
  setAll(0,0,0);
 
  for (int i=0; i<Count; i++) {
     setPixel(random(NUM_LEDS),red,green,blue);
     showStrip();
     delay(SpeedDelay);
     if(OnlyOne) {
       setAll(0,0,0);
     }
   }
 
  delay(SpeedDelay);
}

void TwinkleRandom(int Count, int SpeedDelay, boolean OnlyOne) {
  setAll(0,0,0);
 
  for (int i=0; i<Count; i++) {
     setPixel(random(NUM_LEDS),random(0,255),random(0,255),random(0,255));
     showStrip();
     delay(SpeedDelay);
     if(OnlyOne) {
       setAll(0,0,0);
     }
   }
 
  delay(SpeedDelay);
}

void Sparkle(byte red, byte green, byte blue, int SpeedDelay) {
  int Pixel = random(NUM_LEDS);
  setPixel(Pixel,red,green,blue);
  showStrip();
  delay(SpeedDelay);
  setPixel(Pixel,0,0,0);
}

void SnowSparkle(byte red, byte green, byte blue, int SparkleDelay, int SpeedDelay) {
  setAll(red,green,blue);
 
  int Pixel = random(NUM_LEDS);
  setPixel(Pixel,0xff,0xff,0xff);
  showStrip();
  delay(SparkleDelay);
  setPixel(Pixel,red,green,blue);
  showStrip();
  delay(SpeedDelay);
}

void RunningLights(byte red, byte green, byte blue, int WaveDelay) {
  int Position=0;
 
  for(int i=0; i<NUM_LEDS*2; i++)
  {
      Position++; // = 0; //Position + Rate;
      for(int i=0; i<NUM_LEDS; i++) {
        // sine wave, 3 offset waves make a rainbow!
        //float level = sin(i+Position) * 127 + 128;
        //setPixel(i,level,0,0);
        //float level = sin(i+Position) * 127 + 128;
        setPixel(i,((sin(i+Position) * 127 + 128)/255)*red,
                   ((sin(i+Position) * 127 + 128)/255)*green,
                   ((sin(i+Position) * 127 + 128)/255)*blue);
      }
     
      showStrip();
      delay(WaveDelay);
  }
}

void colorWipe(byte red, byte green, byte blue, int SpeedDelay) {
  for(uint16_t i=0; i<NUM_LEDS; i++) {
      setPixel(i, red, green, blue);
      showStrip();
      delay(SpeedDelay);
  }
}

void rainbowCycle(int SpeedDelay) {
  byte *c;
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< NUM_LEDS; i++) {
      c=Wheel(((i * 256 / NUM_LEDS) + j) & 255);
      setPixel(i, *c, *(c+1), *(c+2));
    }
    showStrip();
    delay(SpeedDelay);
  }
}

// used by rainbowCycle and theaterChaseRainbow
byte * Wheel(byte WheelPos) {
  static byte c[3];
 
  if(WheelPos < 85) {
   c[0]=WheelPos * 3;
   c[1]=255 - WheelPos * 3;
   c[2]=0;
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   c[0]=255 - WheelPos * 3;
   c[1]=0;
   c[2]=WheelPos * 3;
  } else {
   WheelPos -= 170;
   c[0]=0;
   c[1]=WheelPos * 3;
   c[2]=255 - WheelPos * 3;
  }

  return c;
}

void theaterChase(byte red, byte green, byte blue, int SpeedDelay) {
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (int i=0; i < NUM_LEDS; i=i+3) {
        setPixel(i+q, red, green, blue);    //turn every third pixel on
      }
      showStrip();
     
      delay(SpeedDelay);
     
      for (int i=0; i < NUM_LEDS; i=i+3) {
        setPixel(i+q, 0,0,0);        //turn every third pixel off
      }
    }
  }
}

void theaterChaseRainbow(int SpeedDelay) {
  byte *c;
 
  for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
    for (int q=0; q < 3; q++) {
        for (int i=0; i < NUM_LEDS; i=i+3) {
          c = Wheel( (i+j) % 255);
          setPixel(i+q, *c, *(c+1), *(c+2));    //turn every third pixel on
        }
        showStrip();
       
        delay(SpeedDelay);
       
        for (int i=0; i < NUM_LEDS; i=i+3) {
          setPixel(i+q, 0,0,0);        //turn every third pixel off
        }
    }
  }
}

void Fire(int Cooling, int Sparking, int SpeedDelay) {
  static byte heat[NUM_LEDS];
  int cooldown;
 
  // Step 1.  Cool down every cell a little
  for( int i = 0; i < NUM_LEDS; i++) {
    cooldown = random(0, ((Cooling * 10) / NUM_LEDS) + 2);
   
    if(cooldown>heat[i]) {
      heat[i]=0;
    } else {
      heat[i]=heat[i]-cooldown;
    }
  }
 
  // Step 2.  Heat from each cell drifts 'up' and diffuses a little
  for( int k= NUM_LEDS - 1; k >= 2; k--) {
    heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
  }
   
  // Step 3.  Randomly ignite new 'sparks' near the bottom
  if( random(255) < Sparking ) {
    int y = random(7);
    heat[y] = heat[y] + random(160,255);
    //heat[y] = random(160,255);
  }

  // Step 4.  Convert heat to LED colors
  for( int j = 0; j < NUM_LEDS; j++) {
    setPixelHeatColor(j, heat[j] );
  }

  showStrip();
  delay(SpeedDelay);
}

void setPixelHeatColor (int Pixel, byte temperature) {
  // Scale 'heat' down from 0-255 to 0-191
  byte t192 = round((temperature/255.0)*191);
 
  // calculate ramp up from
  byte heatramp = t192 & 0x3F; // 0..63
  heatramp <<= 2; // scale up to 0..252
 
  // figure out which third of the spectrum we're in:
  if( t192 > 0x80) {                     // hottest
    setPixel(Pixel, 255, 255, heatramp);
  } else if( t192 > 0x40 ) {             // middle
    setPixel(Pixel, 255, heatramp, 0);
  } else {                               // coolest
    setPixel(Pixel, heatramp, 0, 0);
  }
}

void BouncingColoredBalls(int BallCount, byte colors[][3], boolean continuous) {
  float Gravity = -9.81;
  int StartHeight = 1;
 
  float Height[BallCount];
  float ImpactVelocityStart = sqrt( -2 * Gravity * StartHeight );
  float ImpactVelocity[BallCount];
  float TimeSinceLastBounce[BallCount];
  int   Position[BallCount];
  long  ClockTimeSinceLastBounce[BallCount];
  float Dampening[BallCount];
  boolean ballBouncing[BallCount];
  boolean ballsStillBouncing = true;
 
  for (int i = 0 ; i < BallCount ; i++) {  
    ClockTimeSinceLastBounce[i] = millis();
    Height[i] = StartHeight;
    Position[i] = 0;
    ImpactVelocity[i] = ImpactVelocityStart;
    TimeSinceLastBounce[i] = 0;
    Dampening[i] = 0.90 - float(i)/pow(BallCount,2);
    ballBouncing[i]=true;
  }

  while (ballsStillBouncing) {
    for (int i = 0 ; i < BallCount ; i++) {
      TimeSinceLastBounce[i] =  millis() - ClockTimeSinceLastBounce[i];
      Height[i] = 0.5 * Gravity * pow( TimeSinceLastBounce[i]/1000 , 2.0 ) + ImpactVelocity[i] * TimeSinceLastBounce[i]/1000;
 
      if ( Height[i] < 0 ) {                      
        Height[i] = 0;
        ImpactVelocity[i] = Dampening[i] * ImpactVelocity[i];
        ClockTimeSinceLastBounce[i] = millis();
 
        if ( ImpactVelocity[i] < 0.01 ) {
          if (continuous) {
            ImpactVelocity[i] = ImpactVelocityStart;
          } else {
            ballBouncing[i]=false;
          }
        }
      }
      Position[i] = round( Height[i] * (NUM_LEDS - 1) / StartHeight);
    }

    ballsStillBouncing = false; // assume no balls bouncing
    for (int i = 0 ; i < BallCount ; i++) {
      setPixel(Position[i],colors[i][0],colors[i][1],colors[i][2]);
      if ( ballBouncing[i] ) {
        ballsStillBouncing = true;
      }
    }
   
    showStrip();
    setAll(0,0,0);
  }
}

void meteorRain(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {  
  setAll(0,0,0);
 
  for(int i = 0; i < NUM_LEDS+NUM_LEDS; i++) {
   
   
    // fade brightness all LEDs one step
    for(int j=0; j<NUM_LEDS; j++) {
      if( (!meteorRandomDecay) || (random(10)>5) ) {
        fadeToBlack(j, meteorTrailDecay );        
      }
    }
   
    // draw meteor
    for(int j = 0; j < meteorSize; j++) {
      if( ( i-j <NUM_LEDS) && (i-j>=0) ) {
        setPixel(i-j, red, green, blue);
      }
    }
   
    showStrip();
    delay(SpeedDelay);
  }
}

// used by meteorrain
void fadeToBlack(int ledNo, byte fadeValue) {
 #ifdef ADAFRUIT_NEOPIXEL_H
    // NeoPixel
    uint32_t oldColor;
    uint8_t r, g, b;
    int value;
   
    oldColor = strip.getPixelColor(ledNo);
    r = (oldColor & 0x00ff0000UL) >> 16;
    g = (oldColor & 0x0000ff00UL) >> 8;
    b = (oldColor & 0x000000ffUL);

    r=(r<=10)? 0 : (int) r-(r*fadeValue/256);
    g=(g<=10)? 0 : (int) g-(g*fadeValue/256);
    b=(b<=10)? 0 : (int) b-(b*fadeValue/256);
   
    strip.setPixelColor(ledNo, r,g,b);
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   leds[ledNo].fadeToBlackBy( fadeValue );
 #endif  
}

// *** REPLACE TO HERE ***



// ***************************************
// ** FastLed/NeoPixel Common Functions **
// ***************************************

// Apply LED color changes
void showStrip() {
 #ifdef ADAFRUIT_NEOPIXEL_H
   // NeoPixel
   strip.show();
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   FastLED.show();
 #endif
}

// Set a LED color (not yet visible)
void setPixel(int Pixel, byte red, byte green, byte blue) {
 #ifdef ADAFRUIT_NEOPIXEL_H
   // NeoPixel
   strip.setPixelColor(Pixel, strip.Color(red, green, blue));
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   leds[Pixel].r = red;
   leds[Pixel].g = green;
   leds[Pixel].b = blue;
 #endif
}

// Set all LEDs to a given color and apply it (visible)
void setAll(byte red, byte green, byte blue) {
  for(int i = 0; i < NUM_LEDS; i++ ) {
    setPixel(i, red, green, blue);
  }
  showStrip();
}

NeoPixel


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
#include <Adafruit_NeoPixel.h>
#include <EEPROM.h>

#define NUM_LEDS 60
#define PIN 5
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

#define BUTTON 2
byte selectedEffect=0;

void setup()
{
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  digitalWrite (BUTTON, HIGH);  // internal pull-up resistor
  attachInterrupt (digitalPinToInterrupt (BUTTON), changeEffect, CHANGE); // pressed
}

// *** REPLACE FROM HERE ***
void loop() {
  EEPROM.get(0,selectedEffect);
 
  if(selectedEffect>18) {
    selectedEffect=0;
    EEPROM.put(0,0);
  }
 
  switch(selectedEffect) {
   
    case 0  : {
                // RGBLoop - no parameters
                RGBLoop();
                break;
              }

    case 1  : {
                // FadeInOut - Color (red, green. blue)
                FadeInOut(0xff, 0x00, 0x00); // red
                FadeInOut(0xff, 0xff, 0xff); // white
                FadeInOut(0x00, 0x00, 0xff); // blue
                break;
              }
             
    case 2  : {
                // Strobe - Color (red, green, blue), number of flashes, flash speed, end pause
                Strobe(0xff, 0xff, 0xff, 10, 50, 1000);
                break;
              }

    case 3  : {
                // HalloweenEyes - Color (red, green, blue), Size of eye, space between eyes, fade (true/false), steps, fade delay, end pause
                HalloweenEyes(0xff, 0x00, 0x00,
                              1, 4,
                              true, random(5,50), random(50,150),
                              random(1000, 10000));
                HalloweenEyes(0xff, 0x00, 0x00,
                              1, 4,
                              true, random(5,50), random(50,150),
                              random(1000, 10000));
                break;
              }
             
    case 4  : {
                // CylonBounce - Color (red, green, blue), eye size, speed delay, end pause
                CylonBounce(0xff, 0x00, 0x00, 4, 10, 50);
                break;
              }
             
    case 5  : {
                // NewKITT - Color (red, green, blue), eye size, speed delay, end pause
                NewKITT(0xff, 0x00, 0x00, 8, 10, 50);
                break;
              }
             
    case 6  : {
                // Twinkle - Color (red, green, blue), count, speed delay, only one twinkle (true/false)
                Twinkle(0xff, 0x00, 0x00, 10, 100, false);
                break;
              }
             
    case 7  : {
                // TwinkleRandom - twinkle count, speed delay, only one (true/false)
                TwinkleRandom(20, 100, false);
                break;
              }
             
    case 8  : {
                // Sparkle - Color (red, green, blue), speed delay
                Sparkle(0xff, 0xff, 0xff, 0);
                break;
              }
               
    case 9  : {
                // SnowSparkle - Color (red, green, blue), sparkle delay, speed delay
                SnowSparkle(0x10, 0x10, 0x10, 20, random(100,1000));
                break;
              }
             
    case 10 : {
                // Running Lights - Color (red, green, blue), wave dealy
                RunningLights(0xff,0x00,0x00, 50);  // red
                RunningLights(0xff,0xff,0xff, 50);  // white
                RunningLights(0x00,0x00,0xff, 50);  // blue
                break;
              }
             
    case 11 : {
                // colorWipe - Color (red, green, blue), speed delay
                colorWipe(0x00,0xff,0x00, 50);
                colorWipe(0x00,0x00,0x00, 50);
                break;
              }

    case 12 : {
                // rainbowCycle - speed delay
                rainbowCycle(20);
                break;
              }

    case 13 : {
                // theatherChase - Color (red, green, blue), speed delay
                theaterChase(0xff,0,0,50);
                break;
              }

    case 14 : {
                // theaterChaseRainbow - Speed delay
                theaterChaseRainbow(50);
                break;
              }

    case 15 : {
                // Fire - Cooling rate, Sparking rate, speed delay
                Fire(55,120,15);
                break;
              }


              // simple bouncingBalls not included, since BouncingColoredBalls can perform this as well as shown below
              // BouncingColoredBalls - Number of balls, color (red, green, blue) array, continuous
              // CAUTION: If set to continuous then this effect will never stop!!!
             
    case 16 : {
                // mimic BouncingBalls
                byte onecolor[1][3] = { {0xff, 0x00, 0x00} };
                BouncingColoredBalls(1, onecolor, false);
                break;
              }

    case 17 : {
                // multiple colored balls
                byte colors[3][3] = { {0xff, 0x00, 0x00},
                                      {0xff, 0xff, 0xff},
                                      {0x00, 0x00, 0xff} };
                BouncingColoredBalls(3, colors, false);
                break;
              }

    case 18 : {
                // meteorRain - Color (red, green, blue), meteor size, trail decay, random trail decay (true/false), speed delay
                meteorRain(0xff,0xff,0xff,10, 64, true, 30);
                break;
              }
  }
}

void changeEffect() {
  if (digitalRead (BUTTON) == HIGH) {
    selectedEffect++;
    EEPROM.put(0, selectedEffect);
    asm volatile ("  jmp 0");
  }
}


// *************************
// ** LEDEffect Functions **
// *************************

void RGBLoop(){
  for(int j = 0; j < 3; j++ ) {
    // Fade IN
    for(int k = 0; k < 256; k++) {
      switch(j) {
        case 0: setAll(k,0,0); break;
        case 1: setAll(0,k,0); break;
        case 2: setAll(0,0,k); break;
      }
      showStrip();
      delay(3);
    }
    // Fade OUT
    for(int k = 255; k >= 0; k--) {
      switch(j) {
        case 0: setAll(k,0,0); break;
        case 1: setAll(0,k,0); break;
        case 2: setAll(0,0,k); break;
      }
      showStrip();
      delay(3);
    }
  }
}

void FadeInOut(byte red, byte green, byte blue){
  float r, g, b;
     
  for(int k = 0; k < 256; k=k+1) {
    r = (k/256.0)*red;
    g = (k/256.0)*green;
    b = (k/256.0)*blue;
    setAll(r,g,b);
    showStrip();
  }
     
  for(int k = 255; k >= 0; k=k-2) {
    r = (k/256.0)*red;
    g = (k/256.0)*green;
    b = (k/256.0)*blue;
    setAll(r,g,b);
    showStrip();
  }
}

void Strobe(byte red, byte green, byte blue, int StrobeCount, int FlashDelay, int EndPause){
  for(int j = 0; j < StrobeCount; j++) {
    setAll(red,green,blue);
    showStrip();
    delay(FlashDelay);
    setAll(0,0,0);
    showStrip();
    delay(FlashDelay);
  }
 
 delay(EndPause);
}

void HalloweenEyes(byte red, byte green, byte blue,
                   int EyeWidth, int EyeSpace,
                   boolean Fade, int Steps, int FadeDelay,
                   int EndPause){
  randomSeed(analogRead(0));
 
  int i;
  int StartPoint  = random( 0, NUM_LEDS - (2*EyeWidth) - EyeSpace );
  int Start2ndEye = StartPoint + EyeWidth + EyeSpace;
 
  for(i = 0; i < EyeWidth; i++) {
    setPixel(StartPoint + i, red, green, blue);
    setPixel(Start2ndEye + i, red, green, blue);
  }
 
  showStrip();
 
  if(Fade==true) {
    float r, g, b;
 
    for(int j = Steps; j >= 0; j--) {
      r = j*(red/Steps);
      g = j*(green/Steps);
      b = j*(blue/Steps);
     
      for(i = 0; i < EyeWidth; i++) {
        setPixel(StartPoint + i, r, g, b);
        setPixel(Start2ndEye + i, r, g, b);
      }
     
      showStrip();
      delay(FadeDelay);
    }
  }
 
  setAll(0,0,0); // Set all black
 
  delay(EndPause);
}

void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay){

  for(int i = 0; i < NUM_LEDS-EyeSize-2; i++) {
    setAll(0,0,0);
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
    showStrip();
    delay(SpeedDelay);
  }

  delay(ReturnDelay);

  for(int i = NUM_LEDS-EyeSize-2; i > 0; i--) {
    setAll(0,0,0);
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
    showStrip();
    delay(SpeedDelay);
  }
 
  delay(ReturnDelay);
}

void NewKITT(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay){
  RightToLeft(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  LeftToRight(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  OutsideToCenter(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  CenterToOutside(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  LeftToRight(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  RightToLeft(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  OutsideToCenter(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
  CenterToOutside(red, green, blue, EyeSize, SpeedDelay, ReturnDelay);
}

// used by NewKITT
void CenterToOutside(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay) {
  for(int i =((NUM_LEDS-EyeSize)/2); i>=0; i--) {
    setAll(0,0,0);
   
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
   
    setPixel(NUM_LEDS-i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(NUM_LEDS-i-j, red, green, blue);
    }
    setPixel(NUM_LEDS-i-EyeSize-1, red/10, green/10, blue/10);
   
    showStrip();
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
}

// used by NewKITT
void OutsideToCenter(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay) {
  for(int i = 0; i<=((NUM_LEDS-EyeSize)/2); i++) {
    setAll(0,0,0);
   
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
   
    setPixel(NUM_LEDS-i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(NUM_LEDS-i-j, red, green, blue);
    }
    setPixel(NUM_LEDS-i-EyeSize-1, red/10, green/10, blue/10);
   
    showStrip();
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
}

// used by NewKITT
void LeftToRight(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay) {
  for(int i = 0; i < NUM_LEDS-EyeSize-2; i++) {
    setAll(0,0,0);
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
    showStrip();
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
}

// used by NewKITT
void RightToLeft(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay) {
  for(int i = NUM_LEDS-EyeSize-2; i > 0; i--) {
    setAll(0,0,0);
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
    showStrip();
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
}

void Twinkle(byte red, byte green, byte blue, int Count, int SpeedDelay, boolean OnlyOne) {
  setAll(0,0,0);
 
  for (int i=0; i<Count; i++) {
     setPixel(random(NUM_LEDS),red,green,blue);
     showStrip();
     delay(SpeedDelay);
     if(OnlyOne) {
       setAll(0,0,0);
     }
   }
 
  delay(SpeedDelay);
}

void TwinkleRandom(int Count, int SpeedDelay, boolean OnlyOne) {
  setAll(0,0,0);
 
  for (int i=0; i<Count; i++) {
     setPixel(random(NUM_LEDS),random(0,255),random(0,255),random(0,255));
     showStrip();
     delay(SpeedDelay);
     if(OnlyOne) {
       setAll(0,0,0);
     }
   }
 
  delay(SpeedDelay);
}

void Sparkle(byte red, byte green, byte blue, int SpeedDelay) {
  int Pixel = random(NUM_LEDS);
  setPixel(Pixel,red,green,blue);
  showStrip();
  delay(SpeedDelay);
  setPixel(Pixel,0,0,0);
}

void SnowSparkle(byte red, byte green, byte blue, int SparkleDelay, int SpeedDelay) {
  setAll(red,green,blue);
 
  int Pixel = random(NUM_LEDS);
  setPixel(Pixel,0xff,0xff,0xff);
  showStrip();
  delay(SparkleDelay);
  setPixel(Pixel,red,green,blue);
  showStrip();
  delay(SpeedDelay);
}

void RunningLights(byte red, byte green, byte blue, int WaveDelay) {
  int Position=0;
 
  for(int i=0; i<NUM_LEDS*2; i++)
  {
      Position++; // = 0; //Position + Rate;
      for(int i=0; i<NUM_LEDS; i++) {
        // sine wave, 3 offset waves make a rainbow!
        //float level = sin(i+Position) * 127 + 128;
        //setPixel(i,level,0,0);
        //float level = sin(i+Position) * 127 + 128;
        setPixel(i,((sin(i+Position) * 127 + 128)/255)*red,
                   ((sin(i+Position) * 127 + 128)/255)*green,
                   ((sin(i+Position) * 127 + 128)/255)*blue);
      }
     
      showStrip();
      delay(WaveDelay);
  }
}

void colorWipe(byte red, byte green, byte blue, int SpeedDelay) {
  for(uint16_t i=0; i<NUM_LEDS; i++) {
      setPixel(i, red, green, blue);
      showStrip();
      delay(SpeedDelay);
  }
}

void rainbowCycle(int SpeedDelay) {
  byte *c;
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< NUM_LEDS; i++) {
      c=Wheel(((i * 256 / NUM_LEDS) + j) & 255);
      setPixel(i, *c, *(c+1), *(c+2));
    }
    showStrip();
    delay(SpeedDelay);
  }
}

// used by rainbowCycle and theaterChaseRainbow
byte * Wheel(byte WheelPos) {
  static byte c[3];
 
  if(WheelPos < 85) {
   c[0]=WheelPos * 3;
   c[1]=255 - WheelPos * 3;
   c[2]=0;
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   c[0]=255 - WheelPos * 3;
   c[1]=0;
   c[2]=WheelPos * 3;
  } else {
   WheelPos -= 170;
   c[0]=0;
   c[1]=WheelPos * 3;
   c[2]=255 - WheelPos * 3;
  }

  return c;
}

void theaterChase(byte red, byte green, byte blue, int SpeedDelay) {
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (int i=0; i < NUM_LEDS; i=i+3) {
        setPixel(i+q, red, green, blue);    //turn every third pixel on
      }
      showStrip();
     
      delay(SpeedDelay);
     
      for (int i=0; i < NUM_LEDS; i=i+3) {
        setPixel(i+q, 0,0,0);        //turn every third pixel off
      }
    }
  }
}

void theaterChaseRainbow(int SpeedDelay) {
  byte *c;
 
  for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
    for (int q=0; q < 3; q++) {
        for (int i=0; i < NUM_LEDS; i=i+3) {
          c = Wheel( (i+j) % 255);
          setPixel(i+q, *c, *(c+1), *(c+2));    //turn every third pixel on
        }
        showStrip();
       
        delay(SpeedDelay);
       
        for (int i=0; i < NUM_LEDS; i=i+3) {
          setPixel(i+q, 0,0,0);        //turn every third pixel off
        }
    }
  }
}

void Fire(int Cooling, int Sparking, int SpeedDelay) {
  static byte heat[NUM_LEDS];
  int cooldown;
 
  // Step 1.  Cool down every cell a little
  for( int i = 0; i < NUM_LEDS; i++) {
    cooldown = random(0, ((Cooling * 10) / NUM_LEDS) + 2);
   
    if(cooldown>heat[i]) {
      heat[i]=0;
    } else {
      heat[i]=heat[i]-cooldown;
    }
  }
 
  // Step 2.  Heat from each cell drifts 'up' and diffuses a little
  for( int k= NUM_LEDS - 1; k >= 2; k--) {
    heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
  }
   
  // Step 3.  Randomly ignite new 'sparks' near the bottom
  if( random(255) < Sparking ) {
    int y = random(7);
    heat[y] = heat[y] + random(160,255);
    //heat[y] = random(160,255);
  }

  // Step 4.  Convert heat to LED colors
  for( int j = 0; j < NUM_LEDS; j++) {
    setPixelHeatColor(j, heat[j] );
  }

  showStrip();
  delay(SpeedDelay);
}

void setPixelHeatColor (int Pixel, byte temperature) {
  // Scale 'heat' down from 0-255 to 0-191
  byte t192 = round((temperature/255.0)*191);
 
  // calculate ramp up from
  byte heatramp = t192 & 0x3F; // 0..63
  heatramp <<= 2; // scale up to 0..252
 
  // figure out which third of the spectrum we're in:
  if( t192 > 0x80) {                     // hottest
    setPixel(Pixel, 255, 255, heatramp);
  } else if( t192 > 0x40 ) {             // middle
    setPixel(Pixel, 255, heatramp, 0);
  } else {                               // coolest
    setPixel(Pixel, heatramp, 0, 0);
  }
}

void BouncingColoredBalls(int BallCount, byte colors[][3], boolean continuous) {
  float Gravity = -9.81;
  int StartHeight = 1;
 
  float Height[BallCount];
  float ImpactVelocityStart = sqrt( -2 * Gravity * StartHeight );
  float ImpactVelocity[BallCount];
  float TimeSinceLastBounce[BallCount];
  int   Position[BallCount];
  long  ClockTimeSinceLastBounce[BallCount];
  float Dampening[BallCount];
  boolean ballBouncing[BallCount];
  boolean ballsStillBouncing = true;
 
  for (int i = 0 ; i < BallCount ; i++) {  
    ClockTimeSinceLastBounce[i] = millis();
    Height[i] = StartHeight;
    Position[i] = 0;
    ImpactVelocity[i] = ImpactVelocityStart;
    TimeSinceLastBounce[i] = 0;
    Dampening[i] = 0.90 - float(i)/pow(BallCount,2);
    ballBouncing[i]=true;
  }

  while (ballsStillBouncing) {
    for (int i = 0 ; i < BallCount ; i++) {
      TimeSinceLastBounce[i] =  millis() - ClockTimeSinceLastBounce[i];
      Height[i] = 0.5 * Gravity * pow( TimeSinceLastBounce[i]/1000 , 2.0 ) + ImpactVelocity[i] * TimeSinceLastBounce[i]/1000;
 
      if ( Height[i] < 0 ) {                      
        Height[i] = 0;
        ImpactVelocity[i] = Dampening[i] * ImpactVelocity[i];
        ClockTimeSinceLastBounce[i] = millis();
 
        if ( ImpactVelocity[i] < 0.01 ) {
          if (continuous) {
            ImpactVelocity[i] = ImpactVelocityStart;
          } else {
            ballBouncing[i]=false;
          }
        }
      }
      Position[i] = round( Height[i] * (NUM_LEDS - 1) / StartHeight);
    }

    ballsStillBouncing = false; // assume no balls bouncing
    for (int i = 0 ; i < BallCount ; i++) {
      setPixel(Position[i],colors[i][0],colors[i][1],colors[i][2]);
      if ( ballBouncing[i] ) {
        ballsStillBouncing = true;
      }
    }
   
    showStrip();
    setAll(0,0,0);
  }
}

void meteorRain(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {  
  setAll(0,0,0);
 
  for(int i = 0; i < NUM_LEDS+NUM_LEDS; i++) {
   
   
    // fade brightness all LEDs one step
    for(int j=0; j<NUM_LEDS; j++) {
      if( (!meteorRandomDecay) || (random(10)>5) ) {
        fadeToBlack(j, meteorTrailDecay );        
      }
    }
   
    // draw meteor
    for(int j = 0; j < meteorSize; j++) {
      if( ( i-j <NUM_LEDS) && (i-j>=0) ) {
        setPixel(i-j, red, green, blue);
      }
    }
   
    showStrip();
    delay(SpeedDelay);
  }
}

// used by meteorrain
void fadeToBlack(int ledNo, byte fadeValue) {
 #ifdef ADAFRUIT_NEOPIXEL_H
    // NeoPixel
    uint32_t oldColor;
    uint8_t r, g, b;
    int value;
   
    oldColor = strip.getPixelColor(ledNo);
    r = (oldColor & 0x00ff0000UL) >> 16;
    g = (oldColor & 0x0000ff00UL) >> 8;
    b = (oldColor & 0x000000ffUL);

    r=(r<=10)? 0 : (int) r-(r*fadeValue/256);
    g=(g<=10)? 0 : (int) g-(g*fadeValue/256);
    b=(b<=10)? 0 : (int) b-(b*fadeValue/256);
   
    strip.setPixelColor(ledNo, r,g,b);
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   leds[ledNo].fadeToBlackBy( fadeValue );
 #endif  
}

// *** REPLACE TO HERE ***



// ***************************************
// ** FastLed/NeoPixel Common Functions **
// ***************************************

// Apply LED color changes
void showStrip() {
 #ifdef ADAFRUIT_NEOPIXEL_H
   // NeoPixel
   strip.show();
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   FastLED.show();
 #endif
}

// Set a LED color (not yet visible)
void setPixel(int Pixel, byte red, byte green, byte blue) {
 #ifdef ADAFRUIT_NEOPIXEL_H
   // NeoPixel
   strip.setPixelColor(Pixel, strip.Color(red, green, blue));
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   leds[Pixel].r = red;
   leds[Pixel].g = green;
   leds[Pixel].b = blue;
 #endif
}

// Set all LEDs to a given color and apply it (visible)
void setAll(byte red, byte green, byte blue) {
  for(int i = 0; i < NUM_LEDS; i++ ) {
    setPixel(i, red, green, blue);
  }
  showStrip();
}

 

Donation options


Donaties worden zeer gewaardeerd maar zijn echt niet verplicht. Donaties worden gebruikt om de web-hosting kosten te dekken, hard- of software aan te schaffen voor projecten die we hier bespreken, of zo nu en dan voor een pilsje of een kopje koffie!

Reacties


Er zijn 24 reacties welke je hieronder kunt lezen.
Je kunt jouw eigen opmerkingen plaatsen m.b.v. dit formulier, of een reactie op een bestaande opmerking plaatsen door op de "Beantwoorden" knop te klikken.

  • 2 feb, 2018 - 11:03 AM - Jan Opmerking Link

    Dank je wel voor de sketch, leer hier weer veel van als vrij nieuwe Arduino-FastLED gebruiker.

    Wat betreft de types LED-strips: ik heb een 5 meter WS2811 strip 12 volt, met 60 leds per meter. (per 3 leds op een rij zit er een controller).

    Je zou zeggen totaal aantal leds = 5×60 = 300, in te vullen in de setup van de Arduino. 

    De Arduino gaat hier blijkbaar anders mee om: bijvoorbeeld met een waarde van 100 wordt al de gehele strip aangestuurd.

    Het lijkt of de Arduino het aantal controllers “telt” ipv de daadwerkelijk aanwezige individuele leds. In de Fastled voorbeelden zie je dit ook duidelijk, alles gaat in blokjes van 3 op elkaar volgende brandende leds. Eén led afzondelijk laten branden lukt mij niet.

    Is dit normaal voor deze strip, ( is dit weer één van de vele varianten LED-strips?), en kan ik dit op een andere manier wel individueel per LED aansturen.

    Beantwoorden

    Jan

    • 16 feb, 2018 - 5:06 PM - hans - Auteur: Opmerking Link

      De Arduino telt inderdaad 1 controller (met rood, groen en blauwe led) als “1 LED”. Beetje verwarrend inderdaad.
      De gedachte is dat de 3 LED met controller verantwoordelijk zijn voor 1 kleur puntje.

      Dit is dus normaal 

      Beantwoorden

      hans

  • 14 apr, 2018 - 11:51 PM - Ruben Opmerking Link

    Beste Hans,

    Allereerst super deze tutorials, ik heb je sketch toegepast op een ledstrip van 5 meter gewikkeld om een hoge hoed.

    Alles draait op een powerbank maar sommige sketches vragen teveel stroom om dit even vol te houden.

    Ik krijg het niet voor elkaar om enkele van deze effecten uit de sketch te halen, en dan met name de sketched waarbij alle leds worden aangesproken.

    Zou je me kunnen helpen om deze eruit te kunnen halen? en als ik nu de boel opstart begint hij direct met vol rood, is het ook mogelijk dat hij blanco opstart en dat de eerste sketch pas geactiveerd word na de eerste druk op de switch??

    de sparkle’s en running lights etc. werken echt fantastisch om de hoed heen, dit zijn super effecten voor dit doel.

    M.v.g. Ruben

    Beantwoorden

    Ruben

  • 15 apr, 2018 - 6:40 PM - Ruben Opmerking Link

    Allereerst, super mooie tutorials, echt top!

    ik heb deze sketch met effecten gebruikt voor mijn festival hoed, dit is een hoge hoed met 5 meter ledstrip omheen gewikkeld.

    Alles werkt prima en ik heb een paar effecten er tussenuit geknipt ivm teveel stroom afname gezien de hoed op een powerbank moet gaan draaien. Nu heb ik alleen nog 2 effecte erin zitten die best veel vermogen stroom vragen, bijna 3A totaal..

    Nu vind ik deze effecten (rainbow) wel mooi en dacht wat als ik de brightness laat zakken voor alleen deze effecten……maar ik kan niet uitvogelen hoe? Nog mooier zou zijn als deze 2 effecten niet alle leds aanspraken maar om en om….dat scheelt de helft aan consumptie.

    Groet,’

    Ruben

    Beantwoorden

    Ruben

    • 16 apr, 2018 - 2:23 PM - hans - Auteur: Opmerking Link

      Hoi Ruben,

      ik zal proberen beide vragen te beantwoorden.

      Effect verwijderen

      Een effect verwijderen doe je als volgt – hieronder haal ik bijvoorbeeld effect 15 (Fire) weg.

      Hieronder zie je de code die van belang is. Voor elk effect dat je verwijderd moet je de waarde “18” aanpassen anders telt het geheel te ver door.

      In loop():

        if(selectedEffect>17) {    <-- aantal effecten aanpassen

      Als je een effect weg haalt dan moet je ook de “case” nummering aanpassen.

      De case-blok van nummer 15 haal je dan weg, en de case’s die er opvolgen verlaag je met 1.

      void loop() { 
        EEPROM.get(0,selectedEffect); 
        
        if(selectedEffect>18) {    <-- aantal effecten aanpassen
          selectedEffect=0;
          EEPROM.put(0,0); 
        } 
        
        switch(selectedEffect) {
          
          case 0 : {
                      // RGBLoop - no parameters
                      RGBLoop();
                      break;
                    }
          case 1 : {
                      // FadeInOut - Color (red, green. blue)
                      FadeInOut(0xff, 0x00, 0x00); // red
                      FadeInOut(0xff, 0xff, 0xff); // white 
                      FadeInOut(0x00, 0x00, 0xff); // blue
                      break;
                    }
                    
          case 2 : {
                      // Strobe - Color (red, green, blue), number of flashes, flash speed, end pause
                      Strobe(0xff, 0xff, 0xff, 10, 50, 1000);
                      break;
                    }
         // ...
         // om ruimte te besparen wat regels weg gelaten
         // ...
          case 13 : {
                      // theatherChase - Color (red, green, blue), speed delay
                      theaterChase(0xff,0,0,50);
                      break;
                    }
          case 14 : {
                      // theaterChaseRainbow - Speed delay
                      theaterChaseRainbow(50);
                      break;
                    }
      //    case 15 : {   //  <-- dit blok halen we (in dit geval door ze als commentaar te markeren)
      //                // Fire - Cooling rate, Sparking rate, speed delay
      //                Fire(55,120,15);
      //                break;
      //              }

                    // simple bouncingBalls not included, since BouncingColoredBalls can perform this as well as shown below
                    // BouncingColoredBalls - Number of balls, color (red, green, blue) array, continuous
                    // CAUTION: If set to continuous then this effect will never stop!!! 
                    
          case 15 : {   // <-- dit was voorheen "16"  
                      // mimic BouncingBalls
                      byte onecolor[1][3] = { {0xff, 0x00, 0x00} };
                      BouncingColoredBalls(1, onecolor, false);
                      break;
                    }
          case 16 : {   // <-- dit was voorheen "17"
                      // multiple colored balls
                      byte colors[3][3] = { {0xff, 0x00, 0x00}, 
                                            {0xff, 0xff, 0xff}, 
                                            {0x00, 0x00, 0xff} };
                      BouncingColoredBalls(3, colors, false);
                      break;
                    }
          case 17 : {   // <-- dit was voorheen "18"
                      // meteorRain - Color (red, green, blue), meteor size, trail decay, random trail decay (true/false), speed delay 
                      meteorRain(0xff,0xff,0xff,10, 64, true, 30);
                      break;
                    }
        }
      }

      Effect dimmen

      Dit is wat lastiger, NeoPixel is daar niet zo erg goed in, maar als je FastLED gebruikt dan kun je het volgende in setup() plaatsen – hiervoor kun je de functie “setBrightness()” gebruiken.

      FastLED.setBrightness(<NUMMER>);

      Hierbij is <NUMMER> een getal tussen de 0 en 255. Ik heb dit zelf nog niet getest, maar voor zover ik de documentatie begrijp veranderd de helderheid naarmate dit nummer hoger wordt (quote: “a 0-255 value for how much to scale all leds before writing them out“), maar als ik code van anderen bekijk dan lijkt het erop dat “0” donker is en “255” maximale helderheid is. Dus even mee spelen.

      Je kunt dan bij iedere effect functie als eerste regel zoiets onderstaande regel gebruiken als maximale helderheid OK is.

      FastLED.setBrightness(255);

      en voor functies die minder helder moeten zijn (even mee spelen dus) bijvoorbeeld:

      FastLED.setBrightness(128);

      b.v.

      void Twinkle(byte red, byte green, byte blue, int Count, int SpeedDelay, boolean OnlyOne) {
        FastLED.setBrightness(255); // <-- gelijk aan het begin van een functie plaatsen
        setAll(0,0,0);
        
        for (int i=0; i<Count; i++) {
           setPixel(random(NUM_LEDS),red,green,blue);
           showStrip();
           delay(SpeedDelay);
           if(OnlyOne) { 
             setAll(0,0,0); 
           }
         }
        
        delay(SpeedDelay);
      }

      Hopelijk helpt dit je op weg … 

      Beantwoorden

      hans

      • 18 apr, 2018 - 3:21 PM - Ruben Opmerking Link

        Super Hans, bedankt voor je uitleg.

        Ik heb inmiddels een paar effecten verwijderd met succes en een paar vervangen door andere effecten.

        Nog een paar kleine wijzigingen en het is klaar.

        Beantwoorden

        Ruben

        • 18 apr, 2018 - 8:14 PM - hans - Auteur: Opmerking Link

          Mooi om te horen en graag gedaan! 

          Beantwoorden

          hans

          • 27 apr, 2018 - 7:44 PM - Ruben Opmerking Link

            Nou mijn hoed is klaar en zeer mooi geworden, doch ben ik weer zo’n type……ik heb nog een paar maand en zou nog best een paar uitbreidingen willen toevoegen. 

            Nu zoek ik me suf maar kan maar weinig leuke sketches vinden om toe te voegen, iemand nog ideeen?

            Ruben

          • 30 apr, 2018 - 12:48 PM - hans - Auteur: Opmerking Link

            Geweldig! Heb je ergens een video of afbeelding? Ben wel benieuwd!

            Wat uitbreidingen betreft; ik sta altijd open voor suggesties. Zo heb ik “Meteor Rain” later toegevoegd nadat iemand me een voorbeeld video van een effect liet zien. Een idee wat ik nog wil uitwerken in de toekomst is vlag kleuren laten zien en laten rond lopen. B.v. 3 blokken van elk drie leds en dan met b.v. de kleuren rood-wit-blauw blokken (als je Nederlander, Luxemburger of Amerikaan bent) of zwart-geel-rood (als je Belg bent) of zwart-rood-geel (voor de Duitsers onder ons) etc. Maar daar zal ik toch eerst tijd voor zien te vinden. Tussen verhuizen en inkomen proberen te genereren wordt dat op het moment een beetje lastig.

            hans

  • 3 jun, 2018 - 1:22 AM - dirkjan Opmerking Link

    Wow mooi uitgelegd en super gedaan.

    Kun je ook de button vervangen zodat het programma automatisch na, bijvoorbeeld 3 seconden naar het volgende effect gaat?

    Beantwoorden

    dirkjan

    • 4 jun, 2018 - 8:12 PM - hans - Auteur: Opmerking Link

      Hoi DrikJan,

      Als eerste: hartelijk dank voor het compliment! Top!

      ja dat kan zeker.

      Probeer dit eens; vervang het volgende stukje code

      void loop() { 
        EEPROM.get(0,selectedEffect); 
        
        if(selectedEffect>18) { 
          selectedEffect=0;
          EEPROM.put(0,0); 
        } 

      door

      void loop() { 
        selectedEffect++; // <--- I forgot the "t" in selectedEffect 
       
        if(selectedEffect>18) { 
          selectedEffect=0;
          delay(1000); // 1 second delay
        } 

      Hierdoor wordt na ieder effect een seconde gewacht en automatisch het volgende effect gestart.

      (zie ook de Engelstalige versie van dit artikel, bij deze vraag)

      Beantwoorden

      hans

  • 16 jul, 2018 - 1:51 PM - Ruben Smit Opmerking Link

    Ach ik zie nu pas je reactie Hans,

    Hier zie je de hoed in actie.

    https://www.youtube.com/watch?v=avPNozqgkB4

    Tot op heden is dit de enige sketch met multipe effects die ik heb kunnen vinden, ik zag ook dat je een vraag beantwoord had over de knap laten vervallen en de sketches achter elkaar door te laten lopen.

    Opzich lijkt me dat wel interessant maar volgens mij moet het ook als een optie met de knop kunnen. Dus zeg maar dat 1 case alles cases doorloopt.

    Tevens wil ik je wijzen op een ontzettend mooie sketch met 12 VU meters en 12 Stand-bypatterns, nu zijn die VU meters niet interessant voor deze skets maar die stand-by patterns zijn weer wel enorm mooi en hierin toe te passen, sommige zitten er zelfs al in zoals de stuiterballen. 

    https://www.youtube.com/watch?v=W8ye2O8ZQPM vanaf 1:50

    Beantwoorden

    Ruben Smit

    • 30 jul, 2018 - 11:11 AM - hans - Auteur: Opmerking Link

      Hi Ruben!

      Mooi gedaan!  (gelijk even “like” aangeklikt)

      Voor wat betreft de optie om een effect te kiezen OF door alle effecten heen te lopen, zou ik zelf een extra schakelaar gebruiken.
      Ik denk dan aan een tuimel schakelaar (die dus in een AAN or UIT positie blijft staan). In de code zou je dan zoiets kunnen doen:

      void loop() { 
        if (schakelaar=aan) {  // pseudo code
        selectedEffect++; // <--- I forgot the "t" in selectedEffect 
       }
        if(selectedEffect>18) { 
          selectedEffect=0;
          delay(1000); // 1 second delay
        } 

      Ik heb even m’n spullen niet bij de hand, vandaar dat de “if (schakelaar=aan) {” regel in pseudo code staat (dus geen echte code). De rest van de code blijft hetzelfde. Als de schakelaar aanstaat, dan worden de effecten geroteerd, zo niet dan gaat ieder effect door to de druk knop wordt ingedrukt. Hopelijk helpt je dit een beetje op weg.

      Voor wat betreft de VU Meter – erg mooi! Ik heb er zelf ook mee lopen spelen (maar dan niet zo mooi) en had zelf wat moeite met LINE-IN of Microfoon gebruiken. Nadeel van de microfoon is namelijk dat je stereo kwijt raakt (deels) en dat je omgevingsgeluiden oppikt (pratende mensen enzo). Nadeel van Line-in is dan weer dat je een versterkertje nodig hebt om het signaal op te poetsen naar een bruikbaar niveau. Wordt vervolgt, want ik wilde dit doen met het Fire effect   

      Beantwoorden

      hans

      • 24 aug, 2018 - 4:51 PM - Ruben Opmerking Link

        Misschien kunnen we elkaar hiermee helpen, ik heb inmiddels de vu meters zo uitgebreid dat deze zowel op line-in als mic kunnen functioneren.

        Zou je me evt. op fb kunnen toevoegen?

        https://www.facebook.com/Gmember78

        Beantwoorden

        Ruben

        • 26 aug, 2018 - 12:06 PM - hans - Auteur: Opmerking Link

          Hi Ruben,

          ik heb je proberen toe te voegen maar om de een of andere manier lukte dat dus niet. Heb je dus maar een berichtje gestuurd. 

          Erg gave hat trouwens!! (voor wie deze gave Hat wil zien: Facebook link

          Beantwoorden

          hans

  • 17 sep, 2018 - 3:56 PM - Pierre Opmerking Link

    Ik gebruik nog de vorige versie van AllLEDEffects.

    heb hier een selectie in gemaakt van 6 verschillende versies.

    Hier zit ik met één groot probleem, een versie die ik heb gemaakt, heb ik de effecten allemaal op wit gezet dus: (0xff, 0xff, 0xff); // white.

    Het probleem is bij  BouncingBalls(0xff,0xff,0xff, 3);.

    Eens dit effect als laatste aan de beurt, wil het niet meer stoppen om het verloop te hervatten van de effecten.

    Heb getest door het te verplaatsen tussen andere effecten, maar eens in de BouncingBalls blijft het dat doen.

    Is hier een oplossing voor?

    Beantwoorden

    Pierre

    • 20 sep, 2018 - 10:17 AM - hans - Auteur: Opmerking Link

      Hoi Pierre,

      ik neem aan dat je de code van het voorgaande artikel (link) bedoelt?
      In dit artikel (wat je nu leest) staat een stukje met de uitdagingen die ik aan moest gaan om de eindeloze effecten (zoals de ballen) kunt oplossen (link).

      De code komt er op neer dat we de while() loop aanpassen;

      void BouncingColoredBalls(int BallCount, byte colors[][3], boolean continuous) {
        float Gravity = -9.81;
        int StartHeight = 1;
        
        float Height[BallCount];
        float ImpactVelocityStart = sqrt( -2 * Gravity * StartHeight );
        float ImpactVelocity[BallCount];
        float TimeSinceLastBounce[BallCount];
        int Position[BallCount];
        long ClockTimeSinceLastBounce[BallCount];
        float Dampening[BallCount];
        boolean ballBouncing[BallCount];
        boolean ballsStillBouncing = true;
        
        for (int i = 0 ; i < BallCount ; i++) {   
          ClockTimeSinceLastBounce[i] = millis();
          Height[i] = StartHeight;
          Position[i] = 0; 
          ImpactVelocity[i] = ImpactVelocityStart;
          TimeSinceLastBounce[i] = 0;
          Dampening[i] = 0.90 - float(i)/pow(BallCount,2);
          ballBouncing[i]=true; 
        }
        while (ballsStillBouncing) {
          for (int i = 0 ; i < BallCount ; i++) {
            TimeSinceLastBounce[i] = millis() - ClockTimeSinceLastBounce[i];
            Height[i] = 0.5 * Gravity * pow( TimeSinceLastBounce[i]/1000 , 2.0 ) + ImpactVelocity[i] * TimeSinceLastBounce[i]/1000;
        
            if ( Height[i] < 0 ) {                      
              Height[i] = 0;
              ImpactVelocity[i] = Dampening[i] * ImpactVelocity[i];
              ClockTimeSinceLastBounce[i] = millis();
        
              if ( ImpactVelocity[i] < 0.01 ) {
                if (continuous) {
                  ImpactVelocity[i] = ImpactVelocityStart;
                } else {
                  ballBouncing[i]=false;
                }
              }
            }
            Position[i] = round( Height[i] * (NUM_LEDS - 1) / StartHeight);
          }
          ballsStillBouncing = false; // assume no balls bouncing
          for (int i = 0 ; i < BallCount ; i++) {
            setPixel(Position[i],colors[i][0],colors[i][1],colors[i][2]);
            if ( ballBouncing[i] ) {
              ballsStillBouncing = true;
            }
          }
          
          showStrip();
          setAll(0,0,0);
        }
      }

      De truuk zit ‘m in dit stukje;

      if ( ImpactVelocity[i] < 0.01 ) {
        if (continuous) {
            ImpactVelocity[i] = ImpactVelocityStart;
          } else {
            ballBouncing[i]=false;
          }
      }

      waarbij we kijken of een bal nog echt stuitert.

      Hopelijk helpt dit je op weg.

      Beantwoorden

      hans

  • 20 sep, 2018 - 3:14 PM - pierre Opmerking Link

    Dag Hans,

    Het is niet de huidige versie die ik bedoel, echt de vorige waar in de map alle effecten afzonderlijk staat maar ook een files met AllLEDEffects-NeoPixel.

    Dus hier is de 

    void loop() { 
      ...
      // BouncingBalls(0xff,0,0, 3);
      // byte colors[3][3] = { {0xff, 0,0}, 
      // {0xff, 0xff, 0xff}, 
      // {0 , 0 , 0xff} };
      // BouncingColoredBalls(3, colors);
    }

    Het gaat dus over BouncingBalls(0xff,0,0, 3); . Deze geeft dus 1 kleur ROOD en heb deze gewijzigd naar WIT. 

    Wat in deze files staat over deze zet ik hieronder, daar lukt het mij niet die wijziging te doen; programma geeft dan een fout.

    void BouncingBalls(byte red, byte green, byte blue, int BallCount) {
      float Gravity = -9.81;
      int StartHeight = 1;
      
      float Height[BallCount];
      float ImpactVelocityStart = sqrt( -2 * Gravity * StartHeight );
      float ImpactVelocity[BallCount];
      float TimeSinceLastBounce[BallCount];
      int Position[BallCount];
      long ClockTimeSinceLastBounce[BallCount];
      float Dampening[BallCount];
      
      for (int i = 0 ; i < BallCount ; i++) {   
        ClockTimeSinceLastBounce[i] = millis();
        Height[i] = StartHeight;
        Position[i] = 0; 
        ImpactVelocity[i] = ImpactVelocityStart;
        TimeSinceLastBounce[i] = 0;
        Dampening[i] = 0.90 - float(i)/pow(BallCount,2); 
      }
     
      while (true) {
        for (int i = 0 ; i < BallCount ; i++) {
          TimeSinceLastBounce[i] = millis() - ClockTimeSinceLastBounce[i];
          Height[i] = 0.5 * Gravity * pow( TimeSinceLastBounce[i]/1000 , 2.0 ) + ImpactVelocity[i] * TimeSinceLastBounce[i]/1000;
      
          if ( Height[i] < 0 ) {                      
            Height[i] = 0;
            ImpactVelocity[i] = Dampening[i] * ImpactVelocity[i];
            ClockTimeSinceLastBounce[i] = millis();
      
            if ( ImpactVelocity[i] < 0.01 ) {
              ImpactVelocity[i] = ImpactVelocityStart;
            }
          }
          Position[i] = round( Height[i] * (NUM_LEDS - 1) / StartHeight);
        }
      
        for (int i = 0 ; i < BallCount ; i++) {
          setPixel(Position[i],red,green,blue);
        }
        
        showStrip();
        setAll(0,0,0);
      }
    }

    Beantwoorden

    pierre

    • 22 sep, 2018 - 11:12 AM - hans - Auteur: Opmerking Link

      Hoi Pierre,

      dus het volgende geeft een foutmelding?

      BouncingBalls(0xff,0xff,0xff, 3);

      Kun je misschien vertellen wat de foutmelding is? Dan kan ik mee kijken wat we over het hoofd zien. 

      Beantwoorden

      hans

  • 6 okt, 2018 - 4:25 PM - Pierre Opmerking Link

    Sorry uw vraag over het hoofd gezien.

    Krijg geen foutmelding, het programma blijft gewoon dit effect geven en gaat niet meer terug naar het volgende effect.

    Bedoel dus dat de lus niet meer verder wordt gegeven enkel het laatste effect blijft werken.

    Beantwoorden

    Pierre

    • 7 okt, 2018 - 10:17 AM - hans - Auteur: Opmerking Link

      Hoi Pierre 

      Kan gebeuren haha. Ik zie dat jouw code gebaseerd is op de oude BouncingBalls (je ziet het aan de regel met “while (true)“).
      Dit was ook een van de uitdagingen voor de alles-in-1 aanpak. Als je hierboven onder het kopje “Uitdaging 1 – Effecten die Eindeloos zijn” kijkt, dan zie je dat de while-loop daar kijkt of de ballen zijn uit gestuiterd. In dat deel staat ook de aangepaste code die dus niet vast blijft in het effect (ook in de code waarbij alle effecten samen staan, maar daar heet het “BouncingColoredBalls”).

      Hopelijk helpt dit je op weg – laat het gerust weten als je nog meer vragen hebt. 

      Beantwoorden

      hans

  • 10 okt, 2018 - 4:41 PM - Mark oost Opmerking Link

    Hans, 

    Doe je dit hobbymatig ? Of doe je ook projecten voor anderen ?

    Of weet je een bedrijfje of persoon die een project zou aanpakken.  Het gaat om een lichteffect te maken met ledstrips.

    Met behulp van arduino. 

    Mark.

    Beantwoorden

    Mark oost

    • 11 okt, 2018 - 2:32 PM - hans - Auteur: Opmerking Link

      Hoi Mark,

      ik heb je een reply per email gestuurd.
      Ik doe dit hobbymatig, maar als je wat meer informatie over het project stuurt (webmaster at tweaking4all dot com) dan kan ik je laten weten waar en hoe ik kan helpen of zelfs het project kan aannemen.

      Beantwoorden

      hans



Jouw opmerking ...

Vriendelijk verzoek om hier geen lange bestanden te posten (zoals source codes, log bestanden of config bestand). Gebruik het Forum hiervoor.

Deel:
*
*
Stuur me een notificatie van nieuwe opmerkingen (email).
       Je kunt jouw RSS reader gebruiken op opmerkingen te volgen.


Tweaking4All gebruikt de gratis Gravatar dienst voor de weergave van Avatars.
Tweaking4All deelt jouw email adressen NOOIT.