Como Hacer Barras LED RGB Con Visualización De Música Usando Arduino

by RAOM electrónica in Circuits > Arduino

3227 Views, 35 Favorites, 0 Comments

Como Hacer Barras LED RGB Con Visualización De Música Usando Arduino

4.jpg
Como hacer Barras de Luz LED RGB tipo GAMER con Visualización de Música | Audioritmicas

En este proyecto realizaremos un circuito de control para unas barras de luz LED RGB con visualización de música, para ello utilizaremos un micrófono electret y las tiras LED programables WS2812B como componentes principales. Para este proyecto utilizaremos las placas PCB que he diseñado y fabricado con PCBWAY con el fin de facilitar el montaje del circuito y dar un mejor acabado. Si no puede adquirir las placas PCB puede realizar el circuito en protoboard como lo explique en el anterior video.

Supplies

En el siguiente enlace del proyecto pueden adquirir con PCBWAY las placas PCB que he diseñado Barra de luz LED RGB GAMER - Share Project - PCBWay

  • Tira LED WS2812B
  • Transistor C945
  • Resistencia de 1K ohm a 1/4 W
  • 2 x Resistencia de 10K ohmios a 1/4 W
  • Resistencia de 100K ohmios a 1/4 W
  • Micrófono electret
  • 3 x Condensador cerámico 104
  • 2 x pulsador normalmente abierto 6,2 mm SMD
  • Potenciómetro 1M ohmios
  • Potenciómetro 50K ohmios
  • Condensador electrolítico 1000 uF a 16V
  • Bornera 2P
  • 2 x LEDs WS2812B 5050 SMD
  • 2 x Condensador de 0.1 uF 0805 SMD
  • Arduino nano
  • 2 x Perfiles de aluminio, 48 cm de largo
  • 2 x Bloques de madera, 10x10 cm
  • Pegamento
  • Cables varios
  • Fuente de 5V (Capacidad de corriente dependiendo de la cantidad de tiras LED, se recomienda usar cargadores de celular)

Adicionalmente será necesario contar con herramientas y materiales para realizar soldadura de estaño.

Diseño Del PCB

Captura de pantalla 2022-08-08 213441.png
Captura de pantalla 2022-08-08 212940.png
Captura de pantalla 2022-08-08 213102.png
Captura de pantalla 2022-08-08 213042.png
1657071017802.jpg
1657071017750.jpg

Para este proyecto lo primero que hice fue pasar el diagrama adjunto de mi circuito a un diseño profesional en PCB y adquirir las placas con PCBway aquí.

Montaje De Componentes Posteriores

Captura de pantalla 2022-08-08 215525.png
Captura de pantalla 2022-08-08 215245.png
Captura de pantalla 2022-08-08 215403.png

Una vez tenemos nuestras placas vamos a realizar el montaje de cada uno de los elementos y realizar la respectiva soldadura. En este paso debemos de observar la serigrafia del PCB y ubicar correctamente cada uno de los elementos, se recomienda tener a un lado el diagrama eléctrico con el fin de observar a que elemento se hace referencia en el PCB.

Iniciamos ubicando los LEDs WS2812B y el condensador 0805 de o.1 uF en la parte trasera del PCB.

Montaje De Componentes Frontales

Captura de pantalla 2022-08-08 220443.png
Captura de pantalla 2022-08-08 220542.png
Captura de pantalla 2022-08-08 220657.png
Captura de pantalla 2022-08-08 220618.png
Captura de pantalla 2022-08-08 220730.png
Captura de pantalla 2022-08-08 220855.png
Captura de pantalla 2022-08-08 220954.png
Captura de pantalla 2022-08-08 221128.png
Captura de pantalla 2022-08-08 221204.png
Captura de pantalla 2022-08-08 221257.png

Ahora ubicamos los elementos frontales, en este paso es recomendable empezar con el montaje de los elementos más pequeños (Como resistencias, componentes SMD) y por últimos los más grandes.

