Saltar al contenido

Construimos el altavoz bluetooth definitivo

No se si los habrás visto pero hace 6 meses hicimos un proyecto de un altavoz bluetooth y hace un mes hicimos otro de un analizador de espectro. Bueno pues  de esto que estábamos hablando y dijimos ¿oye y qué pasa si juntamos estos dos proyectos? Nos pareció buena idea así que es justo lo que hemos hecho.

Resumen del proyecto altavoz bluetooth definitivo

Hemos decidido mezclar dos proyectos que hicimos hace tiempo, el altavoz bluetooth casero y el analizador de espectro. La idea es construir un altavoz bluetooth bastante potente de un solo speaker y que además tenga integrado un pequeño analizador de espectro en su estructura.

Para poder escuchar los graves y los agudos con una buena calidad hemos escogido un speaker coaxial. Eso significa que tiene integrado tanto un Woofer, que sirve para reproducir los sonidos graves, como un Tweeter, que se encarga de reproducir los agudos.

En cuanto a los LEDs del analizador de espectro, hemos cogido una matriz WS2812B de 16×16 y la hemos cortado por la mitad. Así el analizador será de 8 filas (altura) y 16 columnas (longitud).

Por cierto, aquí te dejamos los archivos STL para que puedas imprimir en 3D las mismas piezas que hemos impreso nosotros: repositorio del proyecto

Lista de materiales

Altavoces JVC CS-J620

Altavoces JVC

Microcontrolador NodeMCU ESP8266

Matriz 16×16 LED WS2812b 

Fuente de alimentación 12V 5A 

Contrachapado de 120x60x1,5

Tablón de contrachapado

Amplificador Mono TPA3118 

Tubo de reflexión de bajos

Espuma corrugada para cajas

Micrófono MAX9814    

Tornillos 3,5×30 mm (grosor x longitud)

Tornillos

Receptor Bluetooth      

Transformador de voltaje LM2596S

Adaptador de fuente de alimentación

   Botón interruptor         

Esquema eléctrico del altavoz bluetooth

Esquema eléctrico altavoz bluetooth

Aquí tenemos el esquema eléctrico del altavoz bluetooth con analizador de espectro. Podemos dividirlo en dos partes. Por un lado la parte del altavoz y por el otro la parte del analizador de espectro.

En cuanto a la parte del altavoz, alimentamos el amplificador, al que hemos conectado el speaker, con una fuente de 12V. También tenemos que alimentar el receptor bluetooth, pero como este trabaja con un máximo de 5V, hemos puesto un transformador de voltaje. Por último, nos falta conectar el receptor bluetooth al amplificador para enviarle la señal de sonido. Entre medias hemos conectado un potenciómetro para poder ajustar el volumen manualmente. 

Respecto a la parte del analizador de espectro, alimentamos tanto el microcontrolador ESP8266 como la matriz led con los 5V de salida del transformador de voltaje. El micrófono MAX9814 lo podemos alimentar directamente desde el microcontrolador. El pin de datos de la matriz hay que conectarlo a un pin digital de la ESP8266 y el pin de salida del micrófono a una entrada analógica.

Código del analizador de espectro

Aquí te dejamos el código del analizador de espectro del altavoz bluetooth. Si haces las conexiones siguiendo nuestro esquema eléctrico, no necesitas cambiar nada. 

Si quieres aprender a modificar código y crearlo desde 0, puedes entrar a nuestro curso de programación y electrónica con Arduino.

Curso de Arduino desde cero

Curso de Arduino desde Cero

Aprende programación y electrónica de forma rápida y sencilla con Arduino para que puedas montar tus proyectos tecnológicos lo antes posible.

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

//SEÑAL DE AUDIO
#define SAMPLES 512         //Tiene que ser potencia de 2. Arduino Nano solo tiene memoria para guardar 128 muestras
#define SAMPLING_FREQ 40000 //Determina la frecuencia máxima que se puede analizar con FFT. Freq_max = sampling_freq/2 
#define AMPLITUDE 500      //Can be used as a "sensitivity" control (1000)
#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 16      
#define MAX_BAR_HEIGHT 8   //Número de leds por columna

//LEDS
#define NUM_LEDS NUM_BANDS*MAX_BAR_HEIGHT
#define LEDS_PIN 14   //D5 en la NodeMCU ESP8266
#define COLOR_ORDER GRB
#define MAX_BRIGHTNESS 30
#define LED_TYPE WS2812B
CRGB leds[NUM_LEDS];


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,0,0,0,0,0,0};    //Tenemos 16 bandas
//***********************************************************
int oldBarHeights[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
//***********************************************************
int peak[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

//HSV
byte base_hue = 0;
//Palettes
DEFINE_GRADIENT_PALETTE (ocean_palette){
  0, 13, 4, 156,
  75, 39, 142, 228,
  145, 40, 160, 255,
  255, 0, 255, 255
};

DEFINE_GRADIENT_PALETTE (fire_palette){
  0, 255, 0, 0,
  75, 255, 149, 0,
  150, 255, 0, 100,
  255, 255, 255, 255
};

CRGBPalette16 myPal;


void setup() {
  // put your setup code here, to run once:
  //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);

  //Elegimos Palette
  //myPal = ocean_palette;
  myPal = fire_palette;
}

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
  
    //16 bands, 80Hz a 20000KHz, 512 muestras
      if (i<=1 )           bandValues[0]  += (int)vReal[i];
      if (i>1   && i<=2  ) bandValues[1]  += (int)vReal[i];
      if (i>2   && i<=3  ) bandValues[2]  += (int)vReal[i];
      if (i>3   && i<=4  ) bandValues[3]  += (int)vReal[i];
      if (i>4   && i<=6  ) bandValues[4]  += (int)vReal[i];
      if (i>6   && i<=9 ) bandValues[5]  += (int)vReal[i];
      if (i>9  && i<=13 ) bandValues[6]  += (int)vReal[i];
      if (i>13  && i<=18 ) bandValues[7]  += (int)vReal[i];
      if (i>18  && i<=26 ) bandValues[8]  += (int)vReal[i];
      if (i>26  && i<=37 ) bandValues[9]  += (int)vReal[i];
      if (i>37  && i<=53 ) bandValues[10] += (int)vReal[i];
      if (i>53  && i<=76 ) bandValues[11] += (int)vReal[i];
      if (i>76  && i<=108) bandValues[12] += (int)vReal[i];
      if (i>108 && i<=153) bandValues[13] += (int)vReal[i];
      if (i>153 && i<=218) bandValues[14] += (int)vReal[i];
      if (i>218          ) bandValues[15] += (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 = round(((oldBarHeights[band] * 0.5) + 1.2* barHeight) / 2);

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

      drawWithCHSV(band, barHeight, base_hue);
      drawPeak(band, 255, 255, 255);

      oldBarHeights[band] = barHeight; 
     
  }

  //Bajamos la cima
  EVERY_N_MILLISECONDS(120){
    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 drawWithCHSV(int num_band, int barHeight, byte hue){
  int pos = num_band;
  for(int i=0; i<barHeight; i++){
    if((i%2)!= 0 && i!=0){
      pos += NUM_BANDS*2-(num_band*2)-1;
    }
    else if(i!=0){
      pos += num_band*2+1;
    }
    leds[pos] = CHSV(hue, 255, 255);
    hue+=5;
  }
}

void drawPeak(int num_band, byte R, byte G, byte B){
  int pos = num_band;
  for(int i=0; i<=peak[num_band]; i++){
    if((i%2)!= 0 && i!=0){
      pos += NUM_BANDS*2-(num_band*2)-1;
    }
    else if(i!=0){
      pos += num_band*2+1;
    }
  }
  leds[pos].setRGB(R, G, B);
}
				
			

¿Con qué trabajamos?- Nuestras herramientas más utilizadas