Pagina1 van 1

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

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

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) 

Bestandsnaam:  AllEffects-FastLED.ino.zip
Platform:  Undefined
Versie:  1.1
Omvang:  4.7 kB
Datum:  2019-10-21
 Download Nu  Stuur me Koffie    

Download - AllEffects LEDStrip Effect (NeoPixel) 

Bestandsnaam:  AllEffects-NeoPixel.ino.zip
Platform:  Undefined
Versie:  1.1
Omvang:  4.7 kB
Datum:  2019-10-21
 Download Nu  Stuur me Koffie    

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:


pinMode(2,INPUT_PULLUP);  // 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 );
  pinMode(2,INPUT_PULLUP);  // 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'
  pinMode(2,INPUT_PULLUP);  // 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();
}

 

Ondersteun ons ...


Jouw ondersteuning wordt zeer gewaardeerd, en hoeft zelfs niets te kosten. Bijvoorbeeld door links naar ons te delen op social media, of andere websites.

Andere vormen kunnen ook gratis zijn (b.v. shoppen op Amazon).
Alle opbrengsten worden gebruikt voor web-hosting kosten, project hardware en software, koffie, etc.

Hartelijk dank voor wie al heeft bijgedragen!
Het is altijd geweldig om te zien hoe men mijn artikeltjes en applicaties weet te waarderen.

Merk op dat het klikken op affiliate links een kleine commissie voor ons kunnen genereren - dit wordt zeer gewaardeerd.

Reacties


Er zijn 52 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 - Jan Reactie 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 - 17:06 - hans - Auteur: Reactie 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 - 23:51 - Ruben Reactie 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 - 18:40 - Ruben Reactie 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 - 14:23 - hans - Auteur: Reactie 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 - 15:21 - Ruben Reactie 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 - 20:14 - hans - Auteur: Reactie Link

          Mooi om te horen en graag gedaan! 

          Beantwoorden

          hans

          • 27 apr 2018 - 19:44 - Ruben Reactie 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 - hans - Auteur: Reactie 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 - dirkjan Reactie 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 - 20:12 - hans - Auteur: Reactie 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

      • 10 nov 2023 - 10:51 - Alex Reactie Link

        Hoi Ruben,

        Een opmerking:

        #define button 2

        en

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

        Moeten dan toch ook verwijderd worden….

        Gegroet,

        Alex.

        Beantwoorden

        Alex

  • 16 jul 2018 - 13:51 - Ruben Smit Reactie 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 - hans - Auteur: Reactie 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 - 16:51 - Ruben Reactie 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 - hans - Auteur: Reactie 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 - 15:56 - Pierre Reactie 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 - hans - Auteur: Reactie 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 - 15:14 - pierre Reactie 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 - hans - Auteur: Reactie 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 - 16:25 - Pierre Reactie 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 - hans - Auteur: Reactie 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 - 16:41 - Mark oost Reactie 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 - 14:32 - hans - Auteur: Reactie 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

  • 30 dec 2018 - 7:21 - theo verveen Reactie Link

    Hoi Hans,

    Hardstikke leuk, dank voor alle effort, geeft veel inspiratie en inzicht en in de mogelijkheden van de ledstrips.

    Ik heb na 18 maanden de arduino weer uit de kast gehaald.

    Fijne jaarwisseling.

    Beantwoorden

    theo verveen

    • 30 dec 2018 - 15:53 - hans - Auteur: Reactie Link

      Hoi Theo!

      Dank je wel!
      Mooi om te horen dat je er wat aan had en er weer mee aan de slag gaat 

      Jij ook een fijne jaarwisseling en een gelukkig nieuw jaar 

      Beantwoorden

      hans

  • 3 mei 2019 - 22:28 - Dieuwke Reactie Link

    Hoihoi, 

    Super code! Maar nu zou ik graag een button voor elk effect aan en uit willen. Stuk of 10 a 15 buttons met even zoveel effecten. Maar ik kan niks vinden wat daar op lijkt. Zelf ben ik nog maar een newbie. Kun je me misschien in de juiste richting sturen? 

    Beantwoorden

    Dieuwke

    • 4 mei 2019 - 10:52 - hans - Auteur: Reactie Link

      Hoi Dieuwke!

      Mooi om te horen dat je de code super vindt.

      Wat jou w vraagt betreft; de eerste gedachte die ik had was;
      Jemig 10-15 knoppen gaat niet lukken, omdat de Arduino maar een beperkt aantal knoppen met attachInterrupt() kan opzetten. Voor de Uno zijn er dat zelfs maar 2 (digital pin 2 en 3).

      Er zijn Arduino modellen die wat meer kunnen, maar zelfs dan kom je (volgens wat ik even snel kon vinden) op hoogstens 11 pinnen uit (Uno WiFi v2). Ik vrees dat je dan toch een andere aanpak zult moeten gaan gebruiken.

      Een alternatief wordt snel behoorlijk gecompliceerd, b.v. met een schakelaar matrix, or een draaiknop (kies effect) en een druk knop (effect uitvoeren).

      Beantwoorden

      hans

      • 4 mei 2019 - 19:59 - Dieuwke Reactie Link

        Die heeft er toch 14?en de due zelfs over de 50….is dat dan wel een mogelijkheid? 

        Beantwoorden

        Dieuwke

        • 5 mei 2019 - 9:55 - hans - Auteur: Reactie Link

          Volgens de documentatie van Arduino, zie deze link, ben je beperkt in welke pinnen specifiek voor interrupt gebruikt kunnen worden.

          De Due heeft er inderdaad lekker veel … en de documentatie zegt dat elke digitale pin hiervoor gebruikt kan worden op de Due. Koste me wat zoekwerk, ik heb zelf geen Due.

          Aangezien ik zelf niet de geschikte hardware heb zou je zoiets kunnen doen;

          1) Voor elke pin die je gebruiken wilt, een functie aan een interrupt hangen (dit kan efficienter dan de beschreven code).

          N.b. ik weet niet 100% zeker of we een functie met parameter (changeEffect(x)) kunnen doorgeven naar de attachInterrupt functie. Mocht dit niet werken, dan moeten we per button een “changeEffectX()” functie maken.

          ...
          #define KNOP1 1
          #define KNOP1 2
          #define KNOP1 3
          // zelf uitzoeken wat de knop nummers zijn (digital pins) voor de Due
          ...
          void setup() {
            FastLED.addLeds<WS2811, PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
            digitalWrite (KNOP1, HIGH); // internal pull-up resistor - is dit ook het geval voor de Due?
            attachInterrupt (digitalPinToInterrupt(KNOP1), changeEffect(1), CHANGE); 
            digitalWrite (KNOP2, HIGH); // internal pull-up resistor
            attachInterrupt (digitalPinToInterrupt(KNOP2), changeEffect(2), CHANGE); 
            digitalWrite (KNOP3, HIGH); // internal pull-up resistor
            attachInterrupt (digitalPinToInterrupt(KNOP3), changeEffect(3), CHANGE); 
            ... etc
          }

          2) Vervolgens de functie definiëren. waarbij we het effect nummer doorgeven en opslaan in de EEPROM;

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

          3) Kleine aanpassing aan de loop(), want het “if(selecetedEffect>18) { … }” stukje hebben we niet meer nodig.

          void loop() { 
            EEPROM.get(0,selectedEffect); 
             //Dit stukje hebben we niet meer nodig:
            //if(selectedEffect>18) { 
            //  selectedEffect=0;
            //  EEPROM.put(0,0); 
            //}  switch(selectedEffect) { ... etc

          Dat is al aardig in de buurt van de oplossing …  

          Maar nogmaals; ik heb zelf geen Due liggen om het te testen … ik volg alleen wat de documentatie me vertelt.

          Beantwoorden

          hans

          • 5 mei 2019 - 12:09 - Dieuwke Reactie Link

            Bedankt voor de moeite!! Eens kijken wat ik hiermee kan, maar nogmaals bedankt!! 

            Dieuwke

          • 5 mei 2019 - 16:12 - hans - Auteur: Reactie Link

            Graag gedaan! 

            hans

        • 5 mei 2019 - 9:56 - hans - Auteur: Reactie Link

          Overigens; een layout van de Due, die flink gedetailleerd is, vond ik hier. Maar door de vele details wel een beetje verwarrend.

          Beantwoorden

          hans

      • 4 mei 2019 - 20:51 - Dieuwke Reactie Link

        Of wellicht stuk of 3 effecten per knop?? Realiseerbaar?? 

        Beantwoorden

        Dieuwke

  • 27 jul 2019 - 20:45 - George Reactie Link

    Hoi Hans,

    Geweldige sketch, daar kan ik nog eens wat mee.

    Ik loop echter tegen een praktisch probleem aan: Ik dim normaal gesproken mijn effecten met een Rotary encoder (Keyes KY-040).
    (Deze Rotary encoder heeft ook een Switch door hem in te drukken) . 

    Eenmaal uitgevonden hoe de waardes van een Encoder zijn te lezen, is het vrij eenvoudig om zo de waarde die tussen haakjes staat achter “FastLED.setBrightness(255);” te veranderen.

    Dit Dimmen moet tijdens het runnen van een effect altijd werken, vandaar dat de rotary ook gebruikt maakt van Interrupts.

    Nu zou ik dus graag van deze Switch op de encoder gebruik willen maken om van het ene effect naar het andere te kunnen springen.
    Net zoals in je prachtig uitgewerkte sketch én het te kunnen dimmen door er aan te draaien.

    (Voel je het probleem al aankomen  )

    Zie hieronder de manier waarop ik een Ledstrip dim:

    (source code verwijderd en in het forum geplaatst)

    Beantwoorden

    George

  • 25 aug 2019 - 13:58 - Henk - Auteur: Reactie Link

    Hoi Hans,

    Als nieuwe Arduino/LED gebruiker wil ik je hartelijk danken voor de heldere en duidelijke uitleg. Misschien leuk voor je om te weten waar ik het wil gaan toepassen:

    Op onze praalwagen in Dé oudste verlichte optocht van Nederland, Berghem.

    Wij gebruiken nu 220v LED’s en turbo kappen (die van de kermis). Effecten gaan we nu proberen dus met de Arduino en 5v LED’s en Adafruit proberen.

    Dank voor je uitleg!

    Henk

    Beantwoorden

    Henk

    • 25 aug 2019 - 17:19 - hans - Auteur: Reactie Link

      Hoi Henk,

      Dank je wel voor het bedankje! Ik bekijk net jouw website (http://www.uhkw.nl/) – mooi! 
      Wat v5V LEDs betreft; even bij AliExpress en Amazon kijken, daar krijg je precies dezelfde LEDs voor minder, EN met verschillende gradaties van waterdichtheid!
      Ben benieuwd waar je op uit gaat komen, ik zie dat jullie wel weten hoe je een mooie carnavalswagen in elkaar moet zetten.
      (ik kom uit de omgeving van Breda, dus Carnaval kennen we hier wel )

      Beantwoorden

      hans

  • 21 okt 2019 - 14:50 - hans - Auteur: Reactie Link

    UDPATE:

    De Source code is geüpdate met Daniel’s suggestie om

    pinMode(2,INPUT_PULLUP);

    in plaats van 

    digitalWrite (BUTTON, HIGH); 

    te gebruiken.

    Beantwoorden

    hans

  • 23 jul 2020 - 21:48 - Erik-Jan Wind Reactie Link

    Goedenavond,

    Wat een topsite! ik heb de effecten aan de gang op mijn 5v strip over een meter. Ik wil dit gebruiken om iin interactief bord voor mijn dochter te maken. (gecombineerd maar sloten/scharnieren/etc. en andere lichteffecten en schakelaars. Ik ben zelf een newbie met arduino’s. Zou je mij op gang willen helpen met het volgende?

    Ik wil graag tussen elk effect dat de ledstrip uit gaat..

    Kan er een max tijd aan elk effect gehangen worden? (en dan weer de lestrip uitzetten, wachten op een volgende druk op de knop)

    Kunnen de effecten random?

    Als ik de knop indruk slaat hij vaak effecten over, is het mogelijk een andere “scantijd” van de knop te krijgen, ik kan dit niet vinden in de code.

    Alvast bedankt voor de moeite!

    Groeten,

    Erik-Jan

    Beantwoorden

    Erik-Jan Wind

    • 26 jul 2020 - 14:07 - Hans - Auteur: Reactie Link

      Hoi Erik-Jan!

      Dank je wel voor het compliment! 

      Effect overslaan

      Het overslaan van effecten kan komen door het “bounce” verschijnsel van schakelaars. Wat er gebeurt is dat bij het loslaten van de schakelaar nog een keer contact wordt geregistreerd en de Arduino dus denkt dat je nog een keer op de schakelaar drukt. Je zou dit op verschillende manieren kunnen opvangen.

      Mogelijke oplossingen kun je vinden in een andere schakelaar testen of de code een beetje aanpassen (helaas kom ik het probleem zelf niet tegen dus het is een beetje lastig om een oplossing te vinden omdat ik niet kan testen). Voor meer info over “debouncing” zie dit Arduino Debounce artikel.

      Ongetest, maar dat zou er ongeveer zo uit kunnen zien: We slaan de tijd op waarop het laatst een knop was ingedrukt. Als de tijd tussen twee knop drukken debounceDelay (milliseconden), dan pas registreren we het als een echt knop drukt. 50 milliseconden is wat ik uit het Arduino voorbeeld heb gehaald, en het kan dus nodig zijn om een hogere waarde te kiezen.

      ...
      
      unsigned long lastDebounceTime = 0; // de laatste keer dat de knop werd ingedrukt en we het effect hebben veranderd
      unsigned long debounceDelay = 50; // minimale tijd, in milliseconden, tussen twee knop drukken
      ... void changeEffect() {
        if ((millis() - lastDebounceTime) > debounceDelay)
        {

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

      Random Effecten

      Je kunt effecten inderdaad ook random laten lopen, dus zonder dat de knop nodig is.
      Zie deze uitleg in de Engelstalige versie van dit artikel.

      Strip uitzetten tussen effecten

      Uitzetten van de LEDs tussendoor kan ook. Dit kun je dan het beste in de changeEffect functie doen, bijvoorbeeld zo:

      void changeEffect() {
      ... 
            selectedEffect++;
            EEPROM.put(0, selectedEffect);
            setAll(0,0,0); // zet alle LEDs op zwart
            showStrip(); // maak dit zichtbaar
            delay(500); // 500 milliseconde pauze voor we effect wisselen

            asm volatile (" jmp 0");
      ...
      }

      Er zijn alternatieven natuurlijk.

      Maximale “speelduur” van een effect

      ook hier moeten we dan weer de tijd bijhouden, net zoiets als bij de debounce optie. Bijvoorbeeld zoals hieronder: we registreren de starttijd, en in de loop voeren we de hele “switch” functie alleen maar uit als we binnen de toegestane tijd zitten:

      ...
      unsigned long maxSpeelduur = 5000; // een effect mag maar 5 seconden (5000 milliseconden) draaien
      unsigned long effectStartTijd = 0; // tijd waarop een effect het laatst gestart werd
      ...
      void setup() {
      ... effectStartTijd = millis(); // bij start en reset wordt dit uitgevoerd en de tijd dus ingested van de laatste effect wisseling ...
      }
      void loop() {
        EEPROM.get(0,selectedEffect);
       
        if(selectedEffect>18) {
          selectedEffect=0;
          EEPROM.put(0,0);
        }
       
       if((millis() - effectStartTijd) < maxSpeelduur) {
          switch(selectedEffect) {
          ...
          }
        }
      }

      Nu weet ik niet precies hoe je alles wilt gebruiken, maar hopelijk helpt dit je op weg.
      Mocht het programmeren je nog nieuw zijn, dan kun je misschien in deze mini cursus hulp vinden. 

      Beantwoorden

      Hans

  • 8 dec 2020 - 16:24 - Bart Reactie Link

    Beste Hans,

    ik heb op een Arduino Uno 3 on/off switches en 7 LED-strips aangesloten. Elke switch heeft een desbetreffende ‘loop()’ voor zijn ‘on’ en de ‘off’-stand zodat de aangesproken LED-strips met een bepaalde sequentie aan- of afgezet kunnen worden.

    Echter, als ik de beide posities (on-off) van de 3 schakelaars in 6 verschillende loops onderbreng in een ‘if’-statement dan valt het me op dat Arduino veel tijd nodig heeft om te reageren op mijn switches (lees = hij is telkens wel één of andere ‘loop()’ aan het uitvoeren). Ik heb geprobeerd met attachInterrupt (digitalPinToInterrupt(BUTTON), changeEffect, CHANGE) maar dat is me tot op heden niet echt gelukt. 

    Zou je me op weg kunnen helpen met een voorbeeld voor het gebruik van bovenvermelde functie?

    Moeten de inputs van de schakelaars op bepaalde posities van de Arduino Uno anagesloten worden of kan dat op elke Pin?

    Moet de uiteindelijke ‘loop()’ steeds NA alle IRS-statements komen?

    Hartelijke dank bij voorbaat,

    Bart

    Beantwoorden

    Bart

    • 9 dec 2020 - 13:01 - Hans - Auteur: Reactie Link

      Hoi Bart,

      misschien is het een idee om een forum onderwerp te starten zodat we wat verder kunnen kijken waar je tegen aan loopt.

      Met 3 schakelaars, zou ik op elke schakelaar een interrupt zetten.
      In de betreffende interrupt call zou ik dan een globale variabele van waarde veranderen (in de code hier gebruik ik “selectedEffect”), zodat in de loop() hierop gereageerd kan worden.
      Ik weet niet of je 6 effecten of 3 effecten probeert te gebruiken. Bij 6 effecten kan het e.e.a. wat lastiger worden omdat meerdere (druk?) schakelaars tegelijk een interrupt veroorzaken.

      Misschien is het beste om eerst met iets eenvoudigs te beginnen. B.v. het ledje op de Arduino aan en uit zetten m.b. 1 schakelaar en een interrupt.
      Daarna uitbreiden naar 2 schakelaar en kijken of je met de ene de LED aan kunt zetten en met de andere weer uit.
      Als je dat werkende hebt, dan pas de zaak gecompliceerder maken.

      Interrupts moet je definieren in de void setup(), dus voor de loop wordt gestart.

      Let ook op: het is afhankelijk van jouw Arduino hoeveel interrupts je kunt maken en voor welke pinnen.
      Bijvoorbeeld een Arduino Uno ondersteund attachInterrupt alleen voor PIN 2 en PIN 3.
      Dus met een Uno zal 3 schakelaar niet gaan werken met de attachInterrupt aanpak.
      Zie ook Arduino AttachInterrupt

      N.B. als je meer dan 2 effecten op een Uno probeert te gebruiken, dan zou je kunnen overwegen een draaischakelaar te gebruiken welke meerder posities heeft, gecombineerd met een drukknop die de Arduino triggered om opnieuw te kijken op welke stand de draaischakelaar staat.

      Beantwoorden

      Hans

  • 30 jul 2023 - 14:37 - jeandelaune Reactie Link

    Goedemiddag, ik heb een vraag over het gebruik van de WS2812
    ledstrips. Voor een animatie gebruik ik meerdere ledstrips met elk hun
    eigen effect. Elke strip heeft nu een eigen Arduino voor de aansturing.

    Is
    het mogelijk om met een Arduino meerdere strips tegelijk aan te sturen?
    Zoja, wat zou er dan aan de code aangepast moeten worden?

    Beantwoorden

    jeandelaune

    • 31 jul 2023 - 15:44 - Hans - Auteur: Reactie Link

      Hallo!

      (ik heb jouw andere 2, bijna identieke berichten, verwijderd)

      Je kunt met een Arduino inderdaad meerder strips aansturen.
      Dit kan op twee manieren:

      1) Als beide strips hetzelfde effect zouden moeten laten zien dan kun je beide strips aan dezelfde pin aansluiten (pin 6 in dit voorbeeld). Beide strips reageren dan identiek.

      2) Als elke strip een individueel effect moet doen, dan zul je voor elke strip een aparte pin moeten gebruiken. Dit komt wel met wat uitdagingen omdat een Arduino niet gedacht is voor multitasking. Dus bij 2 strips (als voorbeeld) zul je steeds om beurten een stap in elk van de twee effect moeten uitvoeren (dus doen alsof het parallel gebeurt). Dit kom met wat lastige zaken, en loopt dus langzamer dan met een enkele strip, maar is zeker niet onmogelijk.

      Tip: als je een ESP32 gebruikt, dan zou je gebruik kunnen maken van het feit dat deze 2 cores heeft en dus wel 2 dingen tegelijk kan doen. (zie b.v. dit artikel)

      Beantwoorden

      Hans

      • 1 aug 2023 - 10:07 - Jeandelaune Reactie Link

        Hallo Hans, dank voor je snelle respons. In je antwoord geef je 2 mogelijkheden aan. Mijn probleem gaat over de 2e; elke strip heeft een individueel effect. 

        Hoe kan ik in de code aangeven dat effect A op PIN2 moet komen en effect B op PIN3? In de code staat een regel die verwijst naar een PIN: Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800); Ik moet op e.e.a. manier een 2e PIN adresseren. Hoe kan ik dat doen?


        Daarna kan ik de effecten aanmaken in een functie en die d.m.v. showStrip(); op de uitgang zetten. Hoe wordt bepaald dat het effect naar PIN2 of PIN3 gaat?
        Zou je me op weg kunnen helpen, dan kan ik verder experimenteren. Alvast dank.Jean

        Beantwoorden

        Jeandelaune

      • 1 aug 2023 - 11:42 - Hans - Auteur: Reactie Link

        Hoi! 

        In de loop geef je aan dat er een tweede strip is … (uitgaande van FastLED, aangezien die wat volwassener en sneller is dan AdaFruit)

        Als voorbeeld:

        #include "FastLED.h"
        #include <EEPROM.h>
        #define NUM_LEDS 60
        CRGB ledsStrip1[NUM_LEDS]; CRGB ledsStrip2[NUM_LEDS];
        #define PINStrip1 5 #define PINStrip2 6
        #define BUTTON 2
        byte selectedEffect=0;
        void setup()
        {
          FastLED.addLeds<WS2811, PINStrip1, GRB>(ledsStrip1, NUM_LEDS).setCorrection( TypicalLEDStrip ); FastLED.addLeds<WS2811, PINStrip2, GRB>(ledsStrip2, NUM_LEDS).setCorrection( TypicalLEDStrip );
          pinMode(2,INPUT_PULLUP); // internal pull-up resistor
          attachInterrupt (digitalPinToInterrupt (BUTTON), changeEffect, CHANGE); // pressed
        }

        Zie de “PinStrip1” en “ledsStrip1” definities.
        Je kunt ipv twee arrays (1 per strip) een multi-dimensionele array maken maar dat is niet voor iedereen weggelegd – je kunt hier nog meer voorbeelden vinden.

        De functies, zoals ShowStrip, moeten dan inderdaad wel aangepast worden. 

        Bijvoorbeeld zoiets als dit – maar er zijn plenty andere methoden te bedeken hoe je dit kunt doen.

        // Set a LED color (not yet visible)
        void setPixel(byte Strip, int Pixel, byte red, byte green, byte blue) {
           // FastLED if(Strip==1) {
            ledsStrip1[Pixel].r = red;
            ledsStrip1[Pixel].g = green;
            ledsStrip1[Pixel].b = blue; } else { ledsStrip2[Pixel].r = red; ledsStrip2[Pixel].g = green; ledsStrip2[Pixel].b = blue; }
        }
        // Set all LEDs to a given color and apply it (visible)
        void setAll(byte Strip, byte red, byte green, byte blue) {
          for(int i = 0; i < NUM_LEDS; i++ ) {
            setPixel(Strip, i, red, green, blue);
          }
          showStrip();
        }

        Hopelijk helpt dit je op weg. 😊 

        Beantwoorden

        Hans



Jouw Opmerking ...

Plaats hier geen grote bestanden (zoals source codes, log files of config files). Gebruik hiervoor het Forum.

Delen:
*
*
Laat me per email weten als er nieuwe reacties zijn.
       Je kunt jouw RSS reader gebruiken om reacties te volgen.


Tweaking4All gebruikt de gratis Gravatar dienst voor Avatar weergave.