Prácticas con FastLED&Esp32&Blynk

fill_solid (struct CRGB *leds, int numToFill, const struct CRGB &color)/CHSV&color)

El formato demo sería:

  • fill_solid(leds, NUM_LEDS, CRGB(255,0,0));— formato RGB
  • fill_solid(leds, NUM_LEDS, CHSV(0,255,255)); formato HSV

Vamos a empezar con la función fill_solid .Pulsaremos el boton de la app para ir cambiando los colores. Con V1 en formato RGB y con V2 en formato HSV. Los valores de brillo o intensidad estarán controlador por la variable slidert2.

Si usamos valores menores de 255, el recorrido maximo del slidert2 será el valor declarado.

Recordatorio valores CHSV

  • HUE_RED = 0,
  • HUE_ORANGE = 32, 
  • HUE_YELLOW = 64,
  • HUE_GREEN = 96,
  • HUE_AQUA = 128, 
  • HUE_BLUE = 160,
  • HUE_PURPLE = 192, 
  • HUE_PINK = 224

 #include <OneButton.h> 
#define BTN_PIN   15  //  pin virtual V6 asociado a GPio 15 con valor=1 en reposo y valor 0 en activo,equivalente a dar GND al pulsar
......
OneButton btn = OneButton(BTN_PIN, true, true);
....
void setup(){
.....
btn.attachClick(nextPattern);
....
}
void loop(){
....

 

btn.tick();

} 

sketch completo:

#include <FastLED.h>
#include <OneButton.h>
#define PIN_LEFT     13
#define PIN_RIGHT     14
#define NUM_LEDS    140
#define BTN_PIN   15 
CRGB leds[NUM_LEDS];
#include "SPI.h"
#include "TFT_eSPI.h"
#define TFT_GREY 0x7BEF
// Use hardware SPI
TFT_eSPI tft = TFT_eSPI();
 #include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>

char auth[] = "1mepQ9UdDKFOkOxw8fqpqkyChIJYyDB7";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "atom_2.4g";
char pass[] = "crixalcfilos";



///////////////////////////////////////////////////////////////////////////////////////////////////
uint8_t patternCounter = 0;
uint8_t hue = 0;
int v1;
int v2;
int slidert1;
int slidert2;
int stepper;
///////////////////////////////////////////////////////////////////////////////////////


BlynkTimer timer1; // Announcing the timer1
void Readvalue()
{
//int  v3 = readvalue;         // declaramos una variable que tiene la información requerida
//  Blynk.virtualWrite(V3, v3);  //
}

BLYNK_WRITE(V0){
  slidert1=param.asInt();
}
BLYNK_WRITE(V1){//paralelo
  v1 = param.asInt();
}
  BLYNK_WRITE(V2){
  v2 = param.asInt(); 
  }
  BLYNK_WRITE(V4){
 slidert2 = param.asInt(); 
  }
  BLYNK_WRITE(V5){
 stepper = param.asInt(); 
  }
 

//pin virtual V6 asociado a GPio 15 con valor=1 en reposo y valor 0 en activo,equivalente
//a dar GND al pulsar
OneButton btn = OneButton(BTN_PIN, true, true);


void nextPattern() {
  patternCounter = (patternCounter + 1) % 4; 
}

void setup() {
 //pinMode(15,INPUT); 
 Blynk.begin(auth, ssid, pass);
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_WHITE);  // color de texto en blanco
  tft.setTextSize(3);     // escala de texto en 2
  tft.setCursor(100, 100);    // ubica cursor en esquina superior izquierda
  tft.print("FastLED");  // imprime texto
  FastLED.addLeds<NEOPIXEL, PIN_LEFT>(leds, NUM_LEDS);
  FastLED.addLeds<NEOPIXEL, PIN_RIGHT>(leds, NUM_LEDS);
  FastLED.setBrightness(10);
 FastLED.clear();
FastLED.show();
      Serial.begin(9600);
 btn.attachClick(nextPattern); 
//timer1.setInterval(1000L, Readvalue); //timer will run every sec
}
 

void loop() {
     Blynk.run();
      FastLED.setBrightness(slidert2);
  // timer1.run();
  if  (v1==1){
 switch (patternCounter) {
    case 0:
      fill_solid(leds, NUM_LEDS, CRGB(255,0,0));  // fill red
      break;
    case 1:
     fill_solid(leds, NUM_LEDS, CRGB(0,255,0));  // fill green
      break;
    case 2:
      fill_solid(leds, NUM_LEDS, CRGB(0,0,255));  // fill blue
      break;
      case 3:
       fill_solid(leds, NUM_LEDS, CRGB(255,255,255));  // fill white
      break;
  }

 FastLED.show();
 btn.tick();
  }
  else if (v1==0&&v2==0){  FastLED.clear();   FastLED.show();
}
 if  (v2==1){
  switch (patternCounter) {
    case 0:
      fill_solid(leds, NUM_LEDS, CHSV(0,255,255));  //red
      break;
    case 1:
     fill_solid(leds, NUM_LEDS, CHSV(96,255,255));  //green
      break;
    case 2:
      fill_solid(leds, NUM_LEDS, CHSV(128,255,255)); //aqua
      break;
      case 3:
       fill_solid(leds, NUM_LEDS, CHSV(160,255,255)); //blue 
  }

 FastLED.show();
 btn.tick();
 }
  }
 

  

fill_palette  

En esta demo vamos a ver como funcionan las paletas de colores y como expresarlas en el sketch. He querido poner dos paletas diferentes en cada condicional V1 y V2, Fijémosnos donde se definen y su formato:

fill_palette(leds, NUM_LEDS, paletteIndex, 255 / NUM_LEDS, purplePalette, 255, LINEARBLEND);

fill_palette(leds, NUM_LEDS, paletteIndex, 255 / NUM_LEDS, BluePalette, 255, LINEARBLEND);

uint8_t paletteIndex = 0;
......

