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;