¿Cuánto ruido hay de verdad en una sala de clases, en el taller o en la pieza de al lado? El oído se acostumbra y engaña, pero un micrófono digital no. El INMP441 es un micrófono MEMS del tamaño de una uña que entrega el audio ya convertido a números por el bus I2S, y el ESP32 lo lee sin un solo componente extra.
En esta guía armas el circuito paso a paso y lo haces trabajar en cuatro proyectos: medir la intensidad del sonido (RMS), ver la forma de onda en el Serial Plotter y en Python, encender y apagar un LED con dos aplausos y, como extra propio de esta versión, un medidor de ruido en decibeles que avisa por MQTT cuando una sala pasa del umbral. Al final vas a entender qué viaja por cada cable del I2S, por qué el código desplaza cada muestra 8 bits y cómo calibrar un umbral sin adivinar.
Qué es el INMP441 y por qué conviene más que un micrófono analógico
El INMP441 es un micrófono omnidireccional MEMS (sistema microelectromecánico): una membrana de silicio microscópica que vibra con el sonido, un preamplificador y un conversor análogo digital, todo dentro de la misma cápsula. Lo que sale por sus pines no es un voltaje que sube y baja, sino muestras de audio de 24 bits en formato I2S.

Esa diferencia tiene consecuencias prácticas:
- Omnidireccional: capta sonido desde cualquier dirección, así que no tienes que apuntarlo con precisión.
- Salida digital directa: el ruido eléctrico de la protoboard o de la fuente no se mete en la señal, como pasa con los módulos analógicos tipo KY-038 o MAX4466 conectados al ADC.
- Buena relación señal/ruido y bajo consumo, ideal para proyectos IoT que funcionan todo el día.
- Sin calibrar el ADC: el ADC del ESP32 es poco lineal en los extremos; con el INMP441 esa etapa simplemente no existe.
Los pines vienen sueltos y hay que soldarlos. Al montarlo en la protoboard, deja el agujerito del micrófono mirando hacia ti: ese orificio es la entrada de sonido y no conviene taparlo.

Cómo viaja el audio por I2S
I2S (Inter IC Sound) es un protocolo serie síncrono pensado solo para audio digital entre dos chips. Usa tres señales:
- SCK o BCLK (reloj de bit): marca el ritmo; en cada pulso viaja un bit.
- WS o LRCLK (selección de palabra): indica si la palabra que va pasando es del canal izquierdo o del derecho.
- SD (datos): el audio propiamente tal, bit a bit.
El INMP441 necesita 64 pulsos de reloj por cada ciclo de WS: 32 para el canal izquierdo y 32 para el derecho. Con la configuración de este tutorial (16.000 muestras por segundo y palabras de 32 bits), el ESP32 genera un reloj de 16.000 × 64 = 1,024 MHz. El micrófono solo "habla" en el canal que eligió con su pin L/R y deja el otro en silencio.
Ese detalle explica una línea clave del código que viene más adelante: el INMP441 entrega 24 bits útiles, pero el hueco es de 32. Los 24 bits van alineados a la izquierda (los más significativos primero) y los 8 de abajo quedan en cero. Por eso cada muestra se desplaza con >> 8: así el número queda en su escala real de 24 bits, entre, 8.388.608 y 8.388.607.
El ESP32 trae periféricos I2S propios que pueden funcionar como entrada (leer un micrófono) o como salida (mandar audio a un amplificador). Si quieres el detalle a nivel de registros, la documentación de Espressif sobre I2S está enlazada en la sección de recursos.
Hardware: pines y conexiones
El módulo tiene seis pines:
| Pin | Función | Dónde va |
|---|---|---|
| L/R | Elige el canal I2S: a GND es izquierdo, a 3V3 es derecho | GND (el código lee el canal izquierdo) |
| WS | Word Select (LRCLK) | Un GPIO del ESP32 |
| SCK | Reloj serie (BCLK) | Un GPIO del ESP32 |
| SD | Datos de audio que salen del micrófono | Un GPIO del ESP32 (entrada) |
| GND | Tierra | GND del ESP32 |
| VDD | Alimentación | 3V3 del ESP32 (nunca 5V) |
El ESP32 no tiene pines I2S fijos: la matriz de GPIO permite llevar cada señal a casi cualquier pin seguro. El tutorial original usa una ESP32-S3 DevKitC con esta distribución:
| INMP441 | ESP32-S3 |
|---|---|
| L/R | GND |
| WS | GPIO 40 |
| SCK | GPIO 42 |
| SD | GPIO 41 |
| GND | GND |
| VDD | 3V3 |


Si tienes un ESP32 clásico (DevKit V1 de 30 o 38 pines), los GPIO 40 a 42 no existen. Una combinación que funciona sin pelear con los pines de arranque es SCK en GPIO 26, WS en GPIO 25 y SD en GPIO 33. Solo cambias los tres #define del inicio de cada sketch. Evita los GPIO 0, 2, 12 y 15, que el chip lee al arrancar y pueden impedir que el programa cargue.
Software: lo que necesitas antes de programar
Necesitas Arduino IDE 2 con el soporte de placas ESP32 instalado (desde el gestor de placas, buscando "esp32" de Espressif). No hace falta ninguna librería externa: los tres ejemplos usan driver/i2s.h, el driver I2S de ESP IDF que ya viene dentro del core de Arduino para ESP32.
Un dato para evitar sustos: driver/i2s.h es el driver "heredado" de ESP IDF. En el core 3.x de Arduino para ESP32 sigue compilando, pero puede mostrar un aviso de que está obsoleto. No es un error y el programa funciona igual. Si más adelante quieres migrar, el reemplazo es driver/i2s_std.h o la librería ESP_I2S.h del propio core.
Los tres sketches comparten la misma configuración, que conviene entender una vez:
- Frecuencia de muestreo de 16.000 Hz: es el estándar para voz. Por el teorema de Nyquist captura frecuencias hasta 8 kHz, de sobra para voz, aplausos y ruido ambiente.
- Buffer de 512 muestras: a 16 kHz son 32 milisegundos de audio por lectura. Esa es la "ventana" sobre la que se calcula cada valor.
- 32 bits por muestra y solo canal izquierdo: coincide con el hueco de 32 bits del I2S y con el pin L/R a GND. Si cambias L/R a 3V3, tienes que cambiar
I2S_CHANNEL_FMT_ONLY_LEFTporI2S_CHANNEL_FMT_ONLY_RIGHT. - 8 buffers DMA: el periférico copia el audio a memoria por su cuenta mientras el procesador hace otra cosa, así no se pierden muestras.
Proyecto 1: medir la intensidad del sonido (RMS)
Una muestra aislada de audio no dice mucho, porque la onda cruza por cero miles de veces por segundo. Lo que representa el volumen es el valor RMS (raíz cuadrática media) de un bloque de muestras:
- Elevas al cuadrado cada muestra (así las negativas también suman).
- Sacas el promedio de todos esos cuadrados.
- Calculas la raíz cuadrada del resultado.
Mientras más fuerte el sonido, más alto el RMS. Copia este código en Arduino IDE:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-inmp441-i2s-microphone-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <driver/i2s.h>
// Pin configuration
#define I2S_SCK 42 // BCLK
#define I2S_WS 40 // LRCLK / WS
#define I2S_SD 41 // DOUT from mic
#define I2S_PORT I2S_NUM_0
#define SAMPLE_RATE 16000
#define BUFFER_LEN 512
int32_t sBuffer[BUFFER_LEN];
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("INMP441 Microphone");
// I2S configuration
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // L/R = GND
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = BUFFER_LEN,
.use_apll = false
};
// Pin configuration
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_SD
};
// Start I2S
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
i2s_zero_dma_buffer(I2S_PORT);
Serial.println("I2S started.");
Serial.println("Reading microphone...");
}
void loop() {
size_t bytes_read = 0;
// Read microphone data
i2s_read(I2S_PORT, sBuffer, sizeof(sBuffer), &bytes_read, portMAX_DELAY);
int samples_read = bytes_read / sizeof(int32_t);
double sum = 0;
// Print the samples
for (int i = 0; i < samples_read; i++) {
// INMP441 sends 24-bit audio left-aligned in a 32-bit I2S word
int32_t sample = sBuffer[i] >> 8;
//Serial.println(sample);
sum += (double)sample * sample;
}
// Calculate RMS
double rms = sqrt(sum / samples_read);
// Print RMS
//Serial.print("RMS: ");
Serial.println(rms);
}
Cómo funciona el código
#include <driver/i2s.h>trae el driver I2S. Los tres#definede pines son los únicos que cambias si usas otra placa.I2S_PORTelige el periférico I2S número 0,SAMPLE_RATEfija 16.000 muestras por segundo yBUFFER_LENdefine cuántas muestras entran en cada cálculo. El arreglosBufferes deint32_tporque cada muestra ocupa un hueco de 32 bits.- En
setup()se arma la estructurai2s_config_t(modo maestro y recepción, frecuencia, bits por muestra, canal, formato estándar I2S, buffers DMA) y la estructurai2s_pin_config_tcon los pines.data_out_numva enI2S_PIN_NO_CHANGEporque solo recibes audio. Luegoi2s_driver_install(),i2s_set_pin()ei2s_zero_dma_buffer()dejan el periférico andando. - En
loop(),i2s_read()llena el buffer y devuelve enbytes_readcuántos bytes llegaron. Dividir porsizeof(int32_t)da el número real de muestras. - El
fordesplaza cada muestra>> 8(los 24 bits útiles, como se explicó arriba), la eleva al cuadrado y la acumula ensumcomodoublepara que no se desborde: una muestra de 24 bits al cuadrado ya no cabe en 32 bits. - Al final,
sqrt(sum / samples_read)es el RMS, y se imprime solo el número para que el Serial Plotter lo grafique limpio.
Prueba
Sube el código seleccionando tu placa y el puerto COM correcto. Después abre el Serial Plotter, que está al lado del ícono del Monitor Serie:

Aplaude, habla o chasquea los dedos y mira cómo sube y baja la curva. En la captura, el primer peak es un aplauso y el segundo, un chasquido:

Anota qué valores ves con la pieza en silencio y cuáles con un aplauso: esa es la materia prima para elegir un umbral en cualquier proyecto que reaccione al sonido.
Proyecto 2: ver la forma de onda del sonido
Si en vez del RMS imprimes cada muestra, lo que aparece en el Serial Plotter es la onda misma: la amplitud del sonido en cada instante.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-inmp441-i2s-microphone-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <driver/i2s.h>
// Pin configuration
#define I2S_SCK 42 // BCLK
#define I2S_WS 40 // LRCLK / WS
#define I2S_SD 41 // DOUT from mic
#define I2S_PORT I2S_NUM_0
#define SAMPLE_RATE 16000
#define BUFFER_LEN 512
int32_t sBuffer[BUFFER_LEN];
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("INMP441 Microphone");
// I2S configuration
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // L/R = GND
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = BUFFER_LEN,
.use_apll = false
};
// Pin configuration
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_SD
};
// Start I2S
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
i2s_zero_dma_buffer(I2S_PORT);
Serial.println("I2S started.");
Serial.println("Reading microphone...");
}
void loop() {
size_t bytes_read = 0;
// Read microphone data
i2s_read(I2S_PORT, sBuffer, sizeof(sBuffer), &bytes_read, portMAX_DELAY);
int samples_read = bytes_read / sizeof(int32_t);
// Print the samples
for (int i = 0; i < samples_read; i++) {
// INMP441 sends 24-bit audio left-aligned in a 32-bit I2S word
int32_t sample = sBuffer[i] >> 8;
Serial.println(sample);
}
}
El código es idéntico al anterior, salvo que no calcula el RMS: recorre el buffer y manda cada muestra (ya desplazada >> 8) por el puerto serie. Cada valor es la amplitud de la señal en un momento puntual.
Súbelo y abre el Serial Plotter. Prueba con vocales largas (aaaa, eeee, iiii, oooo, uuuu): cada una combina frecuencias distintas y la forma de la onda cambia.

El Serial Plotter se queda corto para apreciar la forma: dibuja pocos puntos y ajusta la escala solo. Para ver bien la diferencia entre vocales conviene graficar con Python y matplotlib:

Extra: graficar la onda con matplotlib
- Instala Python y, durante la instalación, marca la opción "Add Python to PATH".
- En la terminal (o el símbolo del sistema en Windows), instala las librerías:
pip install pyserial matplotlib
- Deja el sketch de la forma de onda corriendo en el ESP32, anota el puerto serie (por ejemplo, COM5) y cierra Arduino IDE: si queda abierto, el puerto sigue ocupado y Python no puede leerlo.
- Descarga el script
INMP441-microphone.pydel repositorio de los autores (enlace en Recursos), cambia el puerto por el tuyo y guárdalo, por ejemplo, en el Escritorio. - Ejecútalo desde la terminal:
cd Desktop
python INMP441-microphone.py
Se abre una ventana de matplotlib con la onda, donde puedes ajustar la escala y exportar una captura:

Proyecto 3: encender y apagar un LED con dos aplausos
Con lo anterior ya tienes todo para un clásico: dos aplausos seguidos cambian el estado de un LED. En lugar del LED puede ir un módulo relé para una lámpara o una cortina motorizada; el código es el mismo.

La idea: un aplauso produce un peak de amplitud que sobresale claramente del ruido ambiente. Si aparecen dos peaks sobre un umbral dentro de un tiempo corto, el programa lo toma como doble aplauso e invierte el LED.

Ojo: el programa no reconoce aplausos como tales, sino dos peaks consecutivos sobre el umbral. Un golpe en la mesa o un chasquido fuerte también cuentan.
Conexión del LED
Además del micrófono, conecta un LED con una resistencia de 220 Ω (o un valor parecido) en serie al GPIO 38 de la ESP32-S3. En un ESP32 clásico puedes usar, por ejemplo, el GPIO 2 o el 4; solo cambia LED_PIN.
Materiales de este proyecto:
- Placa ESP32-S3 DevKitC (o un ESP32 DevKit con los pines ajustados)
- Módulo micrófono INMP441
- 1 resistencia de 220 Ω
- 1 LED de 5 mm
- Protoboard
- Cables jumper

/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-inmp441-i2s-microphone-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <driver/i2s.h>
// Pin configuration
#define I2S_SCK 42 // BCLK
#define I2S_WS 40 // LRCLK / WS
#define I2S_SD 41 // DOUT from mic
#define I2S_PORT I2S_NUM_0
#define SAMPLE_RATE 16000
#define BUFFER_LEN 512
int32_t sBuffer[BUFFER_LEN];
// LED
#define LED_PIN 38
// Clap detection
#define CLAP_THRESHOLD 1000000
// Maximum time allowed between the first and second clap
const unsigned long CLAP_GAP = 700;
// Prevent the same clap from being detected multiple times
const unsigned long CLAP_COOLDOWN = 250;
// State variables
bool ledState = false;
int clapCount = 0;
unsigned long firstClapTime = 0;
unsigned long lastClapTime = 0;
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("INMP441 Microphone");
// LED setup
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// I2S configuration
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // L/R = GND
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = BUFFER_LEN,
.use_apll = false
};
// Pin configuration
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_SD
};
// Start I2S
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
i2s_zero_dma_buffer(I2S_PORT);
Serial.println("I2S started.");
Serial.println("Double clap to control LED");
}
void loop() {
size_t bytes_read = 0;
// Read microphone data
i2s_read(I2S_PORT, sBuffer, sizeof(sBuffer), &bytes_read, portMAX_DELAY);
int samples_read = bytes_read / sizeof(int32_t);
// Find the loudest sample
int32_t peak = 0;
// Print the samples
for (int i = 0; i < samples_read; i++) {
int32_t sample = sBuffer[i] >> 8;
int32_t magnitude = abs(sample);
if (magnitude > peak) {
peak = magnitude;
}
}
// Print peak
Serial.println(peak);
// Detect a clap
unsigned long now = millis();
if (peak > CLAP_THRESHOLD && now - lastClapTime > CLAP_COOLDOWN) {
lastClapTime = now;
// First clap
if (clapCount == 0) {
clapCount = 1;
firstClapTime = now;
Serial.println("First clap detected");
}
// Second clap
else if (now - firstClapTime <= CLAP_GAP) {
clapCount = 0;
// Double clap - invert LED state
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
if (ledState) {
Serial.println("DOUBLE CLAP - LED ON");
}
else {
Serial.println("DOUBLE CLAP - LED OFF");
}
}
// Too much time passed
else {
// Treat this clap as the beginning of a new pair
clapCount = 1;
firstClapTime = now;
Serial.println("New first clap");
}
}
// Reset if second clap doesn't arrive in time
if (clapCount == 1 && now - firstClapTime > CLAP_GAP) {
clapCount = 0;
}
}
Cómo funciona la detección
La lectura I2S es igual a la de los proyectos anteriores. Lo nuevo son tres parámetros y una pequeña máquina de estados:
CLAP_THRESHOLD(1.000.000): la amplitud desde la cual un peak cuenta como aplauso. Tiene que quedar sobre el ruido ambiente de tu lugar, así que casi siempre toca ajustarlo.CLAP_GAP(700 ms): el tiempo máximo entre el primer y el segundo aplauso.CLAP_COOLDOWN(250 ms): durante ese lapso tras un peak, los siguientes se ignoran. Un aplauso real dura varios bloques de 32 ms, y sin esta pausa un solo aplauso se contaría dos o tres veces.
En cada vuelta del loop(), el programa busca la muestra más fuerte del bloque (peak, usando abs() para que las negativas también cuenten). Si supera el umbral y ya pasó el cooldown:
- Si
clapCountestá en 0, es el primer aplauso: guarda la hora enfirstClapTime. - Si ya había uno y no han pasado más de 700 ms, es el segundo: invierte
ledState, escribe el pin y vuelveclapCounta 0. - Si pasó demasiado tiempo, ese aplauso se toma como el primero de un par nuevo.
Al final, si hay un primer aplauso esperando y se venció el plazo, clapCount vuelve a 0.
Prueba y calibración
Sube el código, aplaude dos veces y el LED se enciende; otras dos, y se apaga.
- Si el LED parpadea solo, el umbral está bajo para tu ruido ambiente: sube
CLAP_THRESHOLD. - Si no reacciona a los aplausos, está alto: bájalo.
Para elegirlo con datos, el sketch imprime el peak de cada bloque con Serial.println(peak); (si en tu versión esa línea está comentada, quítale las //). Abre el Serial Plotter, mira los valores en silencio y con un aplauso, y deja el umbral entre ambos, un poco por debajo del peak típico del aplauso.
Extra de esta versión: medidor de ruido en decibeles con alerta MQTT
El RMS del proyecto 1 es un número sin unidad. Para que diga algo a un profesor o a quien administra una oficina, conviene pasarlo a decibeles. El datasheet del INMP441 da el dato necesario: su sensibilidad es de, 26 dBFS para un tono de 94 dB SPL. Es decir, un sonido de 94 dB produce una señal 26 dB por debajo del máximo digital. De ahí sale una conversión directa:
- dBFS (decibeles respecto de la escala completa) = 20 × log10(RMS / 8.388.607)
- dB SPL aproximado = dBFS + 120
Este sketch promedia un segundo de audio, publica el nivel en un tema MQTT y manda una alerta cuando se pasa del umbral, con histéresis para que no oscile cuando el ruido anda justo en el límite. Usa la librería PubSubClient de Nick O'Leary (instálala desde el gestor de librerías) y los mismos pines de la ESP32-S3:
#include <WiFi.h>
#include <PubSubClient.h>
#include <driver/i2s.h>
#include <math.h>
// Red y broker MQTT (cambia estos datos)
const char* WIFI_SSID = "TU_RED";
const char* WIFI_PASS = "TU_CLAVE";
const char* MQTT_HOST = "192.168.1.50";
const int MQTT_PORT = 1883;
const char* TOPIC_NIVEL = "sala/ruido/db";
const char* TOPIC_ALERTA = "sala/ruido/alerta";
// Pines (ESP32-S3; en un ESP32 clasico usa 26, 25 y 33)
#define I2S_SCK 42
#define I2S_WS 40
#define I2S_SD 41
#define LED_PIN 38
#define I2S_PORT I2S_NUM_0
#define SAMPLE_RATE 16000
#define BUFFER_LEN 512
// INMP441: -26 dBFS a 94 dB SPL, entonces dB SPL = dBFS + 120
const float OFFSET_DB = 120.0;
const float UMBRAL_DB = 70.0;
const float HISTERESIS_DB = 5.0;
const unsigned long PERIODO_MS = 1000;
int32_t sBuffer[BUFFER_LEN];
WiFiClient red;
PubSubClient mqtt(red);
double sumaCuadrados = 0;
uint32_t nMuestras = 0;
unsigned long ultimoEnvio = 0;
bool enAlerta = false;
void conectarMqtt() {
while (!mqtt.connected()) {
if (mqtt.connect("esp32-ruido-sala")) break;
delay(2000);
}
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(500);
mqtt.setServer(MQTT_HOST, MQTT_PORT);
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = BUFFER_LEN,
.use_apll = false
};
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_SD
};
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
i2s_zero_dma_buffer(I2S_PORT);
}
void loop() {
if (!mqtt.connected()) conectarMqtt();
mqtt.loop();
size_t bytes_read = 0;
i2s_read(I2S_PORT, sBuffer, sizeof(sBuffer), &bytes_read, portMAX_DELAY);
int samples_read = bytes_read / sizeof(int32_t);
if (samples_read == 0) return;
// Promedio del bloque, para restar un posible offset DC
double media = 0;
for (int i = 0; i < samples_read; i++) media += (sBuffer[i] >> 8);
media /= samples_read;
for (int i = 0; i < samples_read; i++) {
double x = (sBuffer[i] >> 8) - media;
sumaCuadrados += x * x;
}
nMuestras += samples_read;
unsigned long ahora = millis();
if (ahora - ultimoEnvio >= PERIODO_MS) {
double rms = sqrt(sumaCuadrados / nMuestras);
float db = 20.0 * log10(rms / 8388607.0 + 1e-12) + OFFSET_DB;
char msg[16];
snprintf(msg, sizeof(msg), "%.1f", db);
mqtt.publish(TOPIC_NIVEL, msg);
Serial.println(msg);
if (!enAlerta && db > UMBRAL_DB) {
enAlerta = true;
digitalWrite(LED_PIN, HIGH);
mqtt.publish(TOPIC_ALERTA, "ON", true);
} else if (enAlerta && db < UMBRAL_DB - HISTERESIS_DB) {
enAlerta = false;
digitalWrite(LED_PIN, LOW);
mqtt.publish(TOPIC_ALERTA, "OFF", true);
}
sumaCuadrados = 0;
nMuestras = 0;
ultimoEnvio = ahora;
}
}
Tres cosas para interpretar bien los números:
- Es una medición sin ponderación (dB Z), no dB(A). Los sonómetros oficiales aplican la curva A, que resta peso a los graves porque el oído los percibe menos. Para comparar una sala consigo misma a lo largo del día sirve de sobra; para un informe formal de ruido no reemplaza a un sonómetro certificado.
- La conversión es aproximada. Cada cápsula tiene una tolerancia de sensibilidad, así que conviene contrastarla una vez con un sonómetro o con una app de celular calibrada y ajustar
OFFSET_DBhasta que coincidan. - El umbral depende del lugar. Una clase expositiva normal suele quedar varios decibeles por debajo de 70 y un recreo dentro de la sala, bastante por encima. Deja el medidor un par de días publicando y elige el umbral mirando los datos, igual que con el aplauso.
Con el tema sala/ruido/db puedes graficar el historial en Node RED o Home Assistant. El tema de alerta se publica con la bandera retained, así que un tablero que se conecte después igual sabe si la sala está en alerta.
Errores comunes y cómo resolverlos
- Todo sale en 0: casi siempre es el canal. Si L/R está a 3V3 y el código lee
ONLY_LEFT(o al revés), el ESP32 escucha el canal vacío. También pasa si L/R quedó al aire: conéctalo siempre a GND o a 3V3. - Valores fijos en, 1 o en un número enorme que no cambia: revisa SD y SCK; es típico tenerlos intercambiados o con una soldadura fría.
- Ruido constante muy alto: comprueba que VDD vaya a 3V3 y que los cables del I2S sean cortos. Con cables largos de protoboard, un reloj de 1 MHz ya empieza a sufrir.
- El programa no carga o la placa se reinicia en bucle: usaste un pin de arranque (en el ESP32 clásico, 0, 2, 12 o 15) para una señal I2S. Muévela a otro GPIO.
- Un aplauso cuenta doble: sube
CLAP_COOLDOWNa 300 o 350 ms.
Variantes y mejoras
- Contador de aplausos por patrones: en vez de dos aplausos, reconoce tres para una segunda salida o un aplauso largo para apagar todo, guardando las horas de cada peak en un arreglo pequeño y comparando los intervalos.
- Detector de frecuencia con FFT: con la librería arduinoFFT puedes sacar la frecuencia dominante de cada bloque y, por ejemplo, hacer un afinador de guitarra o encender algo solo con un silbido y no con cualquier ruido.
- Grabar audio en una microSD: guarda las muestras de 16 bits en un archivo WAV mediante un módulo microSD por SPI y tendrás una grabadora de voz. Con dos INMP441 (uno con L/R a GND y otro a 3V3, compartiendo SCK y WS) grabas en estéreo.
- Salida de audio por I2S: junto con un amplificador MAX98357A, también por I2S, el ESP32 puede reproducir lo que escucha o armar un intercomunicador.
Personalización para Chile
En Chile consigues todo lo necesario en MechatronicStore:
- Módulo micrófono INMP441 I2S: el sensor central de los cuatro proyectos.
- Placa ESP32-S3 DevKitC o ESP32 DevKit V1: cualquiera de las dos sirve; con la S3 usas los pines del tutorial tal cual y con la DevKit V1 cambias los tres
#definea 26, 25 y 33. - LED de 5 mm y resistencia de 220 Ω: la salida del proyecto de aplausos.
- Módulo relé de 1 canal a 5V: para reemplazar el LED por una lámpara u otro equipo de 220 V. Si trabajas con la red eléctrica, hazlo con el circuito desenergizado.
- Protoboard de 830 puntos y cables jumper macho macho: para armar todo sin soldar, salvo los pines del micrófono.
- Cable USB de datos (USB-C para la S3, micro USB para la mayoría de las DevKit V1): uno solo de carga no deja que la placa aparezca en Arduino IDE.
Si en el tutorial original usan la ESP32-S3 DevKitC de otro fabricante, cualquier ESP32-S3 de la tienda cumple la misma función: el I2S es parte del chip, no de la placa.
Recursos
- Tutorial original (inglés), en el que se basa esta guía: ESP32 with INMP441 I2S Omnidirectional Microphone Module (Arduino IDE), de Rui Santos y Sara Santos (Random Nerd Tutorials)
- Repositorio GitHub con los archivos del proyecto: Random Nerd Tutorials / INMP441
- Archivos descargables: sketch RMS (.ino), sketch de forma de onda (.ino) y script de matplotlib (.py)
- Documentación adicional: driver I2S de ESP IDF (Espressif), matplotlib y la guía de pines del ESP32
Versión chilena con componentes en stock local en MechatronicStore.