void loop(){
....
if  (v1==1){
  fill_palette(leds, NUM_LEDS, paletteIndex, 255 / NUM_LEDS, purplePalette, 255, LINEARBLEND);
  
  EVERY_N_MILLISECONDS(10){
    paletteIndex++;
  }
  FastLED.show(); 
   }
   
  else if (v1==0&&v2==0){  FastLED.clear();   FastLED.show();
}
 if  (v2==1){
 fill_palette(leds, NUM_LEDS, paletteIndex, 255 / NUM_LEDS, BluePalette, 255, LINEARBLEND);
  
  EVERY_N_MILLISECONDS(10){
    paletteIndex++;
  }

sketch completo

#include <FastLED.h>
#include <OneButton.h>
#define PIN_LEFT     13
#define PIN_RIGHT     14
#define NUM_LEDS    140
#define BTN_PIN   15 
CRGB leds[NUM_LEDS];
CRGB background[NUM_LEDS];
#include "SPI.h"
#include "TFT_eSPI.h"
#define TFT_GREY 0x7BEF
// Use hardware SPI
TFT_eSPI tft = TFT_eSPI();
 #include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>

char auth[] = "1mepQ9UdDKFOkOxw8fqpqkyChIJYyDB7";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "atom_2.4g";
char pass[] = "crixalcfilos";

//////////////////////////////////palettes/////////////////////////////////
uint8_t paletteIndex = 0;

CRGBPalette16 purplePalette = CRGBPalette16 (
    CRGB::DarkViolet,
    CRGB::DarkViolet,
    CRGB::DarkViolet,
    CRGB::DarkViolet,
    
    CRGB::Magenta,
    CRGB::Magenta,
    CRGB::Linen,
    CRGB::Linen,
    
    CRGB::Magenta,
    CRGB::Magenta,
    CRGB::DarkViolet,
    CRGB::DarkViolet,

    CRGB::DarkViolet,
    CRGB::DarkViolet,
    CRGB::Linen,
    CRGB::Linen
);
CRGBPalette16 BluePalette = CRGBPalette16 (

    CRGB::Blue,
    CRGB::DarkBlue,
    CRGB::DarkBlue,
    CRGB::DarkBlue,
    CRGB::DarkBlue,
    CRGB::DarkBlue,
    CRGB::DarkBlue,
    CRGB::DarkBlue,
    CRGB::Blue,
    CRGB::DarkBlue,
    CRGB::SkyBlue,
    CRGB::SkyBlue,
    CRGB::LightBlue,
    CRGB::White,
    CRGB::LightBlue,
    CRGB::SkyBlue
);

///////////////////////////////////////////////////////////////////////////////////////////////////
uint8_t patternCounter = 0;
uint8_t hue = 0;
int v1;
int v2;
int slidert1;
int slidert2;
int stepper;
///////////////////////////////////////////////////////////////////////////////////////


BlynkTimer timer1; // Announcing the timer1
void Readvalue()
{
//int  v3 = readvalue;         // declaramos una variable que tiene la información requerida
//  Blynk.virtualWrite(V3, v3);  //
}

BLYNK_WRITE(V0){
  slidert1=param.asInt();
}
BLYNK_WRITE(V1){//paralelo
  v1 = param.asInt();
}
  BLYNK_WRITE(V2){
  v2 = param.asInt(); 
  }
  BLYNK_WRITE(V4){
 slidert2 = param.asInt(); 
  }
  BLYNK_WRITE(V5){
 stepper = param.asInt(); 
  }
 

//pin virtual V6 asociado a GPio 15 con valor=1 en reposo y valor 0 en activo,equivalente
//a dar GND al pulsar
OneButton btn = OneButton(BTN_PIN, true, true);


void nextPattern() {
  patternCounter = (patternCounter + 1) % 4; 
}

void setup() {
 //pinMode(15,INPUT); 
 Blynk.begin(auth, ssid, pass);
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_WHITE);  // color de texto en blanco
  tft.setTextSize(3);     // escala de texto en 2
  tft.setCursor(100, 100);    // ubica cursor en esquina superior izquierda
  tft.print("FastLED");  // imprime texto
  FastLED.addLeds<NEOPIXEL, PIN_LEFT>(leds, NUM_LEDS);
  FastLED.addLeds<NEOPIXEL, PIN_RIGHT>(leds, NUM_LEDS);
  FastLED.setBrightness(10);
 FastLED.clear();
FastLED.show();
      Serial.begin(9600);
 btn.attachClick(nextPattern); 
//timer1.setInterval(1000L, Readvalue); //timer will run every sec
}
 

void loop() {
     Blynk.run();
      FastLED.setBrightness(slidert2);
  // timer1.run();
  if  (v1==1){
  fill_palette(leds, NUM_LEDS, paletteIndex, 255 / NUM_LEDS, purplePalette, 255, LINEARBLEND);
  
  EVERY_N_MILLISECONDS(10){
    paletteIndex++;
  }
  FastLED.show(); 
   }
   
  else if (v1==0&&v2==0){  FastLED.clear();   FastLED.show();
}
 if  (v2==1){
 fill_palette(leds, NUM_LEDS, paletteIndex, 255 / NUM_LEDS, BluePalette, 255, LINEARBLEND);
  
  EVERY_N_MILLISECONDS(10){
    paletteIndex++;
  }
  FastLED.delay(slidert1);
 //btn.tick();
 }
}

  




  
  • Definiendo un gradiente: Declaro dos formas de expresar el gradient_palette, y dos formas diferentes de presentar con cada condicional, V1 y V2
......
uint8_t colorIndex[NUM_LEDS];

DEFINE_GRADIENT_PALETTE( greenblue_gp ) { 
  0,   0,  255, 245,
  46,  0,  21,  255,
  179, 12, 250, 0,
  255, 0,  255, 245
};

CRGBPalette16 greenblue = greenblue_gp;
.....

uint8_t paletteIndex = 0;

DEFINE_GRADIENT_PALETTE (heatmap_gp) {
    0,   0,   0,   0,   //black
  128, 255,   0,   0,   //red
  200, 255, 255,   0,   //bright yellow
  255, 255, 255, 255    //full white 
};

CRGBPalette16 myPal = heatmap_gp;
void loop() {
     Blynk.run();
      FastLED.setBrightness(slidert2);
  // timer1.run();
  if  (v1==1){
   // Color each pixel from the palette using the index from colorIndex[]
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = ColorFromPalette(greenblue, colorIndex[i]);
  }
  
  EVERY_N_MILLISECONDS(5){
    for (int i = 0; i < NUM_LEDS; i++) {
      colorIndex[i]++;
    }
  }
  FastLED.delay(slidert1);
   }
   
  else if (v1==0&&v2==0){  FastLED.clear();   FastLED.show();
}
 if  (v2==1){
 fill_palette(leds, NUM_LEDS, paletteIndex, 255 / NUM_LEDS, myPal, 255, LINEARBLEND);
  
  EVERY_N_MILLISECONDS(10){
    paletteIndex++;
  }
  
  
  FastLED.delay(slidert1);
 //btn.tick();
 }
}