Se debe tener cuidado al ubicar los elementos con polaridad, como lo es el micrófono electret, condensador electrolítico y transistor (Observar serigrafia e imágenes de referencia del montaje).

Corrección Ruido Eléctrico

Captura de pantalla 2022-08-08 223939.png

Al diseño del PCB olvide agregar 2 condensadores 104 cerámicos que reducen el ruido eléctrico presente en las fuentes de alimentación, por ello se agregan en la parde posterior del PCB, como se observa en las imagines. Un condensador paralelo a R3 y otro entre base y emisor del transistor C945.

Construcción De Soportes Barras

Captura de pantalla 2022-08-08 224212.png
Captura de pantalla 2022-08-08 224321.png
Captura de pantalla 2022-08-08 224422.png
Captura de pantalla 2022-08-08 224524.png
Captura de pantalla 2022-08-08 224614.png
Captura de pantalla 2022-08-08 224703.png
Captura de pantalla 2022-08-08 224846.png

Para las barras que soportan la tiras LED utilizamos dos perfiles de aluminio de 48 cm de largo y dos bloques de madera de 10x10 cm.

Vamos a marcar el centro del bloque de madera, para realizar un orificio y la guía para que entre el perfil de aluminio. posteriormente pasamos un cable de 3 hilos por el orificio, ahora si podremos aplicar pegamento (silicona liquida) para unir las piezas (También se puede aplicar al final). Una vez se ha secado podremos aplicar una lata de pintura del color de su preferencia.

Conexión Tiras LED

Captura de pantalla 2022-08-08 225914.png
Captura de pantalla 2022-08-09 222422.png
Captura de pantalla 2022-08-09 222550.png
Captura de pantalla 2022-08-09 222723.png

Una vez tenemos listos los soportes, vamos a realizar las conexiones. La tira LED WS2812B cuenta con 3 terminales, GND, 5V y Señal DIN. En la placa PCB también encontraran estos terminales y realizamos la unión soldando los terminales del mismo nombre correspondientemente. Terminando este paso también podremos conectar el Arduino nano como se observa en la imagen.

Conexión De Alimentación

Captura de pantalla 2022-08-09 222329.png

El circuito opera a 5V DC, para alimentarlo podremos usar diferentes fuentes de alimentación con la capacidad adecuada de corriente según el tamaño de sus tiras LED. Para este caso utilizare un cargador de Celular y cable USB de donde he tomado los terminales positivos (+ rojo) y negativos (- negro) y se realiza la conexión de negativo a GND de la placa y positivo a 5V.

Instalación De Librerías Arduino

Captura de pantalla 2022-08-09 224032.png
Captura de pantalla 2022-08-09 224507.png

Finalmente, ya hemos realizado el montaje del circuito y es hora de programar el Arduino nano. Inicialmente vamos a instalar dos librerías, FastLED y Adafruit_Neopixel. Para ello ejecutamos el IDE de Arduino y vamos a Programas, Incluir Librería y Administrar de Bibliotecas, se nos abrirá una ventana donde vamos a buscar las librerías mencionadas y las instalamos como se muestra en la imagen.

Código De Programación

//ESTE CODIGO HA SIDO MODIFICADO POR RAOM ELECTRONICA 
//CREADOR DEL CODIGO DESCONOCIDO 
//WWW.YOUTUBE.COM/RAOMELECTRONICA
#include <Adafruit_NeoPixel.h>
#include <FastLED.h>

//TIRA LED
#define PIN 5            //PIN DIGITAL - SALIDA DE DATOS PARA TIRA LED
#define N_PIXELS  29     // NUMERO DE PIXELES DE LA TIRA LED
#define MIC_PIN   A5     //PIN DE ENTRADA ANALOGA DEL MICROFONO
#define NOISE     10     // RUIDO EN LA SEAL DE MIRCOFONO

//LEDs
#define PIN_2 6            //PIN DIGITAL - SALIDA DE DATOS PARA LEDs PLACA
#define N_PIXELS_2  2     // NUMERO DE PIXELES DE LEDs PLACA



