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 “Sketch” “Include Library” “Manage 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
Ad Blocking Gedetecteerd Vriendelijk verzoek om te overwegen Ad Blocking uit te zetten voor onze website.
We zijn afhankelijk van inkomen uit Advertenties om de website te kunnen draaien.
Je kunt ons ook op andere manieren ondersteunen (zie Ondersteun ons links bovenin).
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
Ad Blocking Gedetecteerd Vriendelijk verzoek om te overwegen Ad Blocking uit te zetten voor onze website.
We zijn afhankelijk van inkomen uit Advertenties om de website te kunnen draaien.
Je kunt ons ook op andere manieren ondersteunen (zie Ondersteun ons links bovenin).
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.
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:
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();
} |
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.
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.
Jan
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
hans
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
Ruben
Zie onderstaande uitleg bij jouw tweede vraag
hans
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
Ruben
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():
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.
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.
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.
en voor functies die minder helder moeten zijn (even mee spelen dus) bijvoorbeeld:
b.v.
Hopelijk helpt dit je op weg …
hans
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.
Ruben
Mooi om te horen en graag gedaan!
hans
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
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
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?
dirkjan
Hoi DrikJan,
Als eerste: hartelijk dank voor het compliment! Top!
ja dat kan zeker.
Probeer dit eens; vervang het volgende stukje code
door
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)
hans
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.
Alex
Deze mogen inderdaad verwijderd worden.
Hans
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
Ruben Smit
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:
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
hans
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
Ruben
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)
hans
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?
Pierre
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;
De truuk zit ‘m in dit stukje;
waarbij we kijken of een bal nog echt stuitert.
Hopelijk helpt dit je op weg.
hans
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
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.
pierre
Hoi Pierre,
dus het volgende geeft een foutmelding?
Kun je misschien vertellen wat de foutmelding is? Dan kan ik mee kijken wat we over het hoofd zien.
hans
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.
Pierre
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.
hans
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.
Mark oost
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.
hans
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.
theo verveen
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
hans
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?
Dieuwke
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).
hans
Die heeft er toch 14?en de due zelfs over de 50….is dat dan wel een mogelijkheid?
Dieuwke
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.
2) Vervolgens de functie definiëren. waarbij we het effect nummer doorgeven en opslaan in de EEPROM;
3) Kleine aanpassing aan de loop(), want het “if(selecetedEffect>18) { … }” stukje hebben we niet meer nodig.
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.
hans
Bedankt voor de moeite!! Eens kijken wat ik hiermee kan, maar nogmaals bedankt!!
Dieuwke
Graag gedaan!
hans
Overigens; een layout van de Due, die flink gedetailleerd is, vond ik hier. Maar door de vele details wel een beetje verwarrend.
hans
Of wellicht stuk of 3 effecten per knop?? Realiseerbaar??
Dieuwke
Zie antwoord hierboven
hans
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)
George
Sorry, Ik heb iets fout gedaan. Sketch is zo niet echt duidelijk, maar kan het op deze pagina niet meer aanpassen.
Hier duidelijker
George
Hi George!
Dank je wel dat je de code in het forum hebt geplaatst. Ik heb daar ook een mogelijke oplossing geplaatst.
hans
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
Henk
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 )
hans
UDPATE:
De Source code is geüpdate met Daniel’s suggestie om
in plaats van
te gebruiken.
hans
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
Erik-Jan Wind
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.
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:
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:
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.
Hans
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
Bart
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.
Hans
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?
jeandelaune
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)
Hans
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
Jeandelaune
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:
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.
Hopelijk helpt dit je op weg. 😊
Hans
Dank je Hans. Ik ga hiermee aan de slag.
Jeandelaune