Lo Básico
#include <FastLED.h>
#define NUM_LEDS 144
#define DATA_PIN 13
#define BRIGHTNESS 25
A continuación, necesitamos configurar el bloque de memoria que se utilizará para almacenar y manipular los datos del led:
CRGB leds[NUM_LEDS];
Esto configura una matriz que podemos manipular para configurar / borrar los datos del LED. Ahora, realmente configuremos nuestros leds, que es una sola línea de código en nuestra función de configuración:
void setup() {
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
}
Esto le dice a la biblioteca que hay una cadena de NEOPIXEL en el pin 13 (recuerde, el valor en el que se configuró DATA_PIN), y esos leds usarán los leds de matriz de led, que declaramos 144.
ACTIVANDO UN SOLO LED:
void loop() {
leds[70] = CRGB::Blue;
FastLED.show();
delay(30);
}
/////////////////////////////podemos integrar FastLED.show() y delay() así; Fast.delay()/////////
void loop() {
leds[70] = CRGB::Blue;
FastLED.delay(30);
}
////////////////////////////////////////////////////////////////////////
PRIMER BLINK;
void loop() {
// Turn the first led red for 1 second
leds[70] = CRGB::Red;
FastLED.delay(1000);
// Set the first led back to black for 1 second
leds[70] = CRGB::Black;
}
//para apagar el led tambien se puede proceder así
FastLED.clear();
FastLED.delay(1000);
MOVIENDO UN ELEMENTO
void loop() {
for(int K = 0; K < NUM_LEDS; K++) {
leds[K] = CRGB::Blue;
FastLED.show();
// clear this led for the next time around the loop
leds[K] = CRGB::Black;
delay(30);
}
}
DE OTRA FORMA:
void loop() {
int k=0;
while ( k<=143){
leds[k] = CRGB::Blue;
FastLED.show();
// clear this led for the next time around the loop
leds[k] = CRGB::Black;
delay(25);
k++;
}
}
INCORPORACION POTENCIOMETRO:
void loop() {
int val = analogRead(0);
int numLedsToLight = map(val, 0, 1023, 0, NUM_LEDS);
//lOS LEDS SE IRAN ILUMINANDO CONFORME SE GIRA EN POSITIVO EL POTENCIOMETRO, Y PARA
//QUE SE VAYAN APAGANDO CUANDO SE GIRE EN NEGATIVO PONEMOS "FastLED.clear"
FastLED.clear();
for(int led = 0; led < numLedsToLight; led++) {
leds[led] = CRGB::Blue;
}
FastLED.show();//es muy importante poner esta función fuera del bucle for, de lo constrario, se produce un efecto no deseado ahora, como el destello de los leds
}
Algunos modos de establecer el color
Establecer campos individuales R, G y B, de la forma clásica:
leds[i].r = 255;
leds[i].g = 68;
leds[i].b = 221;
A PARTIR DEL CODIGO DE COLOR HEX
leds[i] = 0xFF44DD;
A PARTIR DE UN CÓDIGO DE COLOR STANDARD DELALISTA DE COLORES PREDEFINIDOS
https://crisalctime.com/lista-colores-predefinidos-para-uso-con/
leds[i] = CRGB::HotPink;
USANDO 'setRGB' Y TRES VALORES A LA VEZ
leds[i].setRGB( 55, 68, 21);
USO DE LOS COLORES HSV
Los objetos de color CRGB usan canales separados rojo, verde y azul internamente para representar cada color compuesto, ya que es exactamente de la misma manera que lo hacen los LED multicolores: tienen un LED rojo, un LED verde y un LED azul en cada píxel. ‘. Al mezclar diferentes cantidades de rojo, verde y azul, se pueden mostrar miles o millones de colores resultantes.
Sin embargo, trabajar con valores RGB sin procesar en su código puede resultar incómodo en algunos casos. Por ejemplo, es difícil trabajar expresando diferentes tonos y sombras de un solo color usando solo valores RGB, y puede ser particularmente desalentador describir un “lavado de color” en RGB que recorre un arcoíris de tonos mientras mantiene un brillo constante.
Para simplificar el trabajo con el color de esta manera, la biblioteca brinda acceso a un modelo de color alternativo basado en tres ejes diferentes: tono, saturación y valor (o ‘brillo’). (Hue, Saturation, and Value (or ‘Brightness’).
HUE es el ‘ángulo’ alrededor de una rueda de colores.
SATURATION es cuán ‘rico’ (frente a pálido) es el color
VALUE es qué tan ‘brillante’ (frente a tenue) es el color( como sabemos implica mas consumo)
“HUE” es un valor de un byte que oscila entre 0 y 255. Va del rojo al naranja, al amarillo, al verde, al aguamarina, al azul, al morado, al rosa y de nuevo al rojo. Aquí están los ocho puntos cardinales del ciclo de tono en la biblioteca y su ángulo de tono correspondiente.
” SATURATION ” es un valor de un byte que va de 0 a 255, donde 255 significa “color puro completamente saturado”, 128 significa “medio saturado, un color claro y pálido” y 0 significa “completamente desaturado: blanco”.
” VALUE ” es un valor de un byte que va de 0 a 255 y representa el brillo, donde 255 significa “completamente brillante, completamente iluminado”, 128 significa “algo atenuado, solo medio iluminado” y cero significa “completamente oscuro: negro”.
// Set color from Hue, Saturation, and Value.
// Conversion to RGB is automatic.
leds[i] = CHSV( 160, 255, 255);
// alternate syntax
leds[i].setHSV( 160, 255, 255);
// set color to a pure, bright, fully saturated, hue
leds[i].setHue( 160);
CONFIGURACIONES DIVERSAS
Modo Espejo:
Es una configuración muy útilizada, en la que se usa un sol array y varias strips. En este ejemplo usaremos dos strips.
#include <FastLED.h>
#define PIN_LEFT 13// pin de datos strip 1
#define PIN_RIGHT 14//pin de datos strip 2
#define NUM_LEDS 144
CRGB leds[NUM_LEDS];
void setup(){
.....
FastLED.addLeds<NEOPIXEL, PIN_LEFT>(leds, NUM_LEDS);
FastLED.addLeds<NEOPIXEL, PIN_RIGHT>(leds, NUM_LEDS);
,,,,,,
}
Multiple led arrays
Ahora vamos a tener,segun el ejemplo ,dos strips y dos arrays. Si queremos que las tareas sean simultáneas,habra que gestionar el delay() adecuadamente.
Para ello declaramos dos leds arrays llamados “left” y “right”
#include <FastLED.h>
#define PIN_LEFT 13// pin de datos strip 1
#define PIN_RIGHT 14//pin de datos strip 2
#define NUM_LEDS 144
CRGB left[NUM_LEDS];
CRGB right[NUM_LEDS];
.........
void setup(){
.....
FastLED.addLeds<NEOPIXEL, PIN_LEFT>(left, NUM_LEDS);
FastLED.addLeds<NEOPIXEL, PIN_RIGHT>(right, NUM_LEDS);
........
}
void loop(){
....
for(int i = 0; i < NUM_LEDS; i+=1) {
left[i] = CRGB( 0, 0, 40);
right[i] = CRGB (0, 0, 40);
FastLED.delay(slidert1);
FastLED.clear();
left[i] =CRGB( 0, 40,0 );
right[i] = CRGB( 0, 40, 0);
}
for(int i = NUM_LEDS; i > 0; i-=1) {
left[i] = CRGB(5,0,0);
right[i] = CRGB(5,0,0);
FastLED.delay(slidert1);
}
}
else{
FastLED.clear();
FastLED.show();
}
Array of led arrays
Ahora vamos a conseguir utilizando dos strips, un array de leds arrays, en nuestro caso dos, que los ordenamos como [0] con el pin de la columna izquierda y [1] para la derecha.
Procederemos como se indica:
#include <FastLED.h>
#define NUM_STRIPS 2
#define NUM_LEDS_PER_STRIP 140
CRGB leds[NUM_STRIPS][NUM_LEDS_PER_STRIP];
#define PIN_LEFT 13
#define PIN_RIGHT 14
void setup(){
.....
FastLED.addLeds<NEOPIXEL, PIN_LEFT>(leds[0], NUM_LEDS_PER_STRIP);
FastLED.addLeds<NEOPIXEL, PIN_RIGHT>(leds[1], NUM_LEDS_PER_STRIP);
........
}
void loop(){
....
for(int x = 0; x < NUM_STRIPS; x++) {
// This inner loop will go over each led in the current strip, one at a time
for(int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
leds[x][i] = CRGB (75,0,0);
FastLED.delay(slidert1);
leds[x][i] = CHSV( 128, 255, 10);
}
}
}
else{
FastLED.clear();
FastLED.show();
}
Un array y varios strips
Vamos a ver que es lo diferente ahora:
tenemos 2 strips y NUM_LEDS=140, construiremos un solo array con el producto 140*2( NUM_STRIPS * NUM_LEDS_PER_STRIP ), tal como si tuvieramos un strip de 280 leds.
Definimos tambien on offset por cada strip, que es el valor de leds de diferencia entre cada strip o donde va a arrancar cada uno. En el ejemplo, el dot empezara por la columna izquierda y en el punto de led 70 arrancará el dot de la columna derecha. Pero si ambos tienen el mismo offset, arrancaran simultaneamente.
Lo interesante de este montaje es contar con mas strips para lograr mas efectos.
#include <FastLED.h>
#define NUM_STRIPS 2
#define NUM_LEDS_PER_STRIP 140
#define NUM_LEDS NUM_LEDS_PER_STRIP * NUM_STRIPS// equivalente a poner #define NUM_LEDS 280
CRGB leds[NUM_LEDS];
#define PIN_LEFT 13
#define PIN_RIGHT 14
#define offset_left 0
#define offset_right 70
void setup(){
.....
FastLED.addLeds<NEOPIXEL, PIN_LEFT>(leds,offset_left, NUM_LEDS_PER_STRIP);
FastLED.addLeds<NEOPIXEL, PIN_RIGHT>(leds,offset_right,NUM_LEDS_PER_STRIP);
........
}
void loop() {
........
for(int i = 0; i < NUM_LEDS; i++) {
leds[i] = CRGB::Red;
FastLED.show();
leds[i] = CRGB (0,0,0);
delay();
}
}
else{
FastLED.clear();
FastLED.show();
}
COMBINACIÓN DE DOS CONFIGURACIONES
En este caso vamos a probar,usando Blynk y a traves de dos pines virtuales ,la combinación en V1 de un array y dos strips ,y en V2, multiple leds arrays (dos en nuestro caso):
La configuración de inicio la podemos poner así;
#include <FastLED.h>
#define PIN_LEFT 13
#define PIN_RIGHT 14
///un array y dos strips/////
#define NUM_STRIPS 2
#define NUM_LEDS_PER_STRIP 140
#define NUM_LEDS NUM_LEDS_PER_STRIP * NUM_STRIPS
CRGB leds[NUM_LEDS];
#define offset_left 79
#define offset_right 79
//dos leds array///
#define NUMofLEDS 140
CRGB left[NUMofLEDS];
CRGB right[NUMofLEDS];
CRGB leds[NUM_LEDS];
En el setup no pondremos nada, para colocarlo dentro de cada condicional V1 y V2
void loop(){
........
if (v1==1){
FastLED.addLeds<NEOPIXEL, PIN_LEFT>(leds,slidert2, NUM_LEDS_PER_STRIP);
FastLED.addLeds<NEOPIXEL, PIN_RIGHT>(leds,offset_right,NUM_LEDS_PER_STRIP);
for(int i = 0; i < NUM_LEDS; i++) {
........
if (v2==1){//
FastLED.addLeds<NEOPIXEL, PIN_LEFT>(left, NUMofLEDS);
FastLED.addLeds<NEOPIXEL, PIN_RIGHT>(right, NUMofLEDS);
for(int i = 0; i < NUMofLEDS; i+=1) {...........
CALCULAR TIEMPO EJECUCIÓN DE UNA TAREA CON LEDS DENTRO DE UN BUCLE
Aprovechando el ejemplo anterior, vamos a introducir en el bucle de la condicional ” v2==1″ la función millis(),, de forma que establecemos las variables long t1 y t2,. Cuando i=0, t1 =millis() y cuando i=NUM_LEDS -1, t2=millis. Luego calcularemos la diferencia “t2-t1” con Serial.print(t2-t1) . Esta expuesto simultaneamente sin perdida apreciable de tiempo.
Es muy imortante resaltar el uso de “delayMicroseconds” si queremos resultados con precición. Por ejemplo, para saber el tiempo que tarda un dot de una tira de led en recorrer todos los Leds.
Utilizando la variable virtual “slidert1” en la app definimos recorrido de 0 a 30, yque luego multiplicaremos por cien
dentro de la funcion delayMicroseconds (). He escogido este margen para establecer una duracion de 1000 mseg el tiempo del recorrido de la tira de 140 leds.
Con este metodo deslizaremos el slider virtual dentro de la app hasta que t2-t1 sea practicamente igual a 1000.
Para calibrar el resultado, podemos omitir las funciones FastLED y dejar el bucle” for” actuando en vacio y jugando con slidert1 para comprobar como t2-t1 varia entre 0 y 140.
void loop() {
Blynk.run();
if (v1==1){
for(int i = 0; i < NUM_LEDS; i+=1) {
leds[i] = CRGB(0,5,0) ;
FastLED.delay(slidert1);
leds[i] = CRGB(0,0,5);
}
for(int i = NUM_LEDS; i > 0; i-=1) {
leds[i] = CRGB(5,5,0);
FastLED.delay(slidert1);
leds[i] = CRGB(5,0,0);
}
}
else{
FastLED.clear();
FastLED.show();
}
if (v2==1){// mover un dot con 5 elementos moviendose a una velocidad slidert1
long t1;
long t2;
for(int i = 0; i < NUM_LEDS; i+=1) {
if (i==0){
t1=millis();
}
leds[i] = CRGB(0,5,0);
leds[i+1] = CRGB(0,5,0);
leds[i+2] = CRGB(0,5,0);
leds[i+3] = CRGB(0,5,0);
leds[i+4] = CRGB(0,5,0);
FastLED.show();
delayMicroseconds(slidert1*100);
FastLED.clear();
if (i==NUM_LEDS-1){
t2=millis();
Serial.println("diff: ");
Serial.print(t2-t1);
}
}
}
}
He realizado un pequeño estudio cambiando los NUM_LEDs desde 140 hasta 37, comprobando que al aumentar los leds de recorrido hay una deceleración apreciable. Partiendo de una condición ideal de no perdida (t2-t1=0), hecho imposible dando el tiempo que necesita cada led para encenderse y apagarse expongo el tiempo en milisegundos que tarda en recorrer la tira un dot de cinco elementos en cada caso:
NUM_LEDS | t2-t1(mseg) | delayMicroseconds para latencia de 1 seg | PERDIDA |
140 | 611 | 2800 | 4,34 mseg/dot |
70 | 175 | 12100 | 2,12 mseg/dot |
37 | 92 | 25960 | 1,06 mseg/dot |
El valor de pérdida sale de la diferencia entre el retraso de la condición ideal- si queremos una latencia de 1 segundo- que seria de 1000/NUM_LEDS menos el valor de “delayMicroseconds” que hemos tenido que poner para conseguir el valor t2-t1=1000.
Mi duda actual es si existe la posibilidad que con un numero de leds mayor de 100 podamos corregir la deceleración.
Si queremos verlo de otra manera quiere decir que si utilizaramos un delay ideal de 1000/140 (para el caso de 140 leds) porque deseamos que tarde 1 segundo en recorrer la tira, vamos a tardar 1,6 segundos por contra, con lo que nos obliga a calcular con la función millis el delay en microsegundos que tenemos que poner para conseguir nuestro objetivo., que seria de 2800 microsegundos.
Con los valores de perdida el calculo del delay a utilizar en microsegundos sin utilizar la función millis sería:
delay=T/NUM_LEDS-perdida,, si T es 2 segundos el delay a utilizar sería de 9967 microsegundos
Podemos utilizar la app de Blynk para recibir la información “t2-t1” que nomino “task time” de la forma siguiente:
Recordemos los nuevos pasos añadidos:
long t1;
long t2;
BlynkTimer timer1; // Announcing the timer1
void readvalue()
{
int v3 = t2-t1; // declaramos una variable que tiene la información requerida
Blynk.virtualWrite(V3, v3); //
void setup(){
timer1.setInterval(1000L, readvalue); //timer will run every sec
}
void loop(){
timer1.run();
}

#include <FastLED.h>
#define PIN_LEFT 13
#define PIN_RIGHT 14
#define NUM_LEDS 140
CRGB leds[NUM_LEDS];
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
char auth[] = "-------";
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "atom_2.4g";
char pass[] = "-------";
///////////////////////////////////////////////////////////////////////////////////////////////////
long t1;
long t2;
BlynkTimer timer1; // Announcing the timer1
void readvalue()
{
int v3 = t2-t1; // declaramos una variable que tiene la información requerida
Blynk.virtualWrite(V3, v3); // sending sensor value to Blynk app
}
int v1;
int v2;
int slidert1;
BLYNK_WRITE(V0){
slidert1=param.asInt();
}
BLYNK_WRITE(V1){//paralelo
v1 = param.asInt(); // varibale para la funcion de lecturas analogicas
}
BLYNK_WRITE(V2){//paralelo
v2 = param.asInt(); // varibale para la funcion de lecturas analogicas
}
void setup() {
Blynk.begin(auth, ssid, pass);
tft.begin();
FastLED.addLeds<NEOPIXEL, PIN_LEFT>(leds, NUM_LEDS);
FastLED.addLeds<NEOPIXEL, PIN_RIGHT>(leds, NUM_LEDS);
FastLED.clear();
FastLED.show();
timer1.setInterval(1000L, readvalue); //timer will run every sec
Serial.begin(9600);
}
void loop() {
Blynk.run();
timer1.run();
if (v1==1){
for(int i = 0; i < NUM_LEDS; i+=1) {
leds[i] = CRGB(0,5,0) ;
FastLED.delay(slidert1);
leds[i] = CRGB(0,0,5);
}
for(int i = NUM_LEDS; i > 0; i-=1) {
leds[i] = CRGB(5,5,0);
FastLED.delay(slidert1);
leds[i] = CRGB(5,0,0);
}
}
else{
FastLED.clear();
FastLED.show();
}
if (v2==1){// mover un dot con 5 elementos moviendose a una velocidad slidert1
for(int i = 0; i < NUM_LEDS; i+=1) {
if (i==0){
t1=millis();
}
leds[i] = CHSV( 160, 255, 10);
leds[i+1] = CHSV( 160, 255, 20);
leds[i+2] = CHSV( 160, 255, 40);
leds[i+3] = CHSV( 160, 255, 60);
leds[i+4] = CHSV( 160, 255, 80);
FastLED.show();
delayMicroseconds(slidert1*100);
FastLED.clear();
if (i==NUM_LEDS-1){
t2=millis();
}
}
}
}