const int analogInPot = A4;  // ENTRADA ANALOGA POTENCIOMETRO
const int buttonPin = 4;     // PIN DIGITAL PULSADOR para tira LED
const int buttonPin_2 = 3;    // PIN DIGITAL PULSADOR 2 para LEDs placa

#define BG 0
#define COLOR_ORDER GRB  // RGB-GBR-BRG
#define BRIGHTNESS 255   // 0-255 BRILLO TIRA LED
#define LED_TYPE WS2812B
#define DC_OFFSET  0  // VALOR DC DE LA SEAL (CERO USANDO POTENCIOMETRO)
#define SAMPLES   60  // Length of buffer for dynamic level adjustment
#define TOP       (N_PIXELS + 2) // Allow dot to go slightly off scale
#define PEAK_FALL 40  // Rate of peak falling dot
#define N_PIXELS_HALF (N_PIXELS/2)
#define GRAVITY           -9.81              // Downward (negative) acceleration of gravity in m/s^2
#define SPEED .20 //PARA VU3



float
greenOffset = 30,
blueOffset = 150;

byte
peak      = 0,      // Used for falling dot
dotCount  = 0,      // Frame counter for delaying dot-falling speed
volCount  = 0;      // Frame counter for storing past volume data
int
vol[SAMPLES],       // Collection of prior volume samples
    lvl       = 10,      // Current "dampened" audio level
    minLvlAvg = 0,      // For dynamic adjustment of graph low & high
    maxLvlAvg = 512;//1023;


Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel LEDs = Adafruit_NeoPixel(N_PIXELS_2, PIN_2, NEO_GRB + NEO_KHZ800);
// Vu meter 4
const uint32_t Red = strip.Color(255, 0, 0);
const uint32_t Yellow = strip.Color(255, 255, 0);
const uint32_t Green = strip.Color(0, 255, 0);
const uint32_t Blue = strip.Color(0, 0, 255);
const uint32_t White = strip.Color(255, 255, 255);
const uint32_t Dark = strip.Color(0, 0, 0);
unsigned int sample;

CRGB leds[N_PIXELS];

int          myhue =   0;
int potLevel=0;              // VALOR LEIDO POTENCIOMETRO
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;

int buttonPushCounter_2 = 0;   
int buttonState_2 = 0;         
int lastButtonState_2 = 0;

