[SOLUCIONADO] ESP8266, Ecualizador y cambio de variable

Hola, necesito ayuda para modificar un código.

Lo primero, el código que estoy usando es una modificación que he realizado del que se encuentra en esta web: Cómo Hacer un Analizador de Espectro DIY
Permite fabricar un ecualizador gráfico con un ESP8266 y una tira led WS2812B. Todo el merito para ellos. Yo lo he modificado para adaptarlo a mis necesidades y funciona de forma correcta. Pego aquí mi código:

#include <arduinoFFT.h> //Librería para calcular la transformada de Fourier
#include <FastLED.h>


//SEÑAL DE AUDIO
#define SAMPLES 256        //Tiene que ser potencia de 2
#define SAMPLING_FREQ 40000 //Determina la frecuencia máxima que se puede analizar con FFT. Freq_max = sampling_freq/2 
#define AMPLITUDE 7000      //Can be used as a "sensitivity" control (por defecto 1000) (Numero más alto menos sensible)
#define AUDIO_IN_PIN A0     //Entrada analógica a la que se ha conectado el microfono
#define NOISE 500           //Los valores que estén por debajo de NOISE se ignoran
#define NUM_BANDS 9         //Numero columnas (por defecto 10)
#define MAX_BAR_HEIGHT 8   //Número de leds por columna
#define LEDS_BETWEEN_BANDS 0 //Leds apagados entre columnas (por defecto 3)

//LEDS
#define NUM_LEDS 2*NUM_BANDS*MAX_BAR_HEIGHT + NUM_BANDS*LEDS_BETWEEN_BANDS + 2*NUM_BANDS
#define LEDS_PIN 14   //D5 en la NodeMCU ESP8266
#define COLOR_ORDER GRB   //(Por defecto GRB)
#define MAX_BRIGHTNESS 30 //Por defecto 30
#define LED_TYPE WS2812B
CRGB leds[NUM_LEDS];
byte state = 0;
bool base_leds_on = false;
int state_cont = 0;


unsigned int sampling_period_us;
unsigned long newTime;
double vReal[SAMPLES];
double vImag[SAMPLES];
arduinoFFT FFT = arduinoFFT(vReal, vImag, SAMPLES, SAMPLING_FREQ);

int bandValues[] = {0,0,0,0,0,0,0,0,0,0};    //Tenemos 10 bandas (defecto 10)
//***********************************************************
int oldBarHeights[] = {0,0,0,0,0,0,0,0,0,0};
//***********************************************************
int peak[] = {0,0,0,0,0,0,0,0,0,0};

//HSV
byte base_hue = 0;

// Posicion (0,0,0,0) = (gradiente, R, G, B)
DEFINE_GRADIENT_PALETTE (fire_palette){
0, 230,7,0,       //Rojo
74, 255,165,0,    //Naranja
148, 255,255,0,   //Amarillo
255, 0,255,0,     //Verde
};

CRGBPalette16 myPal;


void setup() {
  //Configuramos el ADC para obtener 58.6 KHz de velocidad de muestreo
  Serial.begin(115200);
  
  sampling_period_us = round(1000000 * (1.0/SAMPLING_FREQ));
  FastLED.addLeds<LED_TYPE, LEDS_PIN, COLOR_ORDER>(leds, NUM_LEDS);
  FastLED.setBrightness(MAX_BRIGHTNESS);

}