Sunset demo

uint8_t paletteIndex = 0;

// Gradient palette "Sunset_Real_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Sunset_Real.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 28 bytes of program space.

DEFINE_GRADIENT_PALETTE( Sunset_Real_gp ) {
    0, 120,  0,  0,
   22, 179, 22,  0,
   51, 255,104,  0,
   85, 167, 22, 18,
  135, 100,  0,103,
  198,  16,  0,130,
  255,   0,  0,160};


CRGBPalette16 myPal = Sunset_Real_gp;
if  (v1==1){
    fill_palette(leds, NUM_LEDS, paletteIndex, 255 / NUM_LEDS, myPal, 255, LINEARBLEND);
  
  EVERY_N_MILLISECONDS(10){
    paletteIndex++;
  }
  
  FastLED.delay(slidert1);// de 0-20, velocidad de cambio
   }

fill_gradient(T*array,uint16_t startpos,CHSV startcolor,uint16_t endpos,CHSV endcolor,TGradientDirectionCode)

Ejemplo:

fill_gradient(leds, 0, CHSV(0,255,255), NUM_LEDS-1, CHSV(128,255,255), SHORTEST_HUES);

T*array=leds

startpos=0

startcolor= CHSV(0,255,255)—rojo

endpos=NUM_LEDS

endpos= achsv(128,255,255)—aqua

TGradientDirectionCode =SHORTEST_HUES

TGradientDirectionCode

Fill_gradient: rellena un array de colores con un degradado suave de HSV entre dos colores de HSV especificados.

Dado que el ‘tono’ es un valor alrededor de una rueda de colores, siempre hay dos formas de pasar de un tono a otro. Esta función le permite especificar de qué manera desea que el degradado de tono se desplace por la rueda de colores:

FORWARD_HUES: el tono siempre va en el sentido de las agujas del reloj
BACKWARD_HUES: el tono siempre va en sentido contrario a las agujas del reloj
SHORTEST_HUES: el tono va de la forma más corta
LONGEST_HUES: el tono va de la forma más larga
El valor predeterminado es SHORTEST_HUES, ya que esto es casi siempre lo que se desea.


Haciendo uso de la plantilla, expongo solo el void loop()

Con la condicional v1=1 tenemos un ejemplo de gradiente entre HUE red y HUE aqua

Con la condicion V2=1 tenemos un gradiente usando RGB entre el rojo y el verde


void loop() {
     Blynk.run();
      FastLED.setBrightness(slidert2);
  // timer1.run();
  if  (v1==1){
 fill_gradient(leds, 0, CHSV(0,255,255), NUM_LEDS-1, CHSV(128,255,255), SHORTEST_HUES);

 FastLED.show();
// btn.tick();
  }
  else if (v1==0&&v2==0){  FastLED.clear();   FastLED.show();
}
 if  (v2==1){
  fill_gradient_RGB(leds, 0, CRGB(255,0,0), NUM_LEDS-1, CRGB(0,255,0));
 FastLED.show();
 //btn.tick();
 }
  }
 
  • fill_gradient animado: jugando con stepper ( 0-50) y slidert1(0-5000)
if  (v2==1){
  EVERY_N_MILLISECONDS(250) {
     hue+=stepper;
  }    
  fill_gradient(leds, 0, CHSV(hue,random8(100,256),255) , NUM_LEDS-1, CHSV(hue +120,random8(180,256),255), SHORTEST_HUES);
 FastLED.delay(slidert1);
 //btn.tick();
 }
  }
  • Tribanda
EVERY_N_MILLISECONDS(250) {
     hue+=stepper;
  }    
  fill_gradient(leds, 0, CHSV(hue,random8(100,256),255) , 40, CHSV(hue +80,random8(180,256),255), SHORTEST_HUES);
   fill_gradient(leds, 50, CHSV(hue,random8(100,256),255) , 90, CHSV(hue +100,random8(180,256),255), SHORTEST_HUES);
  fill_gradient(leds, 100, CHSV(hue,random8(100,256),255) ,NUM_LEDS, CHSV(hue +120,random8(180,256),255), SHORTEST_HUES);
  FastLED.delay(slidert1);

fill_rainbow (struct CRGB *pFirstLED, int numToFill, uint8_t initialhue, uint8_t deltahue=5)

Vamos a formar un bonito arcoiris entre 0 y NUM_LEDS , el valor 255/NUM_LEDS se define porque para espaciar adecuadamente los colores debe ser un valor 2-3

fill_rainbow(leds, NUM_LEDS, 0,255/NUM_LEDS);

Arcoiris animado sin usar la funcion fill_rainbow:

simple y de efectos muy bonitos

