resources:fastled_effecten

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

Adresseerbare leds zijn te verkrijgen in vele types en uitvoeringen. Hieronder staan de meestgebruikte types en uitvoeringen beschreven.

Strips, panelen, neon, ronde led, FCOB

Shops met kwalitatieve led-strips en groot assortiment:

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

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
}
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();
}

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
}

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();
}

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();
}

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();
}

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();
  }
}

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();
  }
}

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;
    }
  }
}

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();
  }
}

Klik op de afbeelding om het voorbeeld te bekijken. Deze zijn allemaal geschikt om op een Arduino Uno te draaien.

Afstand+hoek (LUT)
Bewegende bollen
Bewegende bollen met staart

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();
}

#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();
}

#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();
}

Geen code, maar wel een goed voorbeeld.

Zie hier een aantal technieken die erg handing zijn bij het maken van patronen.

  • 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
  • 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
  }
}
  • Snelheidswinst
  • Regenboog
  • Gebruik de 8-bit of 16-bit sinusfunctie sin8() sin16() van FastLED in plaats van sin(). Deze gebruiken geen floating-point getallen en zijn veel sneller.

Projecten waarbij de FastLED library is gebruikt:

Project met Adafruit Neopixel library:

  • resources/fastled_effecten.txt
  • Last modified: 04/10/2023 14:38
  • by ron