void loop() {
  FastLED.clear();
  Serial.println("0");

  // Reset bandValues[]
  for (int i = 0; i<NUM_BANDS; i++){
    bandValues[i] = 0;
  }
  
  //Muestreamos la señal eléctrica recibida del microfono
  for(int i=0; i<SAMPLES; i++){
    newTime = micros();   //Se desborda a los 70 minutos aprox.                
    vReal[i] = analogRead(AUDIO_IN_PIN);
    vImag[i] = 0;
    while((micros()-newTime) < sampling_period_us) {  }
  }
  
  FFT.DCRemoval();  //Elimina el offset de la señal eléctrica
  FFT.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(FFT_FORWARD);
  FFT.ComplexToMagnitude();

  //Analizamos los resultados del FFT
  for(int i=2; i<(SAMPLES/2); i++){
    if(vReal[i] > NOISE) {    //Filtro de ruido


    //10 bands, 300Hz a 20000KHz, 256 muestras
      if (i<=2           ) bandValues[0]  += (int)vReal[i];
      if (i>2   && i<=4  ) bandValues[1]  += (int)vReal[i];
      if (i>4   && i<=6  ) bandValues[2]  += (int)vReal[i];
      if (i>6   && i<=10  ) bandValues[3]  += (int)vReal[i];
      if (i>10   && i<=16 ) bandValues[4]  += (int)vReal[i];
      if (i>16   && i<=26) bandValues[5]  += (int)vReal[i];
      if (i>26  && i<=41 ) bandValues[6]  += (int)vReal[i];
      if (i>41  && i<=65 ) bandValues[7]  += (int)vReal[i];
      if (i>65  && i<=104 ) bandValues[8]  += (int)vReal[i];
      if (i>104            ) bandValues[9]  += (int)vReal[i];
    }
  }

  for(int band=0; band<NUM_BANDS; band++){
      //Escalamos las barras
      int barHeight = bandValues[band] / AMPLITUDE;
      if(barHeight > MAX_BAR_HEIGHT)  barHeight = MAX_BAR_HEIGHT;

      //Hacemos promedio con el valor anterior
      barHeight = ((oldBarHeights[band] * 1) + barHeight) / 2;

      //Movemos la "cima"
      if(barHeight > peak[band]){
        peak[band] = min(MAX_BAR_HEIGHT, barHeight);
      }

      //DIBUJAMOS LAS BANDAS
      switch(state){

        case 0: 
        
          myPal = fire_palette; 
          drawBarsWithPalette(band, barHeight, myPal, base_leds_on);
        break;

      }
      
      drawPeak(band, 0, 255, 0);  //Color led superior (RGB)

      oldBarHeights[band] = barHeight; 
     
  }

  //Bajamos la cima
  EVERY_N_MILLISECONDS(500){  //Tiempo que tarda el tope en caer (por defecto 120ms)
    for (byte band = 0; band < NUM_BANDS; band++){
      if (peak[band] > 0) peak[band] -= 1;
    }

  }


  if(base_hue>245) base_hue = 0;
  else base_hue += 10;
  FastLED.show();
}



void drawBarsWithPalette(int num_band, int barHeight, CRGBPalette16 palette, bool base_leds_on){
  int start_point = (num_band+1)*(2*MAX_BAR_HEIGHT) - 1 + num_band*LEDS_BETWEEN_BANDS;
  int j = start_point + LEDS_BETWEEN_BANDS + 1;
  int num_led_band = 0;
  
  for(int i=start_point; i>(start_point-barHeight); i--){
    if(base_leds_on && i==start_point){
      leds[i+1]= ColorFromPalette(palette, round(255*num_led_band/MAX_BAR_HEIGHT), 255, NOBLEND);
      leds[i+2]= ColorFromPalette(palette, round(255*num_led_band/MAX_BAR_HEIGHT), 255, NOBLEND);
      leds[i+3]= ColorFromPalette(palette, round(255*num_led_band/MAX_BAR_HEIGHT), 255, NOBLEND);
    }
    leds[i]= ColorFromPalette(palette, round(255*num_led_band/MAX_BAR_HEIGHT), 255, NOBLEND);
    leds[j]= ColorFromPalette(palette, round(255*num_led_band/MAX_BAR_HEIGHT), 255, NOBLEND);
    num_led_band++;
    j++;
  }
}


void drawPeak(int num_band, byte R, byte G, byte B){
  int start_point1 = (num_band+1)*(2*MAX_BAR_HEIGHT) - 1 + num_band*LEDS_BETWEEN_BANDS;
  int start_point2 = start_point1 + LEDS_BETWEEN_BANDS + 1;
  int point1 = start_point1 - peak[num_band];
  int point2 = start_point2 + peak[num_band];
  
  leds[point1].setRGB(R, G, B);
  leds[point2].setRGB(R, G, B);
}

Como he indicado, el código se ejecuta perfecto en el ESP.
Y aquí es donde necesito ayuda. En las primeras líneas se configura un valor "#define AMPLITUDE 7000" que determina lo sensible que es el micrófono al sonido, de modo que puedo configurarlo variando el numero. Pero necesito poder hacerlo mediante un botón físico, para poder tener dos niveles de sensibilidad. Es posible que sea fácil a rabiar, pero no he sido capaz de dar con el modo de hacerlo.

Lo primero que descubrí es que al estar declarado de este modo "#define AMPLITUDE 7000", no puedo simplemente variar el valor numérico según esté el pin del botón en HIGH o LOW, si no que necesito hacer algo del estilo:

#define DEFAULT_AMPLITUDE 1000  // Valor de amplitud por defecto
#define AMPLITUDE_HIGH 7000    // Valor de amplitud cuando el botón está en estado HIGH

Y añadir también:

if (digitalRead(BUTTON_PIN) == HIGH) {
    amplitude = AMPLITUDE_HIGH;
  } else {
    amplitude = DEFAULT_AMPLITUDE;
  }

Y este "amplitude" modificado añadirlo a mi código de modo que:

//Escalamos las barras
      int barHeight = bandValues[band] / AMPLITUDE;
      if(barHeight > MAX_BAR_HEIGHT)  barHeight = MAX_BAR_HEIGHT;

Pase a quedar:

//Escalamos las barras
      int barHeight = bandValues[band] / amplitude;
      if(barHeight > MAX_BAR_HEIGHT)  barHeight = MAX_BAR_HEIGHT;

En mi cabeza sonaba "sencillo". Pero no funciona.

Incluso encontré otras maneras de hacerlo leyendo aquí y allá, como por ejemplo usando:

attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonInterrupt, CHANGE);  // Configurar la interrupción en el pin del botón

Y añadiendo una nueva funcion:

void buttonInterrupt() {
  if (digitalRead(BUTTON_PIN) == HIGH) {
    amplitude = AMPLITUDE_HIGH;
  } else {
    amplitude = AMPLITUDE_LOW;
  }
}

Pero sin obtener resultados. Reconozco que éste ultimo método lo he probado sin llegar a entenderlo bien del todo, solo adaptando nombres de variables a las mías.

No me veo capaz de terminar el código y conseguir lo que busco. Por eso acudo aquí, tal vez alguien con más conocimientos sea capaz de echarme una mano.

Lo resumo, porque ha quedado laaaaargo.

Quiero modificar el valor de una variable, a dos posibles opciones predefinidas(valores), usando un interruptor/botón físico.

Saludos, y gracias por vuestro tiempo.

Esto esta bien, segun pulsas tendras AMPLITUDE_HIGH o DEFAULT_AMPLITUDE.
Ok
Acá el error

//Escalamos las barras
      int barHeight = bandValues[band] / AMPLITUDE;
      if(barHeight > MAX_BAR_HEIGHT)  barHeight = MAX_BAR_HEIGHT;

Eso modificalo con tu variable amplitude asi

//Escalamos las barras
      int barHeight = bandValues[band] / amplitude;
      if(barHeight > MAX_BAR_HEIGHT)  barHeight = MAX_BAR_HEIGHT;

Que es la que tiene el valor elegido por el pulsador.
Ahora bien, es un pulsador o un switch, se mantiene o solo lo quieres temporalmente?
En cuanto sueltes el pulsasdor vuelves a tener amplitude = DEFAULT_AMPLITUDE y no se si es lo que deseas.

¿ No seria mas fácil ?. en lugar de:

#define AMPLITUDE 7000

Definir:

int AMPLITUDE;

Y luego en el codigo:

if (digitalRead(BUTTON_PIN) == HIGH) {
    AMPLITUDE = 7000;
  } else {
   AMPLITUDE = 1000;
  }

Si, para mi tmb pero el lo hizo asi.

1 Like

Hola de nuevo.
Lo primero es agradecer vuestro tiempo y apuntes.

Respondo a ambos mensajes. Espero hacerlo bien, no suelo participar mucho en foros.

Surbyte, he revisado lo que comentas del cambio en el código. Si, lo he realizado. He sustituido el "AMPLITUDE" que viene por defecto y en su lugar he usado mi variable "amplitude" que es donde se almacena el cambio en el botón. (Aprovecho y respondo que es un switch/interruptor con "dos" posiciones, se mantiene después de soltarlo.)
Continuo. En el momento que yo cambio ese "AMPLITUDE" por lo que sea, he probado varias cosas distintas, la tira led deja de responder. Eso lo sé porque la tira led, una vez que cargo el código (el que he puesto arriba en el primer mensaje) y enciendo el circuito, se muestran una serie de leds encendidos de color verde. Al tocar algo, se quedan todos apagados siempre.

Para no hacer muchos mensajes, respondo ahora a gonpezzi.
También a ti, gracias por tu tiempo. Si. Si no recuerdo mal, cuando descubrí que #define no se puede modificar (o yo no se hacerlo) pensé en declararlo como int pero tampoco funcionó. Aun así, he probado tantas cosas distintas que ya no estoy ni seguro. Ahora mismo hago esos cambios, cargo código y lo pruebo. Mejor equivocarme dos veces a quedar con la duda.
Ya. Aun sin buen resultado. Añadiendo tu parte del código los leds quedan también apagados por completo.
Tal vez estoy haciendo mal la parte física del botón. Repetiré el montaje de eso desde 0.

Voy a simplificar el problema en mi cabeza. Me olvido del botón por ahora.
Voy a ir de más simple hasta llegar a usar botón.
Creo una nueva variable y le asigno valor: "int PRUEBA=5000;" y a mano la uso para cambiar ésta parte del código:

      //Escalamos las barras
      int barHeight = bandValues[band] / PRUEBA;

Vale, por ahora funciona usando "int" en lugar de "#define". Ya es un avance.

Por ahora va a quedar ahí, me reclaman en otros asuntos de la vida. Volveré esta noche al código y seguiré desde este punto.

Muchas gracias a los dos por vuestros consejos y tiempo. Más tarde actualizaré progresos.

Saludos.

A punto de subir más código y comentar que seguía sin funcionar, me ha venido la luz.
Para atarme a una farola del pueblo y que la gente al pasar me mire mal ......

Fallo tonto donde los haya. Acostumbrado a Arduino no caí en la cuenta de que estoy con una ESP.
El fallo lo estaba cometiendo a la hora de declarar el pin del botón:

const int interruptorPin = 8;     //Entrada del estado del botón.

El pin que yo uso para el botón es D8 según lo que pone en la parte superior. Pero el ESP también me lo marca por debajo como IO15. Y solo con ese cambio tonto ya esta funcionando Ok.

const int interruptorPin = 15;     //Entrada del estado del botón.

Pego a continuación el código completo, con todo funcionando de la forma que buscaba.

#include <arduinoFFT.h>         //Librería para calcular la transformada de Fourier
#include <FastLED.h>


//SEÑAL DE AUDIO
#define SAMPLES 256             //Tiene que ser potencia de 2
#define SAMPLING_FREQ 40000     //Determina la frecuencia máxima que se puede analizar con FFT. Freq_max = sampling_freq/2 
#define AMPLITUDE 7000          //Can be used as a "sensitivity" control (por defecto 1000) (Numero más alto menos sensible)
int MODO=100;                   //Variable para elegir Modo "Noche" o "Fiesta"
#define AUDIO_IN_PIN A0         //Entrada analógica a la que se ha conectado el microfono
#define NOISE 500               //Los valores que estén por debajo de NOISE se ignoran
#define NUM_BANDS 9             //Numero columnas (por defecto 10).
#define MAX_BAR_HEIGHT 8        //Número de leds por columna (por defecto 8)
#define LEDS_BETWEEN_BANDS 0    //Leds apagados entre columnas (por defecto 3)

//LEDS
#define NUM_LEDS 2*NUM_BANDS*MAX_BAR_HEIGHT + NUM_BANDS*LEDS_BETWEEN_BANDS + 2*NUM_BANDS
#define LEDS_PIN 14               //D5 en la NodeMCU ESP8266
#define COLOR_ORDER GRB           //(Por defecto GRB)
#define MAX_BRIGHTNESS 30         //Por defecto 30
#define LED_TYPE WS2812B
CRGB leds[NUM_LEDS];
byte state = 0;
bool base_leds_on = false;
int state_cont = 0;


//AÑADIDOS PARA USAR UN BOTÓN.
const int interruptorPin = 15;     //Entrada del estado del botón.
int estadoInterruptor;            //Guardamos el estado.

int noche = 1000;                 //Opción muy sensible para música a volúmen bajo.
int fiesta = 7000;                //Opción poco sensible para musica a volúmen muy alto.

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


unsigned int sampling_period_us;
unsigned long newTime;
double vReal[SAMPLES];
double vImag[SAMPLES];
arduinoFFT FFT = arduinoFFT(vReal, vImag, SAMPLES, SAMPLING_FREQ);

int bandValues[] = {0,0,0,0,0,0,0,0,0,0};    //Tenemos 10 bandas (defecto 10)
//***********************************************************
int oldBarHeights[] = {0,0,0,0,0,0,0,0,0,0};
//***********************************************************
int peak[] = {0,0,0,0,0,0,0,0,0,0};

//HSV
byte base_hue = 0;

/* Color original del código. Guardado para futuras referencias.
DEFINE_GRADIENT_PALETTE (fire_palette){
  0, 255, 0, 0,
  75, 255, 149, 0,
  150, 250, 255, 100,
  255, 255, 255, 255
};
*/


// Posicion (0,0,0,0) = (gradiente, R, G, B)
DEFINE_GRADIENT_PALETTE (ecu_palette){
0, 230,7,0,       //Rojo
74, 255,165,0,    //Naranja
148, 255,255,0,   //Amarillo
255, 0,255,0,     //Verde
};

/* Distintos colores
0, 230,7,0,         //Rojo.
37, 255,69,0,       //Anaranjado.
74, 255,165,0,      //Naranja.
111, 255,215,0,     //Ambar.
148, 255,255,0,     //Amarillo.
185, 154,205,50,    //Amarillo-verde.
222, 50,205,50,     //Lima.
255, 0,255,0,       //Verde.
*/

CRGBPalette16 myPal;


void setup() {
  //Configuramos el ADC para obtener 58.6 KHz de velocidad de muestreo
  Serial.begin(115200);
  sampling_period_us = round(1000000 * (1.0/SAMPLING_FREQ));
  FastLED.addLeds<LED_TYPE, LEDS_PIN, COLOR_ORDER>(leds, NUM_LEDS);
  FastLED.setBrightness(MAX_BRIGHTNESS);


//AÑADIDOS PARA USAR UN BOTÓN

  pinMode(interruptorPin, INPUT);     //Probado también como INPUT_PULLUP sin exito.

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX  


}

void loop() {
  FastLED.clear();
  Serial.println("0");


//AÑADIDOS PARA USAR UN BOTÓN
  estadoInterruptor = digitalRead(interruptorPin);    //Leer el estado del botón.

//Condicionales:
if (estadoInterruptor == HIGH) {                      
    // Caso 1: Modo Noche activado
    MODO = noche;
    Serial.print("Modo Noche");                       //Comprobar si el Monitor Serial muestra este estado.
    } else {
    // Caso 2: Modo Fiesta activado
    MODO = fiesta;
    Serial.print("Modo Fiesta");                      //Comprobar si el Monitor Serial muestra este estado.
  }


//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX  


  // Reset bandValues[]
  for (int i = 0; i<NUM_BANDS; i++){
    bandValues[i] = 0;
  }
  
  //Muestreamos la señal eléctrica recibida del microfono
  for(int i=0; i<SAMPLES; i++){
    newTime = micros();   //Se desborda a los 70 minutos aprox.                
    vReal[i] = analogRead(AUDIO_IN_PIN);
    vImag[i] = 0;
    while((micros()-newTime) < sampling_period_us) {  }
  }
  
  FFT.DCRemoval();  //Elimina el offset de la señal eléctrica
  FFT.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(FFT_FORWARD);
  FFT.ComplexToMagnitude();

  //Analizamos los resultados del FFT
  for(int i=2; i<(SAMPLES/2); i++){
    if(vReal[i] > NOISE) {    //Filtro de ruido


    //10 bands, 300Hz a 20000KHz, 256 muestras
      if (i<=2           ) bandValues[0]  += (int)vReal[i];
      if (i>2   && i<=4  ) bandValues[1]  += (int)vReal[i];
      if (i>4   && i<=6  ) bandValues[2]  += (int)vReal[i];
      if (i>6   && i<=10  ) bandValues[3]  += (int)vReal[i];
      if (i>10   && i<=16 ) bandValues[4]  += (int)vReal[i];
      if (i>16   && i<=26) bandValues[5]  += (int)vReal[i];
      if (i>26  && i<=41 ) bandValues[6]  += (int)vReal[i];
      if (i>41  && i<=65 ) bandValues[7]  += (int)vReal[i];
      if (i>65  && i<=104 ) bandValues[8]  += (int)vReal[i];
      if (i>104            ) bandValues[9]  += (int)vReal[i];
    }
  }

  for(int band=0; band<NUM_BANDS; band++){
      //Escalamos las barras
      int barHeight = bandValues[band] / MODO;
      if(barHeight > MAX_BAR_HEIGHT)  barHeight = MAX_BAR_HEIGHT;

      //Hacemos promedio con el valor anterior
      barHeight = ((oldBarHeights[band] * 1) + barHeight) / 2;

      //Movemos la "cima"
      if(barHeight > peak[band]){
        peak[band] = min(MAX_BAR_HEIGHT, barHeight);
      }

      //DIBUJAMOS LAS BANDAS
      switch(state){
        case 0: 
          myPal = ecu_palette; 
          drawBarsWithPalette(band, barHeight, myPal, base_leds_on);
        break;

      }
      
      drawPeak(band, 0, 255, 0);  //Color led superior (RGB)

      oldBarHeights[band] = barHeight; 
     
  }

  //Bajamos la cima
  EVERY_N_MILLISECONDS(500){  //Tiempo que tarda el tope en caer (por defecto 120ms) REVISAR CON EL PROYECTO MONTADO
    for (byte band = 0; band < NUM_BANDS; band++){
      if (peak[band] > 0) peak[band] -= 1;
    }

  }


  if(base_hue>245) base_hue = 0;
  else base_hue += 10;
  FastLED.show();
}



void drawBarsWithPalette(int num_band, int barHeight, CRGBPalette16 palette, bool base_leds_on){
  int start_point = (num_band+1)*(2*MAX_BAR_HEIGHT) - 1 + num_band*LEDS_BETWEEN_BANDS;
  int j = start_point + LEDS_BETWEEN_BANDS + 1;
  int num_led_band = 0;
  
  for(int i=start_point; i>(start_point-barHeight); i--){
    if(base_leds_on && i==start_point){
      leds[i+1]= ColorFromPalette(palette, round(255*num_led_band/MAX_BAR_HEIGHT), 255, NOBLEND);
      leds[i+2]= ColorFromPalette(palette, round(255*num_led_band/MAX_BAR_HEIGHT), 255, NOBLEND);
      leds[i+3]= ColorFromPalette(palette, round(255*num_led_band/MAX_BAR_HEIGHT), 255, NOBLEND);
    }
    leds[i]= ColorFromPalette(palette, round(255*num_led_band/MAX_BAR_HEIGHT), 255, NOBLEND);
    leds[j]= ColorFromPalette(palette, round(255*num_led_band/MAX_BAR_HEIGHT), 255, NOBLEND);
    num_led_band++;
    j++;
  }
}


void drawPeak(int num_band, byte R, byte G, byte B){
  int start_point1 = (num_band+1)*(2*MAX_BAR_HEIGHT) - 1 + num_band*LEDS_BETWEEN_BANDS;
  int start_point2 = start_point1 + LEDS_BETWEEN_BANDS + 1;
  int point1 = start_point1 - peak[num_band];
  int point2 = start_point2 + peak[num_band];
  
  leds[point1].setRGB(R, G, B);
  leds[point2].setRGB(R, G, B);
}

Muchísimas gracias por vuestra ayuda. No hubiera sido capaz de llegar hasta aquí yo solo.

Saludos.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.