for (int i = 0; i < NUM_LEDS; i++) {
       leds[i] = CHSV(hue + (i*stepper ), 255, 255);
   }
    hue++;
  FastLED.delay(slidert1);

Para apreciar estos efectos,que van desde un aparente latido hasta un movimiento armonioso de colores, las variables utilizadas deben estar en los siguientes valores:

stepper: de 0 a 10,,

slidert1: de 10 a 0

slidert2: de 10 a 20

#include <FastLED.h>
#include <OneButton.h>
#define PIN_LEFT     13
#define PIN_RIGHT     14
#define NUM_LEDS    140
#define BTN_PIN   15 
CRGB leds[NUM_LEDS];
#include "SPI.h"
#include "TFT_eSPI.h"
#define TFT_GREY 0x7BEF
// Use hardware SPI
TFT_eSPI tft = TFT_eSPI();
 #include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>

char auth[] = "1mepQ9UdDKFOkOxw8fqpqkyChIJYyDB7";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "atom_2.4g";
char pass[] = "crixalcfilos";



///////////////////////////////////////////////////////////////////////////////////////////////////
uint8_t patternCounter = 0;
uint8_t hue = 0;
int v1;
int v2;
int slidert1;
int slidert2;
int stepper;
///////////////////////////////////////////////////////////////////////////////////////


BlynkTimer timer1; // Announcing the timer1
void Readvalue()
{
//int  v3 = readvalue;         // declaramos una variable que tiene la información requerida
//  Blynk.virtualWrite(V3, v3);  //
}

BLYNK_WRITE(V0){
  slidert1=param.asInt();
}
BLYNK_WRITE(V1){//paralelo
  v1 = param.asInt();
}
  BLYNK_WRITE(V2){
  v2 = param.asInt(); 
  }
  BLYNK_WRITE(V4){
 slidert2 = param.asInt(); 
  }
  BLYNK_WRITE(V5){
 stepper = param.asInt(); 
  }
 

//pin virtual V6 asociado a GPio 15 con valor=1 en reposo y valor 0 en activo,equivalente
//a dar GND al pulsar
OneButton btn = OneButton(BTN_PIN, true, true);


void nextPattern() {
  patternCounter = (patternCounter + 1) % 4; 
}

void setup() {
 //pinMode(15,INPUT); 
 Blynk.begin(auth, ssid, pass);
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_WHITE);  // color de texto en blanco
  tft.setTextSize(3);     // escala de texto en 2
  tft.setCursor(100, 100);    // ubica cursor en esquina superior izquierda
  tft.print("FastLED");  // imprime texto
  FastLED.addLeds<NEOPIXEL, PIN_LEFT>(leds, NUM_LEDS);
  FastLED.addLeds<NEOPIXEL, PIN_RIGHT>(leds, NUM_LEDS);
  FastLED.setBrightness(10);
 FastLED.clear();
FastLED.show();
      Serial.begin(9600);
 btn.attachClick(nextPattern); 
//timer1.setInterval(1000L, Readvalue); //timer will run every sec
}
 

void loop() {
     Blynk.run();
      FastLED.setBrightness(slidert2);
  // timer1.run();
  if  (v1==1){
 for (int i = 0; i < NUM_LEDS; i++) {
       leds[i] = CHSV(hue + i, 255, 255);
   }
    hue++;
  FastLED.delay(slidert1);
   }
   
  else if (v1==0&&v2==0){  FastLED.clear();   FastLED.show();
}
 if  (v2==1){
  for (int i = 0; i < NUM_LEDS; i++) {
       leds[i] = CHSV(hue + (i*stepper ), 255, 255);
   }
    hue++;
  FastLED.delay(slidert1);
 //btn.tick();
 }
  }
 

  

void loop() {
   Blynk.run();
 //   FastLED.clear();
 //   FastLED.show();
   FastLED.setBrightness(slidert2);
  
  if  (v1==1){

    //para strips mas largas usar uit16_t
  // Waves for LED position
 // uint8_t posBeat  = beatsin8(30, 0, NUM_LEDS - 1, 0, 0);
 // uint8_t posBeat2 = beatsin8(60, 0, NUM_LEDS - 1, 0, 0);
  //uint8_t posBeat3 = beatsin16(30, 0, NUM_LEDS - 1, 0, 127);
  //uint8_t posBeat4 = beatsin16(60, 0, NUM_LEDS - 1, 0, 127);


   // the resolution isn't high enough for position and can lead to some
  // LEDs not lighting. If this is the case, use the 16 bit versions below
  //la variable stepper nos va a dar la velocidad de rebote
   uint16_t posBeat  = beatsin16(stepper, 0, NUM_LEDS - 1, 0, 0);
   uint16_t posBeat2 = beatsin16(stepper*2, 0, NUM_LEDS - 1, 0, 0);
 uint16_t posBeat3 = beatsin16(stepper, 0, NUM_LEDS - 1, 0, 32767);
   uint16_t posBeat4 = beatsin16(stepper*2, 0, NUM_LEDS - 1, 0, 32767);

  // Wave for LED color
  
  leds[(posBeat + posBeat2) / 2]  = CHSV(slidert2, 255, 255);
  leds[(posBeat3 + posBeat4) / 2]  = CHSV(slidert2, 255, 255);

//cantidad de leds que van a rebotar ( aprox con slidert1=100 van a apreciarse solo un led)
  fadeToBlackBy(leds, NUM_LEDS, slidert1+10);

  FastLED.show();
    }
   
  else if (v1==0){
  FastLED.clear();
   FastLED.show();
}
  } 
 

Beat16()/ fadeToBlackBy() / blur1d ()

Vamos a poner en práctica estas funciones pra poder entenderlas y lograr algunos efectos interesantes.

