Effecten maken met FastLED
Informatie, tips en trucs over het aansturen van adresseerbare leds met de library FastLED in Arduino door Ron.
Tags: FastLED, WS2812, WS2811, SK6812 Adafruit Neopixel, Arduino
Aan deze pagina wordt nog geknutseld!
FastLED library
Soorten leds
Adresseerbare leds zijn te verkrijgen in vele types en uitvoeringen. Hieronder staan de meestgebruikte types en uitvoeringen beschreven.
Type leds/chips
- WS2812 led
- WS2812B led
- WS2813 led
- WS2815 led
- WS2811 chip
- SK6812 led
- SK9822 led
- APA102 led clock+data
- APA104 led
- APA106 led
- GS8206 chip
- GS8208 chip
- CS8208 chip
- TM1814 chip
- NeoPixel is een merk van Adafruit! https://www.adafruit.com/category/168
Uitvoeringen
Strips, panelen, neon, ronde led, FCOB
Shops
Shops met kwalitatieve led-strips en groot assortiment:
- RAZEND Official Store (AliExpress)
- Ray wu's store (AliExpress)
Code voorbeelden 1D
Klik op de afbeelding om het voorbeeld te bekijken. Deze zijn allemaal geschikt om op een Arduino Uno te draaien.
Blink met FastLED | |
Kleurvolgorde test | |
Bewegen met sinusgolf | |
Regenboog | |
Multiblink | |
Random fade | |
Random crossfade | |
Regenboog fade met sinusbeweging |
- Nightrider
- Regenboog
- Random fade to color
- Sinusfuncties
- …
Basiscode
De komende voorbeeldprogramma's gebruiken de onderstaande basiscode. Kopiëer dit eerst naar arduino en vervang dan het void loop(){}
gedeelte door de code uit het voorbeeld.
//--FastLED--// #include "FastLED.h" #define DATA_PIN 15 #define LED_TYPE WS2812 #define COLOR_ORDER RGB //kleurvolgorde. Rood,Groen,Blauw #define NUM_LEDS 20 //Aantal leds die je wilt aansturen CRGB leds[NUM_LEDS]; //Geheugen voor elke led in de vorm van een array void setup() { FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS); //FastLED initialiseren FastLED.setBrightness(127); //Helderheid instellen 0...255 FastLED.clear(); //alle leds uitzetten FastLED.show(); //nieuwe waarden naar de leds schrijven } void loop() { leds[0]=CRGB(255,0,0); //Eerste led rood maken FastLED.show(); //nieuwe waarden naar de leds schrijven }
Blink met FastLED
void loop() { leds[0]=CRGB(255,0,0); FastLED.show(); delay(500); leds[0]=CRGB(0,255,0); FastLED.show(); delay(500); }
Blink zonder delay:
void loop() { leds[0]=CRGB(255*(millis()%1000<500),0,0); FastLED.show(); }
Kleurvolgorde test
Stel de kleurvolorde in op RGB.
#define COLOR_ORDER RGB
Gebruik de volgende code in loop().
void loop(){ leds[0]=CRGB(255,0,0); //Rood leds[1]=CRGB(0,255,0); //Groen leds[2]=CRGB(0,0,255); //Blauw FastLED.show(); delay(500); }
Kleurvolgorde goed ingesteld:
Kleurvolgorde fout ingesteld:
Verander de kleurvolgorde naar de volgorde die de leds laten zien.
#define COLOR_ORDER GRB
Code voor de kleurvolgorde test met één enkele led:
void loop(){ leds[0]=CRGB(255,0,0); FastLED.show(); delay(500); //Rood leds[0]=CRGB(0,255,0); FastLED.show(); delay(500); //Groen leds[0]=CRGB(0,0,255); FastLED.show(); delay(500); //Blauw leds[0]=CRGB(0,0,0); FastLED.show(); delay(2000); //Uit }
Bewegen met sinusgolf
void loop(){ unsigned long t = millis(); //Tijd in milliseconden int x=10.5+sin(t/750.0)*10; //Sinusbeweging maken for(int i=0; i<NUM_LEDS; i++){ if(i<x){ leds[i]=CRGB(255,0,0); }else{ leds[i]=CRGB(0,255,0); } } FastLED.show(); }
Regenboog
void loop(){ unsigned long t = millis(); for(int i=0; i<NUM_LEDS; i++){ byte hue = i*12+t/10; leds[i]=CHSV(hue,255,255); } FastLED.show(); }
Multiblink
void loop(){ unsigned long t = millis(); for(int i=0; i<NUM_LEDS; i++){ int periode = 500+(i*421)%500; leds[i]=CRGB(255*(t%periode<periode/2),0,0); } FastLED.show(); }
Random fade
void loop(){ EVERY_N_MILLISECONDS(150){ int i = random(0,NUM_LEDS); if(!leds[i]){ //Led is niet aan byte hue = random(0,255); leds[i] = CHSV(hue,255,255); } } EVERY_N_MILLISECONDS(33){ int sub = 5; for(int i=0; i<NUM_LEDS; i++){ leds[i].r=max(0,leds[i].r-sub); leds[i].g=max(0,leds[i].g-sub); leds[i].b=max(0,leds[i].b-sub); } FastLED.show(); } }
Random crossfade
CRGB buff[NUM_LEDS]; //Extra buffer voor het onthouden van doelkleuren void loop() { EVERY_N_MILLISECONDS(150){ //Elke 150ms een led van kleur veranderen int i = random(0,NUM_LEDS); if(leds[i]==buff[i]){ //Led is statisch byte hue = random(0,255); buff[i]=CHSV(hue,255,255); } } EVERY_N_MILLISECONDS(33){ int inc = 20; for(int i=0; i<NUM_LEDS; i++){ if(leds[i]!=buff[i]){ leds[i].r = leds[i].r + constrain(buff[i].r - leds[i].r,-inc,inc); leds[i].g = leds[i].g + constrain(buff[i].g - leds[i].g,-inc,inc); leds[i].b = leds[i].b + constrain(buff[i].b - leds[i].b,-inc,inc); } } FastLED.show(); } }
Random sliding fade
byte hue=0; CRGB color; int index=0; unsigned long frame=0; void loop() { EVERY_N_MILLISECONDS(33){ if(index==0){ hue=hue+random(50,200); color=CHSV(hue,255,255); } int inc = 20; for(int i=0; i<NUM_LEDS; i++){ if(leds[i]!=color && i<=index){ leds[i].r = leds[i].r + constrain(color.r - leds[i].r,-inc,inc); leds[i].g = leds[i].g + constrain(color.g - leds[i].g,-inc,inc); leds[i].b = leds[i].b + constrain(color.b - leds[i].b,-inc,inc); } } FastLED.show(); //Elke drie frames 1 bij index optellen: if(frame%3==0){ index++; } frame++; //Index resetten wanneer de laatste led klaar is met faden: if(index>=NUM_LEDS && leds[NUM_LEDS-1]==color){ index = 0; } } }
Regenboog fade met sinusbeweging
CRGB buff[NUM_LEDS]; //Extra buffer voor het onthouden van doelkleuren void loop() { EVERY_N_MILLISECONDS(33){ unsigned long t = millis(); int x=10+sin(t/500.0)*10; //Sinusbeweging maken buff[x]=CHSV(t/15,255,255); //Kleur in buffer laden int inc = 20; for(int i=0; i<NUM_LEDS; i++){ //Naar kleur in buffer faden if(leds[i]!=buff[i]){ leds[i].r = leds[i].r + constrain(buff[i].r - leds[i].r,-inc,inc); leds[i].g = leds[i].g + constrain(buff[i].g - leds[i].g,-inc,inc); leds[i].b = leds[i].b + constrain(buff[i].b - leds[i].b,-inc,inc); } } FastLED.show(); } }
Code voorbeelden 2D
Klik op de afbeelding om het voorbeeld te bekijken. Deze zijn allemaal geschikt om op een Arduino Uno te draaien.
- Spiraal algoritme
- Octopus patroon: WS2812B 16x16 Matrix Octopus Pattern
Afstand+hoek (LUT)
LUT = LookUp Table
#include "FastLED.h" #define DATA_PIN 15 #define LED_TYPE WS2812 #define COLOR_ORDER RGB //kleurvolgorde. Rood,Groen,Blauw / Groen,Rood,Blauw #define NUM_LEDS 256 #define COLS 16 #define ROWS 16 CRGB leds[NUM_LEDS]; //Lookup tables: byte _r[NUM_LEDS]; byte _d[NUM_LEDS]; int _x(int i){ if((i/COLS)%2==1){ return i%COLS; }else{ return COLS-i%COLS-1; } } int _y(int i){ return i/COLS; } //Afstand en hoek tot middelpunt berekenen en opslaan in byte array. //Het kost geheugen, maar wint snelheid bij het genereren van patronen. void generateMap(){ float cX=(COLS-1)/2.0; float cY=(ROWS-1)/2.0; float dMax=sqrt(cX*cX+cY*cY); for(int i = 0; i<NUM_LEDS;i++){ _d[i]=sqrt(sq(cX-_x(i))+sq(cY-_y(i)))/dMax*255; //Pythagoras _r[i]=(atan2(cY-_y(i),cX-_x(i))+PI)*255/(2*PI); } } void setup() { FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS); //initialiseren FastLED.setBrightness(25); generateMap(); } void loop() { unsigned long t = millis(); for(int i=0; i<NUM_LEDS; i++){ leds[i].r=max(0,sin8(_d[i]-t/5)*3-255*2); leds[i].g=max(0,sin8(_r[i]-t/5)*10-255*9); } FastLED.show(); }
Bewegende bollen
#include "FastLED.h" #define DATA_PIN 15 #define LED_TYPE WS2812 #define COLOR_ORDER GRB //kleurvolgorde. Rood,Groen,Blauw / Groen,Rood,Blauw #define NUM_LEDS 256 #define COLS 16 #define ROWS 16 CRGB leds[NUM_LEDS]; int _x(int i){ if((i/COLS)%2==1){ return i%COLS; }else{ return COLS-i%COLS-1; } } int _y(int i){ return i/COLS; } uint32_t approx_distance( int32_t dx, int32_t dy ) { //return(sqrt(dx*dx+dy*dy)); //Source:https://www.flipcode.com/archives/Fast_Approximate_Distance_Functions.shtml uint32_t min, max, approx; if ( dx < 0 ) dx = -dx; if ( dy < 0 ) dy = -dy; if ( dx < dy ) { min = dx; max = dy; } else { min = dy; max = dx; } approx = ( max * 1007 ) + ( min * 441 ); if ( max < ( min << 4 )) approx -= ( max * 40 ); // add 512 for proper rounding return (( approx + 512 ) >> 10 ); } void setup() { FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS); //initialiseren FastLED.setBrightness(25); } void loop() { unsigned long t = millis(); int amp=32; for(byte j=0; j<3;j++){ int cX=(COLS-1)*amp/2 + (cos8(t/(7+j)+j*85)-127)*3/2*sin(t/(1000.0+j*50)); int cY=(ROWS-1)*amp/2 + (sin8(t/(7+j)+j*85)-127)*3/2*sin(t/(1000.0+j*50)); for(int i=0; i<NUM_LEDS; i++){ byte value=255-min(255,approx_distance(_x(i)*amp-cX,_y(i)*amp-cY)*3/2); if(j==0)leds[i].r=value; if(j==1)leds[i].g=value; if(j==2)leds[i].b=value; } } FastLED.show(); }
Bewegende bollen met staart
#include "FastLED.h" #define DATA_PIN 15 #define LED_TYPE WS2812 #define COLOR_ORDER GRB //kleurvolgorde. Rood,Groen,Blauw / Groen,Rood,Blauw #define NUM_LEDS 256 #define COLS 16 #define ROWS 16 CRGB leds[NUM_LEDS]; int _x(int i){ if((i/COLS)%2==1){ return i%COLS; }else{ return COLS-i%COLS-1; } } int _y(int i){ return i/COLS; } uint32_t approx_distance( int32_t dx, int32_t dy ) { //return(sqrt(dx*dx+dy*dy)); //Source:https://www.flipcode.com/archives/Fast_Approximate_Distance_Functions.shtml uint32_t min, max, approx; if ( dx < 0 ) dx = -dx; if ( dy < 0 ) dy = -dy; if ( dx < dy ) { min = dx; max = dy; } else { min = dy; max = dx; } approx = ( max * 1007 ) + ( min * 441 ); if ( max < ( min << 4 )) approx -= ( max * 40 ); // add 512 for proper rounding return (( approx + 512 ) >> 10 ); } void setup() { FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS); //initialiseren FastLED.setBrightness(25); } void loop() { unsigned long t = millis(); int amp=32; for(byte j=0; j<3;j++){ int cX=(COLS-1)*amp/2+(cos8(t/(10)+j*85)-127)*(sin(t/215.0)+2.75)/2; int cY=(ROWS-1)*amp/2+(sin8(t/(10)+j*85)-127)*(sin(t/215.0)+2.75)/2; for(int i=0; i<NUM_LEDS; i++){ byte value=255-min(255,approx_distance(_x(i)*amp-cX,_y(i)*amp-cY)*3); CRGB color = CHSV(t/40+j*85,255,value); leds[i].r+=max(0,color.r-leds[i].r); leds[i].g+=max(0,color.g-leds[i].g); leds[i].b+=max(0,color.b-leds[i].b); if(j==2){ leds[i].r=max(0,leds[i].r-3); leds[i].g=max(0,leds[i].g-3); leds[i].b=max(0,leds[i].b-3); } } } FastLED.show(); }
Code voorbeelden 3D
InfinityCube 3D pixelmapping
Geen code, maar wel een goed voorbeeld.
Technieken
Zie hier een aantal technieken die erg handing zijn bij het maken van patronen.
Geen delay()!
- Tijdens delay() staat de processor te wachten. In deze tijd doet de processor effectief NIKS.
- De delay() functie is blocking.
- Gebruik de millis() functie voor het maken van een non blocking timer.
- FastLED timingfuncties
FastLED timingfuncties
- EVERY_N_MILLISECONDS(){}
- EVERY_N_SECONDS(){}
- Non blocking
EVERY_N_MILLISECONDS()
Een led laten knipperen met delay()
:
bool state = false; void loop(){ leds[0]=CRGB(255*state,0,0); //state==true -> rood state==false -> zwart FastLED.show(); state = !state; //inverteren delay(500); }
Een led laten knipperen met EVERY_N_MILLISECONDS()
en tegenlijktijdig iets anders doen:
bool state = false; void loop(){ EVERY_N_MILLISECONDS(500){ //Een actie elke 500ms uitvoeren leds[0]=CRGB(255*state,0,0); //state==true -> rood state==false -> zwart FastLED.show(); state = !state; //inverteren } EVERY_N_MILLISECONDS(100){ //Een 2e actie elke 100ms uitvoeren in "parallel" Serial.println(millis()); } }
Vergelijkbaar gedrag, maar dan met millis()
.
bool state = false; unsigned long tOld = 0; void loop(){ if(millis()-tOld>=500){ tOld=millis(); leds[0]=CRGB(255*state,0,0); //state==true -> rood state==false -> zwart FastLED.show(); state = !state; //inverteren } }
Geen floating point
- Snelheidswinst
Integer overflow
- Regenboog
FastLED integer wiskundige functies
- Gebruik de 8-bit of 16-bit sinusfunctie
sin8()
sin16()
van FastLED in plaats vansin()
. Deze gebruiken geen floating-point getallen en zijn veel sneller.
Pixel mapping
Projecten met FastLED
Projecten waarbij de FastLED library is gebruikt:
Project met Adafruit Neopixel library:
Video's
Playlists:
Videos: