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.