//background color
uint32_t currentBg = random(256);
uint32_t nextBg = currentBg;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  delay( 2000 ); // power-up safety delay
  FastLED.addLeds<WS2812B, PIN, COLOR_ORDER>(leds, N_PIXELS).setCorrection( TypicalLEDStrip );
  FastLED.setBrightness(  BRIGHTNESS );
  //analogReference(EXTERNAL);
  memset(vol, 0, sizeof(vol));
  LEDS.addLeds<LED_TYPE, PIN, COLOR_ORDER>(leds, N_PIXELS);
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  
  LEDs.begin(); // inicia LEDs apagados
  LEDs.show();


  //initialize the serial port
  //Serial.begin(115200);
  pinMode(buttonPin, INPUT);
  //initialize the buttonPin as output
  digitalWrite(buttonPin, HIGH);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  LEDs.setBrightness(255);
  buttonState_2 = digitalRead(buttonPin_2);
  if (buttonState_2 != lastButtonState_2) {
    if (buttonState_2 == HIGH) {
      buttonPushCounter_2++;
      if (buttonPushCounter_2 == 8) {
        buttonPushCounter_2 = 1;
      }
    }
  }
  lastButtonState_2 = buttonState_2;

  switch (buttonPushCounter_2) {


    case 1:
      buttonPushCounter == 1; {
          LEDs.setPixelColor(0,51,233,255);   // LED, R , G, B
          LEDs.setPixelColor(1,255,51,178);  // LED, R , G, B
          LEDs.show();
        break;
      }

    case 2:
      buttonPushCounter == 2; {
          LEDs.setPixelColor(0,51,233,255);   // LED, R , G, B
          LEDs.setPixelColor(1,51,233,255);  // LED, R , G, B
          LEDs.show();
        break;
      }
      case 3:
      buttonPushCounter == 3; {
          LEDs.setPixelColor(0,255,51,178);   // LED, R , G, B
          LEDs.setPixelColor(1,255,51,178);  // LED, R , G, B
          LEDs.show();
        break;
      }
      case 4:
      buttonPushCounter == 4; {
          LEDs.setPixelColor(0,255,0,0);   // LED, R , G, B
          LEDs.setPixelColor(1,255,0,0);  // LED, R , G, B
          LEDs.show();
        break;
      }
      case 5:
      buttonPushCounter == 5; {
          LEDs.setPixelColor(0,0,255,0);   // LED, R , G, B
          LEDs.setPixelColor(1,0,255,0);  // LED, R , G, B
          LEDs.show();
        break;
      }
      case 6:
      buttonPushCounter == 6; {
          LEDs.setPixelColor(0,0,0,255);   // LED, R , G, B
          LEDs.setPixelColor(1,0,0,255);  // LED, R , G, B
          LEDs.show();
        break;
      }
      case 7:
      buttonPushCounter == 7; {
          LEDs.clear();
          LEDs.show();
        break;
      }
    
  }
  

  potLevel =(analogRead(analogInPot)/4)+150;
  //for mic
  uint8_t  i;
  uint16_t minLvl, maxLvl;
  int      n, height;
  // end mic

  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);
  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;
      //Serial.println("on");
      //Serial.print("number of button pushes:  ");
      //Serial.println(buttonPushCounter);
      if (buttonPushCounter == 5) {
        buttonPushCounter = 1;
      }
    }
    else {
      // if the current state is LOW then the button
      // wend from on to off:
      //Serial.println("off");
    }
  }
  // save the current state as the last state,
  //for next time through the loop
  lastButtonState = buttonState;


  switch (buttonPushCounter) {


    case 1:
      buttonPushCounter == 1; {
        vu(); // Red
        break;
      }

    case 2:
      buttonPushCounter == 2; {
        vu2(); // Red
        break;
      }
      case 3:
      buttonPushCounter == 3; {
        Vu3(); //
        break;
      }
      case 4:
      buttonPushCounter == 4; {
        Vu4(); //
        break;
      }
    
  }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void vu2() {

  uint8_t  i;
  uint16_t minLvl, maxLvl;
  int      n, height;

  n   = analogRead(MIC_PIN);                        // Raw reading from mic
  n   = abs(n - potLevel - DC_OFFSET); // Center on zero
  n   = (n <= NOISE) ? 0 : (n - NOISE);             // Remove noise/hum
  n   = n*1.5;
  lvl = ((lvl * 7) + n) >> 3;    // "Dampened" reading (else looks twitchy)
  
  //Serial.print("\t Pot = ");
  //Serial.println(potLevel);
  //Serial.print("sensor valor absoluto = ");
  //Serial.print(n);
        
  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L)       height = 0;     // Clip output
  else if (height > TOP) height = TOP;
  if (height > peak)     peak   = height; // Keep 'peak' dot at top


  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS; i++) {
    if (i >= height)               strip.setPixelColor(i,   0,   0, 0);
    else strip.setPixelColor(i, Wheel(map(i, 0, strip.numPixels() - 1, 30, 150)));

  }


  // Draw peak dot
  if (peak > 0 && peak <= N_PIXELS - 1) strip.setPixelColor(peak, Wheel(map(peak, 0, strip.numPixels() - 1, 30, 150)));

  strip.show(); // Update strip

  // Every few frames, make the peak pixel drop by 1:

  if (++dotCount >= PEAK_FALL) { //fall rate

    if (peak > 0) peak--;
    dotCount = 0;
  }



  vol[volCount] = n;                      // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0; // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl)      minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average)

}