beat16 (accum88 beats_per_minute, uint32_t timebase=0)
beat16 generates a 16-bit ‘sawtooth’ wave at a given BPM
accum88
 ANSI: unsigned short _Accum. 8 bits int, 8 bits fraction.
  • beat16() genera una onda en diente de sierra entre los valores 0 a 65535 a un ritmo dado por la variable BPM ,,beats por minuto.. Para comprobar los efectos de su variación,asignaremos la variable stepper de la App de Blynk:

 int bpm=stepper// 0-50 en pasos de 10
este ajuste influirá en la equidistancia de los segmentos

El formato de la función sería: beat16(bpm,timebase=0).

El timebase representa el origen de la onda en diente de sierra,partiendo de 0. En el ejemplo se se han hecho 5 divisiones iguales de 65535 (0, 1/5, 2/5, 3/5, 4/5), de forma que las ondas se vayan generando desfasadas en tiempos iguales.

  • fadeToBlackBy (CRGB *leds, uint16_t num_leds, uint8_t fadeBy)

Esta función nos posibilita generar una estela final de la onda con el desvanecimiento de los leds segun el valor de la variable slidert1 controlada desde la App Blynk con un rango entre 0y 20. Con 0 no habría desvanecimiento. Esta función puede ir dentro de:


 fadeToBlackBy( leds, NUM_LEDS, slidert1);  // Fade out pixels 



EVERY_N_MILLISECONDS( 5 ) { 

fadeToBlackBy( leds, NUM_LEDS, slidert1); 

}
  • blur1d (CRGB *leds, uint16_t numLeds, fract8 blur_amount)

Esta función nos permite generar un efecto de desintegración

fract8 blur_amount …….el valor que utilizo por defecto es de 97 que da la maxima desintegración
uint8_t fract8
ANSI unsigned short _Fract
range is 0 to 0.99609375 in steps of 0.00390625

.En la demo declaro juntas estas dos funciones, que dan un efecto completo a cada segmento,desintegrando por arriba y desvaneciendo por debajo

fadeToBlackBy( leds, NUM_LEDS, slidert1);  // Fade out pixels 
blur1d(leds, NUM_LEDS, 97);//95-100 
  • Otro aspecto a resaltar en el sketch es este:


uint16_t pos1 =map( beat16(bpm,0),0,65535,0,NUM_LEDS); 

 Se mapea el función diente de sierra a los valores 0,NUM_LEDS,para poder adaptar la onda al rango de nuestro numero de leds.

El cambio de tonalidades se logra de nuevo con:

......

leds[pos1] = CHSV( hue, 200, 255);
  leds[pos2] = CHSV( hue*2, 200, 255);
  leds[pos3] = CHSV( hue*3, 200, 255);
  leds[pos4] = CHSV( hue*4, 200, 255);
  leds[pos5] = CHSV( hue*5, 200, 255);



EVERY_N_MILLISECONDS( 50 ) { 
    hue++;
    } //lento cambio de matiz

   Blynk.run();
      FastLED.setBrightness(slidert2);
 
  if  (v1==1){
    int bpm=stepper;// 0-50  en pasos de 10
   uint16_t pos1 =map( beat16(bpm,0),0,65535,0,NUM_LEDS); 
   uint16_t  pos2 =map( beat16(bpm,13107),0,65535,0,NUM_LEDS);
    uint16_t pos3 =map( beat16(bpm,26214),0,65535,0,NUM_LEDS);
    uint16_t pos4 =map( beat16(bpm,39321),0,65535,0,NUM_LEDS);
    uint16_t pos5 =map( beat16(bpm,52428),0,65535,0,NUM_LEDS); 
    
  leds[pos1] = CHSV( hue, 200, 255);
  leds[pos2] = CHSV( hue*2, 200, 255);
  leds[pos3] = CHSV( hue*3, 200, 255);
  leds[pos4] = CHSV( hue*4, 200, 255);
  leds[pos5] = CHSV( hue*5, 200, 255);
 
EVERY_N_MILLISECONDS( 50 ) { 
    hue++;
    } //lento cambio de matiz


    fadeToBlackBy( leds, NUM_LEDS, slidert1);  // Fade out pixels 
     blur1d(leds, NUM_LEDS, 97);//95-100 
    

  FastLED.show();   
   }
   

Mezcla (Blend)

CRGB blend (const CRGB &p1, const CRGB &p2, fract8 amountOfP2)
 
CHSV blend (const CHSV &p1, const CHSV &p2, fract8 amountOfP2, TGradientDirectionCode directionCode=SHORTEST_HUES)
 
CRGB * blend (const CRGB *src1, const CRGB *src2, CRGB *dest, uint16_t count, fract8 amountOfsrc2)
 
CHSV * blend (const CHSV *src1, const CHSV *src2, CHSV *dest, uint16_t count, fract8 amountOfsrc2, TGradientDirectionCode directionCode=SHORTEST_HUES)
 
CRGB & nblend (CRGB &existing, const CRGB &overlay, fract8 amountOfOverlay)
 
CHSV & nblend (CHSV &existing, const CHSV &overlay, fract8 amountOfOverlay, TGradientDirectionCode directionCode=SHORTEST_HUES)
 
void nblend (CRGB *existing, CRGB *overlay, uint16_t count, fract8 amountOfOverlay)
 
void nblend (CHSV *existing, CHSV *overlay, uint16_t count, fract8 amountOfOverlay, TGradientDirectionCode directionCode=SHORTEST_HUES)

Demo1: sencillo ejemplo definiendo valores en el formato RGB Y CHSV

En esta demo declaramos CRGB colorCurrent como una variable que contiene la función blend definiendo un color de inicio (Red) y un color objetivo(Yellow) como color final de lla mezcla segun la variable de 8bit amountblend que ira incrementándose hasta su valor máximo 255 para volver a empezar de cero

Usando fill_solid apreciaremos el color naranja convirtiendose en amarillo.segun la velocidad controlada con FastLED.delay(), slidert1 tomara valores entre 0 y 20 desde la APP Blynk.

