In diesem ESP32-Projekt möchte ich dir zeigen, wie du ganz einfach ein Dezibel-Messgerät mit einer Lärmschutzampel bauen kannst.
Das Messgerät misst die Lautstärke in deiner Umgebung und zeigt dir den aktuellen Lärmpegel in unterschiedlichen LED-Farben an. So kannst du ganz einfach herausfinden, ob es in deiner Werkstatt, Büro oder Zuhause ruhig genug ist.
Und es kann uns auch dabei unterstützen, unsere Ohren zu schützen, indem es uns vor potenziell schädlichen Lärmpegeln warnt.
So können wir rechtzeitig unseren Hörschutz aufsetzen und Hörschäden vermeiden.
Hauptkomponente hier bei ist das Mikrofon INMP441, das aus allen Richtungen Schallwellen gleichermaßen aufnimmt. Die INMP441-Komplettlösung besteht aus einem MEMS-Sensor, Signalverarbeitung, Analog-Digital-Wandler, Anti-Aliasing-Filter, Energiemanagement und einer 24-Bit-I2S-Schnittstelle.
Funktionsweise:
Das Mikrofonmodul nimmt analoge Schallwellen aus der Umgebung auf. Diese Schallwellen verursachen Schwankungen im elektrischen Signal, das vom Mikrofon erzeugt wird. Das integrierte I2S-Interface im Mikrofonmodul konvertiert diese analogen Signale in digitale Daten. I2S (Inter-IC Sound) ist ein Standard für digitale Audiodatenübertragung, der es dem ESP32 ermöglicht, diese digitalen Audiodaten präzise und effizient zu empfangen und zu verarbeiten.
Bitte beachte, dass diese Methoden nur ungefähre Ergebnisse liefern können und nicht die Genauigkeit professioneller Geräte erreichen. Für kritische Messungen oder Lärmschutzmaßnahmen sollte immer professionelles Equipment verwendet werden.
Hardware:
ESP32 WROOM —> Belegungsplan
INMP441 Mikrofonmodul 3,3 Volt
3x LEDs (rot, gelb, grün) plus Vorwiderstand
Jumper-Kabel und Steckbrett
Computer mit installierter Entwicklungsumgebung Arduino IDE
optional gezeigte kleine Ampel, große Signal Ampel oder das 4 Fach Relay incl. ESP32
Verdrahtung:
Verbinde das INMP441 Mikrofonmodul mit dem ESP32:
VCC an 3.3V
GND an GND
BCLK (SCK) an GPIO 26
LRCLK (WS) an GPIO 25
DOUT (SD) an GPIO 22
L/R an GND oder VCC, (Linker oder Rechter Kanal) Wenn dieser nicht gesetzt ist (also nicht mit GND oder VCC verbunden ist), wird standardmäßig der rechte Kanal verwendet
Verbinde die LEDs mit dem ESP32:
Rot: Pin 2
Gelb: Pin 5
Grün: Pin 4
Jeder LED-Anschluss über einen Vorwiderstand mit GND verbinden. Siehe Beitrag Vorwiderstand
Verbinde USB Kabel mit dem ESP32 und dem Computer
Funktionsweise der Bauteile
- ESP32: Der ESP32 ist ein leistungsstarker Mikrocontroller mit integrierter WLAN- und Bluetooth-Funktionalität. Er steuert die LEDs und liest die Audiodaten vom INMP441-Sensor.
- INMP441 Mikrofonmodul: Dies ist ein MEMS-Mikrofon mit integriertem I2S-Interface, das hochauflösende Audiosignale digital an den ESP32 überträgt.
- LEDs: Die LEDs dienen als visuelle Indikatoren für die Lautstärke. Grün bedeutet stille Umgebung, Gelb zeigt normale Gespräche an, und Rot warnt vor lauten Geräuschen.
- Widerstände: Diese begrenzen den Strom, der durch die LEDs fließt, um sie vor Beschädigung zu schützen.
Umwandlung von analogen Geräuschen in digitale Werte
Das INMP441 Mikrofonmodul nimmt analoge Schallwellen aus der Umgebung auf. Diese Schallwellen verursachen Schwankungen im elektrischen Signal, das vom Mikrofon erzeugt wird. Das integrierte I2S-Interface im Mikrofonmodul konvertiert diese analogen Signale in digitale Daten. I2S (Inter-IC Sound) ist ein Standard für digitale Audiodatenübertragung, der es dem ESP32 ermöglicht, diese digitalen Audiodaten präzise und effizient zu empfangen und zu verarbeiten.
So funktioniert I2S:
- BCLK (Bit Clock): Synchronisiert den Datentransfer.
- LRCLK (Left/Right Clock): Bestimmt, ob die Daten zum linken oder rechten Audiokanal gehören.
- DOUT (Data Out): Überträgt die digitalen Audiowerte vom Mikrofonmodul zum ESP32.
Diese digitalen Daten können dann vom ESP32 weiterverarbeitet werden, um die Lautstärke zu berechnen und entsprechende LEDs zu steuern.
Programmierung
Der Programmcode zur Steuerung der LEDs basierend auf den Lautstärkepegeln wird hier kurz zusammengefasst:
- Initialisiere den ESP32 und konfiguriere die I2S-Schnittstelle.
- Lese kontinuierlich Audiodaten vom INMP441-Sensor.
- Berechne den Durchschnitt und die Lautstärke in Dezibel (dB).
- Schalte die LEDs basierend auf den berechneten dB-Werten.
Benötigte Bibliotheken:
Für math.h müsst ihr keine Library installieren. Die mathematischen Funktionen, wie log10
, abs
und pow
, sind bereits in der Arduino-Umgebung integriert und gehören zum Standard-C/C++-Header <math.h>
.
Für i2s.h habe ich diese Library hinzugefügt:
Sketch / Quellcode < > anzeigen
// Bibliotheken einbinden
#include <driver/i2s.h>
#include <math.h>
// Diese Zeilen inkludieren die notwendigen Bibliotheken für die I2S-Kommunikation (driver/i2s.h) und mathematische Operationen (math.h).
// Pins für das I2S Interface definieren
#define I2S_SCK 26
#define I2S_WS 25
#define I2S_SD 22
// Diese Zeilen definieren die GPIO-Pins des ESP32, die für das I2S-Interface verwendet werden: SCK (Serial Clock), WS (Word Select) und SD (Serial Data).
// Pins für die LEDs definieren
#define GREEN_LED_PIN 2
#define YELLOW_LED_PIN 5
#define RED_LED_PIN 4
// Diese Zeilen definieren die GPIO-Pins, die für die LEDs verwendet werden: Grün, Gelb und Rot.
#define SAMPLE_SIZE 1024
int32_t samples[SAMPLE_SIZE];
#define AVERAGE_COUNT 10
// SAMPLE_SIZE definiert die Anzahl der Samples, die pro Durchgang gesammelt werden sollen (1024).
// Ein Array samples wird deklariert, um diese Samples zu speichern.
// AVERAGE_COUNT definiert die Anzahl der Durchläufe, die für den gleitenden Mittelwert verwendet werden (10).
float averageBuffer[AVERAGE_COUNT];
int avgIndex = 0;
// Diese Zeilen deklarieren ein Array averageBuffer, um die letzten 10 Durchschnittswerte zu speichern, und einen Index avgIndex, um die aktuelle Position im Puffer zu verfolgen.
void setup() {
Serial.begin(115200);
// Diese Zeile initialisiert die serielle Kommunikation mit einer Baudrate von 115200, um Debug-Informationen an den seriellen Monitor zu senden.
pinMode(GREEN_LED_PIN, OUTPUT);
pinMode(YELLOW_LED_PIN, OUTPUT);
pinMode(RED_LED_PIN, OUTPUT);
// Diese Zeilen konfigurieren die Pins für die grünen, gelben und roten LEDs als Ausgänge.
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = 48000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0
};
// Diese Struktur i2s_config_t konfiguriert die I2S-Schnittstelle:
// mode: Setzt den Modus auf Master und Empfang (RX).
// sample_rate: Setzt die Abtastrate auf 48 kHz.
// bits_per_sample: Setzt die Abtastauflösung auf 32 Bit.
// channel_format: Setzt das Kanalformat auf rechts und links.
// communication_format: Definiert das I2S-Kommunikationsformat.
// intr_alloc_flags: Setzt die Interrupt-Flags.
// dma_buf_count: Definiert die Anzahl der DMA-Puffer.
// dma_buf_len: Definiert die Länge der DMA-Puffer.
// use_apll: Nutzt nicht den APLL.
// tx_desc_auto_clear: Deaktiviert die automatische Löschung der TX-Beschreibung.
// fixed_mclk: Fixiert den Master-Clock.
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
};
// Diese Struktur i2s_pin_config_t konfiguriert die Pins für die I2S-Schnittstelle:
// bck_io_num: Setzt den BCK-Pin.
// ws_io_num: Setzt den WS-Pin.
// data_out_num: Kein Pin für Datenausgabe.
// data_in_num: Setzt den SD-Pin.
if (i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL) == ESP_OK) {
Serial.println("I2S driver installed");
} else {
Serial.println("Failed to install I2S driver");
}
// Installiert den I2S-Treiber mit der konfigurierten Struktur i2s_config. Gibt eine Erfolgsmeldung aus, wenn der Treiber installiert ist, oder eine Fehlermeldung, wenn nicht.
if (i2s_set_pin(I2S_NUM_0, &pin_config) == ESP_OK) {
Serial.println("I2S pins set");
} else {
Serial.println("Failed to set I2S pins");
}
// Setzt die Pins für die I2S-Schnittstelle mit der konfigurierten Struktur pin_config. Gibt eine Erfolgsmeldung aus, wenn die Pins gesetzt sind, oder eine Fehlermeldung, wenn nicht.
if (i2s_set_clk(I2S_NUM_0, 48000, I2S_BITS_PER_SAMPLE_32BIT, I2S_CHANNEL_MONO) == ESP_OK) {
Serial.println("I2S clock set");
} else {
Serial.println("Failed to set I2S clock");
}
// Setzt den I2S-Clock auf 48 kHz, 32 Bit und Monokanal. Gibt eine Erfolgsmeldung aus, wenn der Clock gesetzt ist, oder eine Fehlermeldung, wenn nicht.
for (int i = 0; i < AVERAGE_COUNT; i++) {
averageBuffer[i] = 0;
}
// Initialisiert den Durchschnittspuffer averageBuffer mit Nullen.
}
void loop() {
size_t bytes_read;
int64_t sum = 0;
// Deklariert eine Variable bytes_read zur Speicherung der gelesenen Bytes und initialisiert sum zur Summierung der absoluten Werte der Samples.
for (int i = 0; i < SAMPLE_SIZE; i++) {
i2s_read(I2S_NUM_0, &samples[i], sizeof(samples[i]), &bytes_read, portMAX_DELAY);
sum += abs(samples[i]);
}
// Liest die I2S-Samples in das samples-Array und summiert die absoluten Werte der Samples.
float average = sum / (float)SAMPLE_SIZE;
averageBuffer[avgIndex] = average;
avgIndex = (avgIndex + 1) % AVERAGE_COUNT;
// Berechnet den Durchschnitt der Samples und speichert ihn im averageBuffer-Array. Aktualisiert den Index avgIndex zyklisch.
float smoothedAverage = 0;
for (int i = 0; i < AVERAGE_COUNT; i++) {
smoothedAverage += averageBuffer[i];
}
smoothedAverage /= AVERAGE_COUNT;
// Berechnet den geglätteten Durchschnitt aus den letzten AVERAGE_COUNT-Durchläufen.
if (smoothedAverage > 0) {
float dB = 20 * log10(smoothedAverage) - 70; // Feinjustierung der Kalibrierung WICHTIG auch für spätere Anpassungen
Serial.print("Smoothed Average: ");
Serial.print(smoothedAverage);
Serial.print(" dB: ");
Serial.println(dB);
// Berechnet den Dezibel-Wert (dB) des geglätteten Durchschnitts und gibt diesen zusammen mit dem geglätteten Durchschnittswert auf dem seriellen Monitor aus.
if (dB < 40) {
digitalWrite(GREEN_LED_PIN, HIGH); // Stille
digitalWrite(YELLOW_LED_PIN, LOW);
digitalWrite(RED_LED_PIN, LOW);
} else if (dB < 80) {
digitalWrite(GREEN_LED_PIN, LOW);
digitalWrite(YELLOW_LED_PIN, HIGH); // Gespräch
digitalWrite(RED_LED_PIN, LOW);
} else {
digitalWrite(GREEN_LED_PIN, LOW);
digitalWrite(YELLOW_LED_PIN, LOW);
digitalWrite(RED_LED_PIN, HIGH); // Laut
}
// Steuert die LEDs basierend auf dem Dezibel-Wert: Grün für Stille, Gelb für Gespräch und Rot für Lautstärke über 80 dB.
} else {
Serial.println("Average is zero or negative");
// Falls der Durchschnitt null oder negativ ist, wird eine Fehlermeldung ausgegeben.
}
delay(100);
// Wartet 100 ms, bevor die Schleife erneut durchlaufen wird.
}
Feintuning
Es kann schwierig sein, den tatsächlichen Dezibelpegel ohne professionelle Geräte genau zu bestimmen, aber es gibt einige Ansätze und Werkzeuge, die dir eine ungefähre Schätzung bieten können:
1. Smartphone-Apps:
Es gibt viele kostenlose und kostenpflichtige Dezibel-Mess-Apps, die das Mikrofon deines Smartphones nutzen, um den Schallpegel zu messen. Einige beliebte Apps sind:
- Schallmesser (iOS)
- Sound Meter (Android)
- Decibel X (iOS und Android)
- NIOSH Sound Level Meter (iOS)
Diese Apps sind zwar nicht so präzise wie professionelle Geräte, aber sie können dir eine gute Schätzung liefern.
2. Vergleich mit bekannten Schallquellen:
Du kannst bekannte Schallquellen verwenden, deren Dezibelwerte allgemein bekannt sind, um dein Messgerät zu kalibrieren. Hier sind einige Beispiele:
0 dB – Hörschwelle
10 dB – Raschelndes Blatt
20 dB – Flüstern
30 dB – Ruhiges Schlafzimmer
40 dB – Kühlschrankbrummen
50 dB – Normales Gespräch
60 dB – Nähmaschine
70 dB – Staubsauger
80 dB – Stadtverkehr
90 dB – Motorrad
100 dB – Bohrmaschine
110 dB – Rockkonzert
120 dB – Düsenflugzeug beim Starten
130 dB – Schmerzgrenze
140 dB – Feuerwerkskörper aus nächster Nähe
Du kannst dein DIY dB Messgerät in der Nähe solcher Schallquellen testen und sehen, ob die angezeigten Werte ungefähr stimmen.
3. Manuelle Kalibrierung:
Wenn du eine grobe Schätzung der Dezibelwerte von bekannten Schallquellen hast, kannst du den Kalibrierungswert in deinem Code anpassen, bis die angezeigten Werte ungefähr mit den erwarteten Werten übereinstimmen. Dies ist natürlich nicht so präzise wie eine professionelle Kalibrierung, kann dir aber eine brauchbare Annäherung bieten.
4. Referenzpegel mit einem bekannten Gerät:
Wenn du Zugang zu einem anderen Gerät hast, das Schallpegel messen kann (z.B. ein hochwertiges Mikrofon oder ein anderes Dezibel-Messgerät), kannst du dein DIY dB Messgerät damit vergleichen. Führe Messungen unter denselben Bedingungen durch und justiere deinen Kalibrierungswert entsprechend.
Kalibrierung deines DIY dB Messgeräts:
Nachdem du eine der oben genannten Methoden verwendet hast, kannst du den Kalibrierungswert in deinem Code anpassen, z.B.:
float dB = 20 * log10(smoothedAverage) - 70; // Anpassen des Kalibrierungswerts je nach Referenzpegel
Ändere den Wert -70
, um die Genauigkeit deiner Messungen zu verbessern.
Diese Methoden bieten dir eine einfache Möglichkeit, den Dezibelpegel ohne professionelle Geräte brauchbar zu kalibrieren.
Video:
Nicht im Video zu sehen:
Dezibel Messung
mit einem Arduino Nano 33 BLE Sense Rev2 Board.
Dieses Entwicklungsboard bringt unter anderen, direkt einen MP34DT06JTR Mikrofon Sensor mit.
Dieser Sensor ist ein ultrakompaktes Mikrofon, das PDM (Pulse-Density Modulation) verwendet, um ein analoges Signal mit einem binären Signal darzustellen.
Der Sensor hat folgende Werte:
Signal-Rausch-Verhältnis: 64dB
Empfindlichkeit: -26dBFS ±3dB
Ablauf im Sketch:
Zunächst werden die Rohwerte von den Mikrofon-Samples erfasst.
Diese Werte sind die direkte Ausgabe des PDM (Pulse-Density Modulation) Mikrofonsensors und repräsentieren die Lautstärke der Umgebung in Form von digitalen Zahlen.
Diese digitalen Zahlen, liegen normalerweise in einem Bereich zwischen -32768 und 32767.
Das ist der Bereich der 16-Bit-Samples, wobei 0 den Ruhezustand (keine Schallwellen) darstellt. Positive und negative Werte repräsentieren die Auslenkung der Schallwellen nach oben und unten.
Um die gemessenen Werte in Dezibel (dB) umzurechnen, muss zunächst die Amplitude (RMS – Root Mean Square) der Audio-Samples berechnet werden.
Eine Amplitude ist im Kontext von Schallwellen die maximale Auslenkung einer Welle von ihrem Ruhezustand. Stelle Dir eine Schallwelle wie eine Wellenbewegung im Wasser vor. Die Amplitude ist die Höhe der Welle von der Mitte (Ruhepunkt) bis zum höchsten Punkt (Spitze der Welle). In einem elektrischen Signal (wie bei einem Mikrofon) entspricht die Amplitude der Stärke des elektrischen Signals, die die Lautstärke des Tons widerspiegelt.
Berechnung des RMS-Wertes:
Stellen wir uns vor, wir haben vier Audio-Samples mit den Werten 2, -3, 4 und -1.
Die Schritte zur Berechnung des RMS-Wertes lauten wie folgt:
- Quadrieren jedes Samples:
Sample 1: 2 -> 2² = 4 Sample 2: -3 -> (-3)² = 9 Sample 3: 4 -> 4² = 16 Sample 4: -1 -> (-1)² = 1
- Summieren der quadrierten Werte:
4 + 9 + 16 + 1 = 30
- Durchschnitt der quadrierten Werte:
30 / 4 = 7.5
- Quadratwurzel des Durchschnitts:
√7.5 ≈ 2.74
Zusammengefasste Quadratsummenbildung:
Originalwerte: 2 -3 4 -1 Quadrierte Werte: 4 9 16 1 Summe der Quadrate: 4 + 9 + 16 + 1 = 30 Durchschnitt: 30 / 4 = 7.5 RMS-Wert: √7.5 ≈ 2.74
Mit dieser Methode erhalten wir den RMS-Wert der Samples, der als Grundlage für die Umrechnung in Dezibel (dB) dient. Der RMS-Wert repräsentiert somit eine Art „durchschnittliche“ Amplitude des Signals.
Berechnung des Dezibel-Wert:
Um den Dezibel-Wert zu erhalten, benutzt du den RMS-Wert und eine spezielle Formel:
dB = 20 * log10(RMS-Wert)
Diese Formel nutzt den Logarithmus zur Basis 10, um die Werte zu skalieren.
Je größer der Dezibel-Wert, desto lauter ist das Geräusch.
Anpassungsmöglichkeit:
Auch in diesem Sketch kann der Kalibrierungsfaktor für dB-Werte nachkalibriert werden.
const float calibrationFactor = 1.2; // Kalibrierungsfaktor für dB-Werte db *= calibrationFactor; // Anwendung des Kalibrierungsfaktors
Auswertung per LED:
Die auf dem Board befindliche RGB LED wechselt je nach Lautstärke wieder ihre Farbe.
Sketch / Quellcode < > anzeigen
#include <PDM.h>
#include <math.h> // Für die Berechnung der Dezibel
short sampleBuffer[256];
volatile int samplesRead;
const float calibrationFactor = 1.2; // Kalibrierungsfaktor für dB-Werte
void setup() {
Serial.begin(9600);
while (!Serial);
// Konfiguration des Datenempfangs
PDM.onReceive(onPDMdata);
// Initialisierung des PDM mit einem Kanal und einer Abtastrate von 16 kHz
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}
// Setzen der LED-Pins als Ausgang
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
}
void loop() {
if (samplesRead) {
float rms = 0;
// Berechnung des RMS-Werts
for (int i = 0; i < samplesRead; i++) {
rms += sampleBuffer[i] * sampleBuffer[i];
}
rms = sqrt(rms / samplesRead);
// Umrechnung in Dezibel
float db = 20 * log10(rms);
// Anwendung des Kalibrierungsfaktors
db *= calibrationFactor;
Serial.print("RMS: ");
Serial.print(rms);
Serial.print("\t dB: ");
Serial.println(db);
// LED-Farbanzeige je nach Lautstärke
if (db >= 80) { // Hohe Lautstärke
digitalWrite(LEDR, LOW);
digitalWrite(LEDG, HIGH);
digitalWrite(LEDB, HIGH);
} else if (db >= 40) { // Mittlere Lautstärke
digitalWrite(LEDB, LOW);
digitalWrite(LEDR, HIGH);
digitalWrite(LEDG, HIGH);
} else { // Niedrige Lautstärke
digitalWrite(LEDG, LOW);
digitalWrite(LEDR, HIGH);
digitalWrite(LEDB, HIGH);
}
samplesRead = 0;
}
}
void onPDMdata() {
int bytesAvailable = PDM.available();
PDM.read(sampleBuffer, bytesAvailable);
samplesRead = bytesAvailable / 2;
}
Ausgabe
im Seriellen Monitor bei einem lauteren Gespräch: