Tira LED neopixel no funciona al ritmo de la música

Este circuito no modifica el offset con elpotenciómetro.


Modifica la amplitud de la señal de entrada.
Asi que esta bien que siempre recibas 512 o sea 2.5V porque eso es lo que dice el divisor de tensión.
Para modificar el offset deberías poner dos resistores bajos de digamos 4k7 a GND y a VCC (5V) y un potenciómetro al centro. Y en el cursor iría conectado tanto el AX como la entrada de la seña de entrada.
Hablo de un potenciómetro de 10K por supuesto para mantener los 20K totales mas o menos.
Con ello regularias entre 4.7k/19.4k*5V = 1.211V y 3.7V aprox

Se me ocurre que si usas un rectificador en puente siempre tendras el positivo de la señal aplicado al pin analogico, la tension de salida del rectificador sera proporcional a la tension que le entre y para probar le intercalaria un potenciometro de 1M puesto al maximo para no sobrecargar el pin analogico y luego ir probando a bajar la resistencia.
imagen

Una vez vista mas o menos que resistencia le estas interponiendo con el potenciometro puedes buscar un potenciometro del doble de valor pero que sea multivuelta para un ajuste mas fino

Y así se destroza una señal de audio... :rofl:

Por supuesto que no varía el offset con el potenciómetro por eso aclaré que el mismo es para regular el nivel de entrada..
Ese circuito pone un offset de 2.5V a la señal de audio.
En pocas palabras "monta" la señal de audio sobre la tensión del divisor.

Saludos

Nunca te olvides de conectar las masas (salvo que el circuito sea aislado) sino falta la referencia y el procesador no "ve" la señal, sea en un pin analógico o digital.

Saludos

@anon90500195 entiendo que lo que quiere hacer es una especie de vumetro con una tira de led por lo que unico que necesita es medir el voltaje del audio y no el audio en si

Es muy cierto, no lo había tenido en cuenta
En ese caso con un diodo (preferiblemente de germanio o en su defecto tipo Schottky, para minimizar la caída de tensión) basta y sobra.

Saludos

PD: Obviamente no habría offset en la señal, claramente.

Efectivamente @anon90500195 con un diodo seria suficiente pero se perderian los ciclos negativos, que no se si serian importantes.

Con un diodo la señal resultante seria así
imagen

Y con un rectificador puente quedaria así
imagen

Pero como vas a muestrar los máximos cada x tiempo, no es importante la perdida.
Te digo más, los viejos vúmetros a aguja, generalmente usaban un solo diodo para dejar pasar solo la parte positiva de la señal.

Saludos

Es posible @anon90500195 que tengas razon, no se la velocidad de muestreo ni la precision que se necesita, y leyendo tu post se me ha ocurrido otra idea y es la de muestrear los dos canales para para que mida la media entre los dos.
imagen

Sinceramente no se que resultado dará

Una captura de la simulación del circuito propuesto en #17 al que le hice un pequeño cambio, el capacitor de 10uF en lugar de 1uF

En azul la señal de entrada (punto de unión del potenciómetro RV1 y C1).
En verde nivel GND, como referencia.
En amarillo la señal "montada" sobre la tensión offset (punto de unión de R1, R2 , C1 y D1).
En rojo la tensión offset (2.5V), para referencia.

Saludos

Buenos días a todos. En primer lugar muchas gracias por todos por las respuestas. De todas he sacado algo. El circuito propuesto por @anon90500195 en el último post ha resultado el que finalmente he estado usando. Traté de utilizar un LM358P para amplificar la señal proveniente del jack, pero rompí uno de los dos potenciómetros que estaba usando para controlar ganancia en tensión y offset, por lo que no pude seguir con ello.

Con el circuito de gatul consigo unos valores muy pequeños, siempre cercanos a los 510 debido al offset que le estoy aplicando, pero suficientemente grandes para empezar con ellos.
He pensado en hacer una interpolación usando la función map(), en la que tendremos como rango de entrada el valor mínimo y máximo registrados durante la ventana de 40 ms que uso como referencia, y como rango de salida un número entre 0 y 1023.

De esta manera pretendo que, si en 40 ms de muestreo el valor máximo y mínimo son respectivamente 515 y 485, convertir este a uno entre 0 y 100 para que el vúmetro haga algo mas que quedarse siempre parado entorno al medio de la tira.

Sin embargo, esta solución me parece bastante mala, pero la única que se me ocurre hasta que me lleguen los nuevos potenciómetros.

Dejo por aquí el código:

int pinJack = A0;
int valorJack = 0;
int maximo_anterior = 0;
int minimo_anterior = 1023;
int maximo_final=0;
int minimo_final=0;


unsigned long tiempoAhora =0;

void setup(){
  Serial.begin(9600);
  tiempoAhora = millis();
}

void loop(){
  while(millis()-tiempoAhora< 50){
    valorJack = analogRead(pinJack);
    Serial.print("ValorJack: ");
    Serial.println(valorJack);
    if(valorJack>maximo_anterior){//Si el valor leido por el ADC en el pin del jack es mayor que el guardado anteriormente (maximo_anterior lo iniciamos en 0)...
       maximo_anterior=valorJack;//...guardamos el nuevo máximo
    }
    if(valorJack<minimo_anterior){
      minimo_anterior = valorJack;
    }
    valorJack=0;//e iniciamos en cero de nuevo la variable de registro de datos
  }


  maximo_final=map(maximo_anterior, 450, 570, 0, 100);
  maximo_final=constrain(maximo_final, 0 ,100);
  minimo_final=map(minimo_anterior, 450, 570, 0, 100);
  minimo_final=constrain(minimo_final, 0 ,100);
  Serial.print("Valor máximo = ");
  Serial.println(maximo_anterior);
  Serial.print("Valor mínimo = ");
  Serial.println(minimo_anterior);
  Serial.print("Maximo anterior mapeado = ");
  Serial.println(maximo_final);
  Serial.print("Minimo anterior mapeado = ");
  Serial.println(minimo_final);
  delay(2000);
//  vumetro();
  //------------Reiniciamos las variable---------/////
  maximo_anterior = 0;
  minimo_anterior = 1023;
  tiempoAhora=millis();//Guardamos el nuevo tiempo anterior antes de entrar de nuevo en el while
}

Bueno, tras realizar de nuevo la función vumetro() y ajustar un poco más los valores de partida en el mapeo (registré el minimo y el máximo en un largo periodo de tiempo con distintos tipos de música), he conectado de nuevo la tira LED para ver los resultados, y curiosamente me pasa lo mismo que me pasaba antes de rehacer el código: solo se realiza una vez el ciclo. Adjunto un par de imágenes para retratar lo que digo.

Anteriormente, pensaba que el problema venía del while(), por eso rehíce el código poco a poco comprobando que todo funcionaba correctamente por separada y añadiendo poco a poco las distintas funciones. Por lo que veo el problema lo causa añadir la función vúmetro, no sé si por que estoy interactuando mal con ella o a que se puede deber el problema.

Sigo investigando. Dejo por aquí el código con la nueva función:

#include <Adafruit_NeoPixel.h>///https://github.com/adafruit/Adafruit_NeoPixel

#define pin_led 6//Defininmos el pin de conexión de la tira LED
#define numero_led 30//Definimos el número de LED´s de nuestra tira. En nuestro caso es 30 LED´s en 0,5m 

int pinJack = A0;
int valorJack = 0;
int maximo_anterior = 0;
int minimo_anterior = 1023;
int maximo_final=0;
int minimo_final=0;


unsigned long tiempoAhora =0;

//Creamos un objeto de la tira
//Primer parámetro = cantidad de pixeles en la tira
//Segundo parámetro = pin de conexión a Arduino
//Tercer parámetro:
  //NEO_KHZ800  800 KHz velocidad de datos (WS2812 y nuevos)
  //NEO_KHZ400  400 KHz velocidad de datos (WS2811 y anteriores)
  //NEO_GRB     flujo de datos en el orden GRB (WS2812 y nuevos)
  //NEO_RGB     fluo de datos en el orden RGB (versiones más antiguas)
Adafruit_NeoPixel tira_LED = Adafruit_NeoPixel(numero_led, pin_led, NEO_GRB + NEO_KHZ800);

void vumetro(void);

void setup(){
  Serial.begin(9600);
  tira_LED.begin();//Iniciamos la tira LED
  tira_LED.show();//mandamos un valor 0 a la  tira LED, es decir, iniciamos con la tira LED apagada
  tiempoAhora = millis();
}

void loop(){
  while(millis()-tiempoAhora< 50){
    valorJack = analogRead(pinJack);
    Serial.print("ValorJack: ");
    Serial.println(valorJack);
    if(valorJack>maximo_anterior){//Si el valor leido por el ADC en el pin del jack es mayor que el guardado anteriormente (maximo_anterior lo iniciamos en 0)...
       maximo_anterior=valorJack;//...guardamos el nuevo máximo
    }
    if(valorJack<minimo_anterior){
      minimo_anterior = valorJack;
    }
    valorJack=0;//e iniciamos en cero de nuevo la variable de registro de datos
  }


  maximo_final=map(maximo_anterior, 350, 700, 0, 100);
  maximo_final=constrain(maximo_final, 0 ,100);
  minimo_final=map(minimo_anterior, 350, 700, 0, 100);
  minimo_final=constrain(minimo_final, 0 ,100);
  Serial.print("Valor máximo = ");
  Serial.println(maximo_anterior);
  Serial.print("Valor mínimo = ");
  Serial.println(minimo_anterior);
  Serial.print("Maximo anterior mapeado = ");
  Serial.println(maximo_final);
  Serial.print("Minimo anterior mapeado = ");
  Serial.println(minimo_final);
  delay(2000);
  vumetro();
  //------------Reiniciamos las variable---------/////
  maximo_anterior = 0;
  minimo_anterior = 1023;
  tiempoAhora=millis();//Guardamos el nuevo tiempo anterior antes de entrar de nuevo en el while
}

void vumetro(){
  int i = 0;
  if(maximo_final>0){
    for(i=0; i = 5; i++){
      tira_LED.setPixelColor(i, tira_LED.Color(255, 0 ,0));
      tira_LED.show();
    }
  }
  if(maximo_final>15){
    for(i=0; i = 10; i++){
      tira_LED.setPixelColor(i, tira_LED.Color(0, 255 ,0));
      tira_LED.show();
    }
  }
  if(maximo_final>30){
    for(i=10; i = 15; i++){
      tira_LED.setPixelColor(i, tira_LED.Color(0, 255 ,255));
    }
  }
  if(maximo_final>45){
    for(i=15; i = 20; i++){
      tira_LED.setPixelColor(i, tira_LED.Color(255, 255 ,0));
    }
  }
  if(maximo_final>60){
    for(i=20; i =25 ; i++){
      tira_LED.setPixelColor(i, tira_LED.Color(0, 255 ,255));
    }
  }
  if(maximo_final>75){
    for(i=25; i = 27; i++){
      tira_LED.setPixelColor(i, tira_LED.Color(170, 255 ,100));
    }
  }
  if(maximo_final>85){
    for(i=27; i = 29; i++){
      tira_LED.setPixelColor(i, tira_LED.Color(100, 255 ,170));
    }
  }
  if(maximo_final>95){
      tira_LED.setPixelColor(30, tira_LED.Color(255, 255 ,255));
  }
  //tira_LED.show();
}




Creo que el problema está en que entro en bucle infinito cuando comprueba el primer if de la función vumetro(), ya que la entrada siempre es mayor que 15, lo cual hace que entre continuamente en el for que enciende los LEDS. Aún así sigo sin entender por qué solo se enciende un LED, el último.

El problema era la condición del for. Ya se encienden todos los LED´s al menos. La nueva función vumetro() es la siguiente:

void vumetro(){
  Serial.print("He entrado");
  int i = 0;
  int numero_led_encendidos = map(maximo_anterior, 0, 100, 0, 30);
  numero_led_encendidos = constrain(numero_led_encendidos, 0 ,30);
  Serial.println(numero_led_encendidos);
  delay(1000);
  for(i=0; i<numero_led_encendidos; i++){
    Serial.print("Aquí también");
    tira_LED.setPixelColor(i, tira_LED.Color(0, 255, 0));
    tira_LED.show();
  }
}

Tiene algunas lineas de depuración. No está ni mucho menos arreglado el problema, pero es un avance.

Bueno, tras cambiar unos pocos errores que tenía, he conseguido que haga lo que esperaba: encenderse el número de LED´s que indica el máximo de la señal analógica leida. He conseguido incluso jugar un poco con la tira LED añadiendo una función random() para la elección de los colores. Sin embargo, de reprente ha dejado de funcionar y ya siempre lee el valor 510, es decir, el del offset añadido. No sé por qué ha podido pasar esto. Dejo por aquí el código y voy a despejar la mente, a ver si me viene la idea feliz.

#include <Adafruit_NeoPixel.h>///https://github.com/adafruit/Adafruit_NeoPixel

#define pin_led 6//Defininmos el pin de conexión de la tira LED
#define numero_led 30//Definimos el número de LED´s de nuestra tira. En nuestro caso es 30 LED´s en 0,5m 

int pinJack = A1;
int valorJack = 0;
int maximo_anterior = 0;
int minimo_anterior = 1023;
int maximo_final=0;
int minimo_final=0;


unsigned long tiempoAhora =0;

//Creamos un objeto de la tira
//Primer parámetro = cantidad de pixeles en la tira
//Segundo parámetro = pin de conexión a Arduino
//Tercer parámetro:
  //NEO_KHZ800  800 KHz velocidad de datos (WS2812 y nuevos)
  //NEO_KHZ400  400 KHz velocidad de datos (WS2811 y anteriores)
  //NEO_GRB     flujo de datos en el orden GRB (WS2812 y nuevos)
  //NEO_RGB     fluo de datos en el orden RGB (versiones más antiguas)
Adafruit_NeoPixel tira_LED = Adafruit_NeoPixel(numero_led, pin_led, NEO_GRB + NEO_KHZ800);

void vumetro(void);

void setup(){
  Serial.begin(9600);
  tira_LED.begin();//Iniciamos la tira LED
  tira_LED.show();//mandamos un valor 0 a la  tira LED, es decir, iniciamos con la tira LED apagada
  tiempoAhora = millis();
}

void loop(){
  while(millis()-tiempoAhora< 50){
    valorJack = analogRead(pinJack);
    Serial.print("ValorJack: ");
    Serial.println(valorJack);
    if(valorJack>maximo_anterior){//Si el valor leido por el ADC en el pin del jack es mayor que el guardado anteriormente (maximo_anterior lo iniciamos en 0)...
       maximo_anterior=valorJack;//...guardamos el nuevo máximo
    }
    if(valorJack<minimo_anterior){
      minimo_anterior = valorJack;
    }
    valorJack=0;//e iniciamos en cero de nuevo la variable de registro de datos
  }


  maximo_final=map(maximo_anterior, 350, 700, 0, 100);
  maximo_final=constrain(maximo_final, 0 ,100);
  minimo_final=map(minimo_anterior, 350, 700, 0, 100);
  minimo_final=constrain(minimo_final, 0 ,100);
  Serial.print("Valor máximo = ");
  Serial.println(maximo_anterior);
  Serial.print("Valor mínimo = ");
  Serial.println(minimo_anterior);
  Serial.print("Maximo anterior mapeado = ");
  Serial.println(maximo_final);
  Serial.print("Minimo anterior mapeado = ");
  Serial.println(minimo_final);
  delay(2000);
  vumetro();
  
  tira_LED.clear();
  //------------Reiniciamos las variable---------/////
  maximo_anterior = 0;
  minimo_anterior = 1023;
  tiempoAhora=millis();//Guardamos el nuevo tiempo anterior antes de entrar de nuevo en el while
}

void vumetro(){
  Serial.print("He entrado");
  int i = 0;
  int numero_led_encendidos = map(maximo_final, 0, 100, 0, 30);
  numero_led_encendidos = constrain(numero_led_encendidos, 0 ,30);
  Serial.println(numero_led_encendidos);
  for(i=0; i<numero_led_encendidos; i++){
    //Serial.print("Aquí también");
    tira_LED.setPixelColor(i, tira_LED.Color(random(255), random(255), random(255)));
    tira_LED.show();
  }
}




Tu has visto que pones que el loop se ejecute dentro de los 50 mseg y en ese mismo loop tienes un delay(2000)? What!!!

Buenas Surbyte! Si soy consciente de ello. Lo he utilizado para parar la transmisión de datos y comprobar los máximos y mínimos yo visualmente. Lo he hecho a modo de depuración. Lógicamente ese delay() no existirá en la versión final.

Ahh perfecto.

Bueno... finalmente he encontrado otro de los errores. Al conectar el audio Jack, estaba identificando mi ordenador como que le había conectado el audio de la pantalla auxiliar que tengo. Por tanto nunca estaba sonando y por eso me estaba dando siempre el valor de la tensión de offset.
Solucionado esto, ya puedo ver variaciones en mi tira LED. Con el volumen del ordenador a tope y el potenciómetro a tope llega a completar la tira completa. El problema viene por los LED´s de abajo de la tira. Prácticamente los LED´s 0 a 12 no se apagan nunca porque no varía tanto la señal de audio parece ser.

A pesar de este error, he de decir que el efecto por ahora no queda bonito. No parece que vaya al ritmo de la música (no puedo comprobarlo porque el único altavoz que tengo es mono y no estereo).

Sea como sea, sigo avanzando.. en los próximos días comentaré como va el proyecto.