uint8_t amountblend=0
void loop(){
....
if  (v1==1){
    
    //blend (const CRGB &p1, const CRGB &p2, fract8 amountOfP2)

  CRGB colorCurrent=blend(CRGB::Red, CRGB::Yellow, amountblend);
  fill_solid( leds, NUM_LEDS, colorCurrent );
amountlbend++
  FastLED.delay(slidert1);
 
   }
if  (v2==1){
//CHSV blend (const CHSV &p1, const CHSV &p2, fract8 amountOfP2, //TGradientDirectionCode directionCode=SHORTEST_HUES)

CHSV colorCurrent=blend(CHSV (0,255,255), CHSV (64,255,255), amountblend,SHORTEST_HUES);
  fill_solid( leds, NUM_LEDS, colorCurrent );
   amountblend ++;
  FastLED.delay(slidert1);
}

demo :Mezcla de paletas:

uint8_t colorIndex[NUM_LEDS];
uint8_t whichPalette = 0;

DEFINE_GRADIENT_PALETTE( greenblue_gp ) { 
    0,    0,  194,  255,     //light blue
   46,    3,    0,  246,     //dark blue
  176,   55,  222,   70,     //bright green
  255,    0,  194,  255      //light blue
};

DEFINE_GRADIENT_PALETTE( orangepink_gp ) { 
    0,  255,  100,    0,     //orange
   90,  255,    0,  255,     //magenta
  150,  255,  100,    0,     //orange
  255,  255,  100,    0      //orange
};

DEFINE_GRADIENT_PALETTE( browngreen_gp ) { 
    0,    6,  255,    0,     //green
   71,    0,  255,  153,     //bluegreen
  122,  200,  200,  200,     //gray
  181,  110,   61,    6,     //brown
  255,    6,  255,    0      //green
};

CRGBPalette16 currentPalette(greenblue_gp);
CRGBPalette16 targetPalette(orangepink_gp);
if  (v1==1){
    // Color each pixel from the palette using the index from colorIndex[]
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = ColorFromPalette(currentPalette, colorIndex[i]);
  }

  nblendPaletteTowardPalette( currentPalette, targetPalette, 10 );

  switch (whichPalette) {
    case 0:
      targetPalette = orangepink_gp;
      break;
    case 1:
      targetPalette = browngreen_gp;
      break;
     case 2:
      targetPalette = greenblue_gp;
      break;
  }

  EVERY_N_SECONDS(5) {
    whichPalette++;
    if (whichPalette > 2) whichPalette = 0;
    Serial.println(currentPalette[0]);
  }
  
  EVERY_N_MILLISECONDS(5){
    for (int i = 0; i < NUM_LEDS; i++) {
      colorIndex[i]++;
    }
  }
  FastLED.delay(slidert1);//nos dara la velocidad de mezcla recomendado de 0-20
   }

CREAR UN BACKGROUND

Vamos a aprender a usar un background para ,con la funcion nblend(), poder mostrar simultáneamente dos funciones con una gradacion dada por amountoverlay, en el ejemplo 100.

Para generar el background, tenemos que definir en el inicio CRGB background[NUM_LEDS];

y usaremos la funcion fill_solid(background, NUM_LEDS,CHSV(hue2,180,50)); .

«leds» queda definida con La función beat() nos servira de ejemplo con tres leds[pos1] = CRGB:: Red; leds[pos2] = CRGB:: Blue; leds[pos3] = CRGB:: Green;lo que nos ofrecera pequeños segmentos de colores moviendose sobre un fondo cambiante cada 10 seg dado por:

EVERY_N_SECONDS(10){
hue2+=32;
if (hue2>224){hue2=0;}
}

8 saltos de colores con saturación media y brillo no mayor de 50

la función blur1d(leds, NUM_LEDS, 97); nos va a dejar un aspecto de pequeños segmentos ,si no solo aparecerán tres puntos

nblend(leds, background, NUM_LEDS, 20);

  if  (v1==1){
    int bpm=8;// 
   uint16_t pos1 =map( beat16(bpm,0),0,65535,0,NUM_LEDS);
   uint16_t pos2 =map( beat16(bpm,21845),0,65535,0,NUM_LEDS);
   uint16_t pos3 =map( beat16(bpm,43690),0,65535,0,NUM_LEDS);
   leds[pos1] = CRGB:: Red;
 leds[pos2] = CRGB:: Blue;
leds[pos3] = CRGB:: Green;

     blur1d(leds, NUM_LEDS, 97);//95-100 
 EVERY_N_SECONDS(10){
  hue2+=32;
 }
 
 
    fill_solid(background, NUM_LEDS, CHSV(hue2,180,50));
       nblend(leds, background, NUM_LEDS, 100);//amountoverlay=100
 
  FastLED.delay(slidert1);
   }

beatsin16()

 uint16_t beatsin16(accum88 beats_per_minute,
uint16_t lowest = 0,
uint16_t highest = 65535,
uint32_t timebase = 0,
uint16_t phase_offset = 0 
)

beatsin16 genera una onda senoidal de 16 bits a una freq BPM dada, al igual que el diente de sierra, con la salvedad de que ahora no necesitamos mapear la función gracias a su formato de la forma;

  •  beatsin16 (accum88 beats_per_minute, uint16_t lowest=0, uint16_t highest=65535, uint32_t timebase=0, uint16_t phase_offset=0)

unsigned short _Accum. 8 bits int, 8 bits fraction.

En el ejemplo,los valores lowest=0 y highest=65535, se sustituyen del valor minimo 0 leds a al máximo=NUM_LEDS definido, restandole 1 para que no se pierda el efecto rebote al llegar al NUM_LEDS, PUES SI NO EL EFECTO ES DE DESAPARICIÓN.

  • beatsin16(bpm, 0, NUM_LEDS – 1, 0, 0);

El timebase ya lo entendimos arriba, en cuanto al phase_offset (compensación de fase) lo entenderemos definiendo tres ondas desfasadas,segun la razón 65535/3 (0,1/3, 2/3)

int bpm=stepper;
   uint16_t sinBeat   = beatsin16(bpm, 0, NUM_LEDS - 1, 0, 0);
 uint16_t sinBeat2  = beatsin16(bpm, 0, NUM_LEDS - 1, 0, 21845);//  1/3 de 65535
 uint16_t sinBeat3  = beatsin16(bpm, 0, NUM_LEDS - 1, 0, 43690);// 2/3  de 65535

En la siguiente demo vamos a ver la diferencia entre hacer tres divisiones iguales en el timebase (v1==1) o hacerlas en el phase_offset (v2==1).

Con timebase dividido, las ondas se persiguen unas a optras,mientras que la división e en la compensación de fase, el efecto es de ping pong, dando una bella armonía.

void loop() {
     Blynk.run();
      FastLED.setBrightness(slidert2);
  // timer1.run();
  if  (v1==1){//tres divisiones iguales en el timebase
    int bpm=stepper;
   uint16_t sinBeat   = beatsin16(bpm, 0, NUM_LEDS - 1, 0, 0);//stepper entre 2-40
  uint16_t sinBeat2  = beatsin16(bpm, 0, NUM_LEDS - 1, 21845, 0);
 uint16_t sinBeat3  = beatsin16(bpm, 0, NUM_LEDS - 1,43690 , 0);

  leds[sinBeat]   =CHSV( hue, 200, 255);
  leds[sinBeat2]  =CHSV( hue*3, 200, 255);
  leds[sinBeat3]  =CHSV( hue*5, 200, 255);
 
 EVERY_N_MILLISECONDS( 50 ) { 
    hue++;
    } //lento cambio de matiz

 fadeToBlackBy( leds, NUM_LEDS, slidert1);  // Fade out pixels 
     blur1d(leds, NUM_LEDS, 97);//95-100 
 
   
  FastLED.show();
 //btn.tick();  
  }
   
 
 if  (v2==1){//tres divisiones iguales en el phase_offset
  int bpm=stepper;
   uint16_t sinBeat   = beatsin16(bpm, 0, NUM_LEDS - 1, 0, 0);//stepper entre 2-40
  uint16_t sinBeat2  = beatsin16(bpm, 0, NUM_LEDS - 1, 0, 21845);
 uint16_t sinBeat3  = beatsin16(bpm, 0, NUM_LEDS - 1, 0, 43690);

  leds[sinBeat]   =CHSV( hue, 200, 255);
  leds[sinBeat2]  =CHSV( hue*3, 200, 255);
 leds[sinBeat3]  =CHSV( hue*5, 200, 255);
 
 EVERY_N_MILLISECONDS( 50 ) { 
    hue++;
    } //lento cambio de matiz

 fadeToBlackBy( leds, NUM_LEDS, slidert1);  // Fade out pixels 
     blur1d(leds, NUM_LEDS, 97);//95-100 
 
   
  FastLED.show();
 //btn.tick();
}
  else if (v1==0&&v2==0){  FastLED.clear();   FastLED.show();
}
 }

Veamos la siguiente variación para obtener un bonito efecto de rebotes:

 int bpm=stepper;
   uint16_t sinBeat   = beatsin16(bpm, 0, NUM_LEDS - 1, 0, 0);//stepper entre 2-40
   uint16_t sinBeat2   = beatsin16(bpm*2, 0, NUM_LEDS - 1, 0, 0);
  uint16_t sinBeat3  = beatsin16(bpm, 0, NUM_LEDS - 1, 0, 32767);
 uint16_t sinBeat4  = beatsin16(bpm*2, 0, NUM_LEDS - 1, 0, 32767);

  leds[(sinBeat + sinBeat2) / 2]  = CHSV(hue, 255, 255);
  leds[(sinBeat3 + sinBeat4) / 2]  = CHSV(hue*4, 255, 255);
 
 EVERY_N_MILLISECONDS( 50 ) { 
    hue++;
    } //lento cambio de matiz

 fadeToBlackBy( leds, NUM_LEDS, slidert1);  // Fade out pixels 
     blur1d(leds, NUM_LEDS, 97);//95-100 
 
   
  FastLED.show();
 //btn.tick();  

Funciones Noise

.

void fill_noise8 (CRGB *leds, int num_leds, uint8_t octaves, uint16_t x, int scale, uint8_t hue_octaves, uint16_t hue_x, int hue_scale, uint16_t time)
 
void fill_noise16 (CRGB *leds, int num_leds, uint8_t octaves, uint16_t x, int scale, uint8_t hue_octaves, uint16_t hue_x, int hue_scale, uint16_t time, uint8_t hue_shift=0)

fill_noise16 (CRGB *leds, int num_leds, uint8_t octaves, uint16_t x, int scale, uint8_t hue_octaves, uint16_t hue_x, int hue_scale, uint16_t time, uint8_t hue_shift=0)

uint16_t inoise16 (uint32_t x, uint32_t y, uint32_t z)
 
uint16_t inoise16 (uint32_t x, uint32_t y)
 
uint16_t inoise16 (uint32_t x)

demo1; fire_raw_noise8


.......
uint8_t   noiseData[NUM_LEDS];

CRGBPalette16 party = PartyColors_p;

uint8_t   octaveVal   = 2;
uint16_t  xVal        = 0;
int       scaleVal    = 50;
uint16_t  timeVal     = 0;
if  (v1==1){
   timeVal = millis() / 4;

  memset(noiseData, 0, NUM_LEDS);
  fill_raw_noise8(noiseData, NUM_LEDS, octaveVal, xVal, scaleVal, timeVal);
  
  for (int i = 0; i < NUM_LEDS; i++) {
      leds[i] = ColorFromPalette(party, noiseData[i], noiseData[NUM_LEDS - i - 1]);
  }
  
  FastLED.delay(slidert1);
   }

demo2; fire

