/*
v1
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <math.h>
// --- Configuraciones de Hardware ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define OLED_ADDR 0x3C
// --- Pines de entrada de Voltaje DC para ESP32 ---
#define voltageInL 36 // Canal Izquierdo (ADC1_CH0)
#define voltageInR 39 // Canal Derecho (ADC1_CH3)
// --- Parámetros del Medidor ---
#define SAMPLES_AVG 64
#define ADC_MAX_VALUE 4095
// Referencia para 0dB
#define ADC_REF_0DB 1106.0
// Parámetros para barras HORIZONTALES
#define BAR_LENGTH 100 // Longitud total de la barra en píxeles
#define BAR_HEIGHT 20 // Altura de la barra en píxeles
#define SEGMENT_WIDTH 3
#define SEGMENT_SPACING 1
// Rango de dB que se mostrará en la pantalla
#define DB_MIN -30.0
#define DB_MAX 11.4
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Función para dibujar una barra horizontal
void drawVUMeterBar(int x_start, int y_start, double dbValue) {
int totalSegments = BAR_LENGTH / (SEGMENT_WIDTH + SEGMENT_SPACING);
int segmentsToDraw = map(dbValue, DB_MIN, DB_MAX, 0, totalSegments);
segmentsToDraw = constrain(segmentsToDraw, 0, totalSegments);
display.drawRect(x_start - 1, y_start - 1, BAR_LENGTH + 2, BAR_HEIGHT + 2, WHITE);
for (int i = 0; i < segmentsToDraw; i++) {
int xPos = x_start + (i * (SEGMENT_WIDTH + SEGMENT_SPACING));
display.fillRect(xPos, y_start, SEGMENT_WIDTH, BAR_HEIGHT, WHITE);
}
}
void setup() {
//Serial.begin(115200);
display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
display.clearDisplay();
display.display();
}
void loop() {
// --- 1. Muestreo y promedio del valor DC ---
unsigned long totalL = 0;
unsigned long totalR = 0;
for (int i = 0; i < SAMPLES_AVG; i++) {
totalL += analogRead(voltageInL);
totalR += analogRead(voltageInR);
}
unsigned int avgL = totalL / SAMPLES_AVG;
unsigned int avgR = totalR / SAMPLES_AVG;
// --- 2. Convertir el valor promedio a Decibelios (dB) ---
double dbL = (avgL == 0) ? DB_MIN : 20 * log10((double)avgL / ADC_REF_0DB);
double dbR = (avgR == 0) ? DB_MIN : 20 * log10((double)avgR / ADC_REF_0DB);
// --- 3. Visualización en la Pantalla OLED ---
display.clearDisplay();
int label_x = 9; // Posición X para las etiquetas L y R y dB
int bar_x_start = 26; // Posición X inicial para ambas barras
display.setTextSize(1);
display.setTextColor(WHITE);
// --- Canal Izquierdo (L) ---
drawVUMeterBar(bar_x_start, 4, dbL);
display.setCursor(1, 12);
int roundedDbL = round(dbL); // Redondear el valor de dB a un entero
if (roundedDbL > 0) {
display.print("+"); // Si es positivo, añadir el signo '+'
}
display.print(roundedDbL); // Imprimir el valor (con signo - si es negativo, o sin signo si es 0)
display.setCursor(label_x, 3);
display.print("L");
display.setCursor(6, 20);
display.print("dB");
// --- Canal Derecho (R) ---
drawVUMeterBar(bar_x_start, 39, dbR);
display.setCursor(1, 47);
int roundedDbR = round(dbR);
if (roundedDbR > 0) {
display.print("+");
}
display.print(roundedDbR);
display.setCursor(label_x, 37);
display.print("R");
display.setCursor(6, 55);
display.print("dB");
// NOMBRE
display.setCursor(52, 28);
display.print("PATRO DJ");
display.display();
delay(50);
}
*/
//v2 peak & hold
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <math.h>
// --- Configuraciones de Hardware ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define OLED_ADDR 0x3C
// --- Pines de entrada de Voltaje DC para ESP32 ---
#define voltageInL 36 // Canal Izquierdo (ADC1_CH0)
#define voltageInR 39 // Canal Derecho (ADC1_CH3)
// --- Parámetros del Medidor ---
#define SAMPLES_AVG 64
#define ADC_MAX_VALUE 4095
// Referencia para 0dB
#define ADC_REF_0DB 1106.0
// Parámetros para barras HORIZONTALES
#define BAR_LENGTH 100 // Longitud total de la barra en píxeles
#define BAR_HEIGHT 20 // Altura de la barra en píxeles
#define SEGMENT_WIDTH 3
#define SEGMENT_SPACING 1
// Rango de dB que se mostrará en la pantalla
#define DB_MIN -30.0
#define DB_MAX 11.4
// --- NUEVOS PARÁMETROS PARA PEAK & HOLD ---
#define PEAK_HOLD_MS 1500 // Tiempo en milisegundos que el pico se mantiene antes de caer
#define PEAK_DECAY_RATE 0.35 // Cuántos dB baja el pico en cada ciclo del loop (después del hold)
// Un valor más alto hace que caiga más rápido.
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// --- NUEVAS VARIABLES GLOBALES PARA EL ESTADO DEL PICO ---
double peakL = DB_MIN;
double peakR = DB_MIN;
unsigned long lastPeakTimeL = 0;
unsigned long lastPeakTimeR = 0;
// --- FUNCIÓN DE DIBUJO MODIFICADA para incluir el indicador de pico ---
void drawVUMeterBar(int x_start, int y_start, double dbValue, double peakDbValue) {
int totalSegments = BAR_LENGTH / (SEGMENT_WIDTH + SEGMENT_SPACING);
// Dibuja el borde de la barra
display.drawRect(x_start - 1, y_start - 1, BAR_LENGTH + 2, BAR_HEIGHT + 2, WHITE);
// Calcula y dibuja los segmentos de la barra de nivel en tiempo real
int activeSegments = map(dbValue, DB_MIN, DB_MAX, 0, totalSegments);
activeSegments = constrain(activeSegments, 0, totalSegments);
for (int i = 0; i < activeSegments; i++) {
int xPos = x_start + (i * (SEGMENT_WIDTH + SEGMENT_SPACING));
display.fillRect(xPos, y_start, SEGMENT_WIDTH, BAR_HEIGHT, WHITE);
}
// --- NUEVO: Calcula y dibuja el indicador de PICO ---
// Solo se dibuja un segmento para el pico
int peakSegment = map(peakDbValue, DB_MIN, DB_MAX, 0, totalSegments);
peakSegment = constrain(peakSegment, 0, totalSegments);
int peakXPos = x_start + (peakSegment * (SEGMENT_WIDTH + SEGMENT_SPACING));
// Nos aseguramos de no dibujarlo fuera de la barra
if (peakXPos < x_start + BAR_LENGTH) {
display.fillRect(peakXPos, y_start, SEGMENT_WIDTH, BAR_HEIGHT, WHITE);
}
}
void setup() {
//Serial.begin(115200);
display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
display.clearDisplay();
display.display();
}
void loop() {
// --- 1. Muestreo y promedio del valor DC ---
unsigned long totalL = 0;
unsigned long totalR = 0;
for (int i = 0; i < SAMPLES_AVG; i++) {
totalL += analogRead(voltageInL);
totalR += analogRead(voltageInR);
}
unsigned int avgL = totalL / SAMPLES_AVG;
unsigned int avgR = totalR / SAMPLES_AVG;
// --- 2. Convertir el valor promedio a Decibelios (dB) ---
double dbL = (avgL == 0) ? DB_MIN : 20 * log10((double)avgL / ADC_REF_0DB);
double dbR = (avgR == 0) ? DB_MIN : 20 * log10((double)avgR / ADC_REF_0DB);
// --- NUEVO: LÓGICA DE ACTUALIZACIÓN DE PEAK & HOLD ---
unsigned long currentTime = millis();
// Canal Izquierdo (L)
if (dbL >= peakL) {
peakL = dbL;
lastPeakTimeL = currentTime; // Reinicia el temporizador de mantenimiento
} else {
// Si ha pasado el tiempo de mantenimiento, empieza a decaer
if (currentTime - lastPeakTimeL > PEAK_HOLD_MS) {
peakL -= PEAK_DECAY_RATE;
// Asegurarse de que el pico no caiga por debajo del nivel actual ni del mínimo
if (peakL < dbL) peakL = dbL;
if (peakL < DB_MIN) peakL = DB_MIN;
}
}
// Canal Derecho (R)
if (dbR >= peakR) {
peakR = dbR;
lastPeakTimeR = currentTime; // Reinicia el temporizador de mantenimiento
} else {
// Si ha pasado el tiempo de mantenimiento, empieza a decaer
if (currentTime - lastPeakTimeR > PEAK_HOLD_MS) {
peakR -= PEAK_DECAY_RATE;
// Asegurarse de que el pico no caiga por debajo del nivel actual ni del mínimo
if (peakR < dbR) peakR = dbR;
if (peakR < DB_MIN) peakR = DB_MIN;
}
}
// --- 3. Visualización en la Pantalla OLED ---
display.clearDisplay();
int label_x = 9; // Posición X para las etiquetas L y R y dB
int bar_x_start = 26; // Posición X inicial para ambas barras
display.setTextSize(1);
display.setTextColor(WHITE);
// --- Canal Izquierdo (L) ---
// Se pasa el valor del pico a la función de dibujo
drawVUMeterBar(bar_x_start, 4, dbL, peakL);
display.setCursor(1, 12);
int roundedDbL = round(dbL);
if (roundedDbL > 0) {
display.print("+");
}
display.print(roundedDbL);
display.setCursor(label_x, 3);
display.print("L");
display.setCursor(6, 20);
display.print("dB");
// --- Canal Derecho (R) ---
// Se pasa el valor del pico a la función de dibujo
drawVUMeterBar(bar_x_start, 39, dbR, peakR);
display.setCursor(1, 47);
int roundedDbR = round(dbR);
if (roundedDbR > 0) {
display.print("+");
}
display.print(roundedDbR);
display.setCursor(label_x, 37);
display.print("R");
display.setCursor(6, 55);
display.print("dB");
// NOMBRE
display.setCursor(52, 28);
display.print("PATRO DJ");
display.display();
delay(50);
}