// Input a value 0 to 255 to get a color value.
// The colors are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void vu() {

  uint8_t  i;
  uint16_t minLvl, maxLvl;
  int      n, height;



  n   = analogRead(MIC_PIN);                        // Raw reading from mic
  n   = abs(n - potLevel - DC_OFFSET); // Center on zero
  n   = (n <= NOISE) ? (n=0) : (n - NOISE);             // Remove noise/hum          
  n   = n*0.5;  
  lvl = ((lvl * 7) + n) >> 3;    // "Dampened" reading (else looks twitchy)

  //Serial.print("\t Pot = ");
  //Serial.println(potLevel);
  //Serial.print("sensor valor absoluto = ");
  //Serial.print(n);
  
  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L)       height = 0;     // Clip output
  else if (height > TOP) height = TOP;
  if (height > peak)     peak   = height; // Keep 'peak' dot at top


  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS_HALF; i++) {
    if (i >= height) {
      strip.setPixelColor(N_PIXELS_HALF - i - 1,   0,   0, 0);
      strip.setPixelColor(N_PIXELS_HALF + i,   0,   0, 0);
    }
    else {
      uint32_t color = Wheel(map(i, 0, N_PIXELS_HALF - 1, 30, 150));
      strip.setPixelColor(N_PIXELS_HALF - i - 1, color);
      strip.setPixelColor(N_PIXELS_HALF + i, color);
    }

  }



  // Draw peak dot
  if (peak > 0 && peak <= N_PIXELS_HALF - 1) {
    uint32_t color = Wheel(map(peak, 0, N_PIXELS_HALF - 1, 30, 150));
    strip.setPixelColor(N_PIXELS_HALF - peak - 1, color);
    strip.setPixelColor(N_PIXELS_HALF + peak, color);
  }

  strip.show(); // Update strip

  // Every few frames, make the peak pixel drop by 1:

  if (++dotCount >= PEAK_FALL) { //fall rate

    if (peak > 0) peak--;
    dotCount = 0;
  }



  vol[volCount] = n;                      // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0; // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl)      minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average)

}



// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos, float opacity) {

  if (WheelPos < 85) {
    return strip.Color((WheelPos * 3) * opacity, (255 - WheelPos * 3) * opacity, 0);
  }
  else if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color((255 - WheelPos * 3) * opacity, 0, (WheelPos * 3) * opacity);
  }
  else {
    WheelPos -= 170;
    return strip.Color(0, (WheelPos * 3) * opacity, (255 - WheelPos * 3) * opacity);
  }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Vu3() {
  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;

  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - potLevel - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  n   = n*1.5;
  lvl = ((lvl * 7) + n) >> 3;    // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L)       height = 0;      // Clip output
  else if (height > TOP) height = TOP;
  if (height > peak)     peak   = height; // Keep 'peak' dot at top

  greenOffset += SPEED;
  blueOffset += SPEED;
  if (greenOffset >= 255) greenOffset = 0;
  if (blueOffset >= 255) blueOffset = 0;

  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS; i++) {
    if (i >= height) {
      strip.setPixelColor(i, 0, 0, 0);
    } else {
      strip.setPixelColor(i, Wheel(
                            map(i, 0, strip.numPixels() - 1, (int)greenOffset, (int)blueOffset)
                          ));
    }
  }
  // Draw peak dot
  if (peak > 0 && peak <= N_PIXELS - 1) strip.setPixelColor(peak, Wheel(map(peak, 0, strip.numPixels() - 1, 30, 150)));

  strip.show(); // Update strip

  // Every few frames, make the peak pixel drop by 1:

  if (++dotCount >= PEAK_FALL) { //fall rate

    if (peak > 0) peak--;
    dotCount = 0;
  }
  strip.show();  // Update strip

  vol[volCount] = n;
  if (++volCount >= SAMPLES) {
    volCount = 0;
  }

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) {
      minLvl = vol[i];
    } else if (vol[i] > maxLvl) {
      maxLvl = vol[i];
    }
  }

  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP) {
    maxLvl = minLvl + TOP;
  }
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average)
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Vu4() {
  uint8_t  i;
  uint16_t minLvl, maxLvl;
  int      n, height;

  n   = analogRead(MIC_PIN);                        // Raw reading from mic
  n   = abs(n - potLevel - DC_OFFSET); // Center on zero
  n   = (n <= NOISE) ? 0 : (n - NOISE);             // Remove noise/hum
  n   = n*0.5;  
  lvl = ((lvl * 7) + n) >> 3;    // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L)       height = 0;     // Clip output
  else if (height > TOP) height = TOP;
  if (height > peak)     peak   = height; // Keep 'peak' dot at top
  greenOffset += SPEED;
  blueOffset += SPEED;
  if (greenOffset >= 255) greenOffset = 0;
  if (blueOffset >= 255) blueOffset = 0;

  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS_HALF; i++) {
    if (i >= height) {
      strip.setPixelColor(N_PIXELS_HALF - i - 1,   0,   0, 0);
      strip.setPixelColor(N_PIXELS_HALF + i,   0,   0, 0);
    }
    else {
      uint32_t color = Wheel(map(i, 0, N_PIXELS_HALF - 1, (int)greenOffset, (int)blueOffset));
      strip.setPixelColor(N_PIXELS_HALF - i - 1, color);
      strip.setPixelColor(N_PIXELS_HALF + i, color);
    }

  }

  // Draw peak dot
  if (peak > 0 && peak <= N_PIXELS_HALF - 1) {
    uint32_t color = Wheel(map(peak, 0, N_PIXELS_HALF - 1, 30, 150));
    strip.setPixelColor(N_PIXELS_HALF - peak - 1, color);
    strip.setPixelColor(N_PIXELS_HALF + peak, color);
  }

  strip.show(); // Update strip

  // Every few frames, make the peak pixel drop by 1:

  if (++dotCount >= PEAK_FALL) { //fall rate

    if (peak > 0) peak--;
    dotCount = 0;
  }


  vol[volCount] = n;                      // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0; // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl)      minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average)

}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


Programacion Arduino

Captura de pantalla 2022-08-09 231502.png
Captura de pantalla 2022-08-09 231403.png

Antes de cargar el código de programación debemos de modificar el parámetro del número de pixeles de la tira LED, debemos de colocar la cantidad de LEDs que cuenta la tira LED individual (No el total). También podremos modificar el ruido (NOISE) si es necesario.

Una vez modificado los parámetros conectamos el Arduino nano al puerto USB de la computadora y vamos a ir Herramientas, Placa, Arduino AVR Boards y seleccionamos Aduino nano par el caso del Arduino original o Arduino Duemilanove para la versión China, Seleccionamos el puerto donde hemos conectado el Arduino y Subimos el código de programación.

Ajuste Final Potenciometros

Captura de pantalla 2022-08-09 232909.png
Captura de pantalla 2022-08-09 232305.png
Captura de pantalla 2022-08-09 232234.png

Con el potenciómetro de 1M ohm podemos variar la ganancia del transistor, debemos de llevarlo hacia la derecha cercano a su valor máximo, ahora con el potenciómetro de 50K ohm vamos a llevarlo hacia el valor máximo a la derecha y nos regresamos hacia la izquierda hasta que las tiras LED queden apagadas. Una vez hecho este paso podremos probar nuestro circuito utilizando música, si el comportamiento no es el deseado pruebe variado los potenciómetros hasta obtener un resultado optimo.

FIN

Captura de pantalla 2022-08-09 232634.png
Captura de pantalla 2022-08-09 232517.png

Finalmente, puedes probar estas luces con la música o con la reacción a la voz. El circuito cuenta con 2 botones, un para cambiar el color de la base del circuito y otro botón para cambiar el efecto las tiras LED.

Si este proyecto les ha gustado, realizare una actualización del código de programación, con mayores efectos.

¡Saludos y nos vemos en un próximo proyecto!