CRGBPalette16 firePalette = HeatColors_p;
if  (v1==1){
    EVERY_N_MILLISECONDS(5) {
   int  a = millis();
  
  for (int i = 0; i < NUM_LEDS; i++) {

    // 3D noise, x is constant, we move through time on y and z axis
    // The 60 here will change the scale of the effect, lower is smoother
    // higher is more flickery. The time value for z was in the original code
    // as that was a 2D matrix version. I've left it in here as it looks 
    // nice in 1D too!
    uint8_t noise = inoise8 (0 , i * 60 + a , a / 3);

    // Divides 255 by (NUM_LEDS - 1) and subtracts that amount away from 255 to return 
    // a decreasing number each time e.g. for NUM_LEDS = 18, difference between
    // each point is 15, so:
    // i = 0, math = 255
    // i = 1, math = 240
    // i = 2, math = 225
    // ...
    // i = NUM_LEDS, math =  0
    uint8_t math = abs8(i - (NUM_LEDS-1)) * 255 / (NUM_LEDS-1);

    // Take the noise function from earlier and subtract math from it,
    // so the further along the strip you are, the higher palette index you
    // are likely to get. This results in the base of the fire (white, yellow)
    // being at the far end of the strip
    uint8_t index = qsub8 (noise, math);

    // Set the LED color from the palette
    leds[i] = ColorFromPalette (firePalette, index, 255);    
  } 
    } 
  FastLED.delay(slidert1);
   }

demo3: inoise

if  (v1==1){
    uint16_t  x        = 0;
  int       scale    = 10;
  uint16_t  t        = 0;
  
  for (int i = 0; i < NUM_LEDS; i++) {
      uint8_t hue = inoise8(i * scale + x, t);
      leds[i] = CHSV(hue, 255, 255);
  }
  FastLED.delay(slidert1);
   }

demo4: inoise8

uint16_t  x;
int       scale;
uint16_t  t;
  if  (v1==1){
     x = 0;
  t = millis() / 5;
  scale = beatsin8(10, 10, 30);
  
  for (int i = 0; i < NUM_LEDS; i++) {
      uint8_t noise = inoise8(i * scale + x, t);
      uint8_t hue = map(noise, 50, 190, 0, 255);
      leds[i] = CHSV(hue, 255, 255);
  }
  FastLED.delay(slidert1);
   }

demo5: lava

CRGBPalette16  lavaPalette = CRGBPalette16(
  CRGB::DarkRed,  CRGB::Maroon,   CRGB::DarkRed,  CRGB::Maroon,
  CRGB::DarkRed,  CRGB::Maroon,   CRGB::DarkRed,  CRGB::DarkRed,
  CRGB::DarkRed,  CRGB::DarkRed,  CRGB::Red,      CRGB::Orange,
  CRGB::White,    CRGB::Orange,   CRGB::Red,      CRGB::DarkRed
);

uint16_t brightnessScale = 150;
uint16_t indexScale = 100;
for (int i = 0; i < NUM_LEDS; i++) {
    uint8_t brightness = inoise8(i * brightnessScale, millis() / 5);
    uint8_t index = inoise8(i * indexScale, millis() /10);
    leds[i] = ColorFromPalette(lavaPalette, index, brightness);
    //leds[i] = CHSV(0, 255, brightness);
  }

  FastLED.show();

demo6:

CRGB background[NUM_LEDS];
if  (v1==1){
   uint8_t octaves = 1;
  uint16_t x = 0;
  int scale = 100;
  uint8_t hue_octaves = 1;
  uint16_t hue_x = 1;
  int hue_scale = 50;
  uint16_t ntime = millis() / 3;
  uint8_t hue_shift = 5;
  
  fill_noise16 (leds, NUM_LEDS, octaves, x, scale, hue_octaves, hue_x, hue_scale, ntime, hue_shift);
  FastLED.show(); 
   }
   
  else if (v1==0&&v2==0){  FastLED.clear();   FastLED.show();
}
 if  (v2==1){
 fill_noise16 (background, NUM_LEDS, 1, millis(), 30, 1, 0, 50, millis() / 3, 10);
 uint16_t pos = inoise16(millis() * 100);
  pos = constrain(pos, 13000, 51000);
  pos = map(pos, 13000, 51000, 0, NUM_LEDS - 1);
  leds[pos] = CHSV(hue, 255, 255);
  fadeToBlackBy(leds, NUM_LEDS, 10); 
EVERY_N_MILLISECONDS(20) {
   
    nblend(leds, background, NUM_LEDS, 30);
hue++;
 
  } 
  
  FastLED.delay(slidert1);
 //btn.tick();
 }

// A simple plasma effect




......
void loop(){
...// A simple plasma effect
fill_noise16 (background, NUM_LEDS, 1, millis(), 30, 1, 0, 50, millis() / 3, 10);
EVERY_N_MILLISECONDS(20) {
    fadeToBlackBy(leds, NUM_LEDS, 10); 
    nblend(leds, background, NUM_LEDS, 30);

 
  } 

void drawMovingPixel() {
  // A pixel that moves back and forth using noise
  uint16_t pos = inoise16(millis() * 100);
  pos = constrain(pos, 13000, 51000);
  pos = map(pos, 13000, 51000, 0, NUM_LEDS - 1);
  leds[pos] = CRGB::Red;
}

Vamos a rellenar las columnas de muchos puntos de colores

if  (v1==1){
   uint8_t octaves = 1;
  uint16_t x = 0;
  int scale = 100;
  uint8_t hue_octaves = 1;
  uint16_t hue_x = 1;
  int hue_scale = 50;
  uint16_t ntime = millis() / 3;
  uint8_t hue_shift = 5;
  
  fill_noise16 (leds, NUM_LEDS, octaves, x, scale, hue_octaves, hue_x, hue_scale, ntime, hue_shift);
  FastLED.show(); 
   }

Ampliación conocimiento:

Documentación de origen en;

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *