Componenti · 18 min di lettura

Sensore di suono Arduino KY-038: luce col battito di mani

Come funziona il sensore di suono KY-038/KY-037 con Arduino? Regolazione del trimmer, livello picco-picco, lampada a doppio battito, VU meter LED, ESP32 e Pico.

Quando si parla di sensore di suono per Arduino, quasi sempre si intende il KY-038: un modulo economico che riunisce su una scheda un piccolo microfono a elettrete, un comparatore LM393 e un trimmer blu per regolare la sensibilità. Il fratello con il microfono grande, il KY-037, funziona allo stesso modo. Non serve nessuna libreria: il pin DO cambia stato quando il suono supera una soglia e si legge con digitalRead(), mentre il pin AO fornisce il segnale grezzo del microfono e si legge con analogRead(). Con questo modulo si costruiscono lampade che si accendono battendo le mani, allarmi di rumore e luci che reagiscono alla musica.

Questo sensore però ha un limite importante che molte guide saltano: il KY-038 è un rilevatore di suono sì o suono no. Non registra audio, non riconosce la voce e non può misurare i decibel. In questo articolo imparerai come funziona il circuito del modulo, come regolare bene il trimmer, perché la lettura analogica spesso sembra non cambiare affatto e come misurare correttamente l'intensità del suono con il metodo picco-picco. Poi costruirai una lampada che si accende e si spegne con un doppio battito di mani e un indicatore di livello a 8 LED, farai le stesse cose con un ESP32 e un Raspberry Pi Pico e vedrai a quali moduli passare quando serve una vera misura del suono.

Modulo sensore di suono KY-038 (microfono a elettrete e LM393)
Sensore di suono KY-038: a destra il microfono a elettrete, al centro il comparatore LM393 e il trimmer blu della sensibilità, a sinistra i pin AO, G, + e DO.

Che cos'è un sensore di suono e come funziona?

Il cilindro argentato in fondo alla scheda è un microfono a condensatore a elettrete. Al suo interno una membrana sottile è affacciata a una piastra con una carica elettrica permanente e insieme formano un piccolo condensatore. Il suono è una variazione di pressione nell'aria; muovendo la membrana avanti e indietro cambia la capacità e nasce una variazione di tensione molto piccola. Un minuscolo JFET dentro la capsula fa da buffer a questo segnale: per questo il microfono a elettrete si alimenta tramite una resistenza ed è polarizzato. Il risultato è un'onda sonora di appena pochi millivolt sovrapposta a una tensione continua fissa.

Il chip LM393 a 8 piedini al centro della scheda contiene due comparatori e il modulo ne usa uno. Un comparatore guarda due tensioni: il segnale del microfono e la soglia impostata dal trimmer. Nell'istante in cui il segnale supera la soglia, l'uscita cambia stato e reagiscono il pin DO e il secondo LED della scheda. Ecco un dettaglio molto importante: un comparatore non è un amplificatore. Non rende il segnale più grande, risponde solo alla domanda «sopra o sotto la soglia?». Sul pin AO arriva il segnale grezzo del microfono, non amplificato, ed è per questo che la lettura analogica è così debole.

CaratteristicaValore
MicrofonoCapsula a condensatore a elettrete, omnidirezionale
ComparatoreLM393 (doppio comparatore, ne viene usato uno)
Alimentazione3,3–5 V
CorrentePochi mA (circa 5–10 mA con i LED)
UsciteAO: segnale grezzo del microfono, DO: uscita a soglia
Regolazione sensibilitàTrimmer blu multigiro (di solito tipo 3296)
LEDUno per l'alimentazione, uno per lo stato di DO
Ordine dei pinAO, G, +, DO

Differenza tra KY-038 e KY-037

KY-038 e KY-037 usano lo stesso circuito, lo stesso LM393 e lo stesso ordine dei pin, quindi tutti gli sketch di questo articolo funzionano su entrambi senza modifiche. La differenza è nella capsula del microfono: il KY-037 ha una capsula più grande ed è venduto come «sensore di suono ad alta sensibilità», mentre il KY-038 ha una capsula più piccola ed è il modello che trovi più spesso nei kit di sensori. In pratica entrambi rilevano bene i suoni forti vicini, ma nessuno dei due sente una conversazione dall'altra parte della stanza. Esistono anche moduli audio LM393 a 3 pin con la sola uscita digitale; nella maggior parte l'uscita va a LOW quando c'è suono.

ModelloPinMicrofonoNota
KY-038AO, G, +, DOCapsula piccolaIl modello più diffuso nei kit di sensori
KY-037AO, G, +, DOCapsula grandeStesso circuito e stesso codice; di solito un po' più sensibile
Modulo audio LM393 a 3 pinVCC, GND, OUTCapsula piccolaSolo uscita digitale; OUT di solito va a LOW con il suono

Collegamento del sensore di suono: Arduino Uno, ESP32 e Pico

Pin del moduloArduino UnoESP32Raspberry Pi Pico
+5V3V33V3(OUT), pin 36
GGNDGNDGND, pin 38
AOA0GPIO 34 (ADC1)GP26 (ADC0), pin 31
DOD2GPIO 27GP15, pin 20
I pin di ESP32 e Pico sono progettati per 3,3 V. Su queste schede alimenta il sensore di suono dal pin 3V3, non da 5V, VIN o VBUS; altrimenti l'uscita DO sale a 5 V e può danneggiare il pin di ingresso. Sull'ESP32 usa per AO uno dei pin ADC1 (GPIO 32–39): i pin ADC2 non si possono leggere con analogRead() mentre il Wi-Fi è attivo.

Uscita digitale (DO) e regolazione del trimmer

Il pin DO è una risposta sì/no. Su molte schede KY-038, DO va a HIGH e si accende il secondo LED quando il suono supera la soglia; su alcuni cloni e sui moduli a 3 pin succede esattamente il contrario. Per questo gli sketch salvano il livello che significa «suono» in una costante chiamata SOUND_ACTIVE. Il secondo punto chiave: DO non dà un unico impulso lungo per ogni battito di mani. Dato che l'onda sonora sale sopra la soglia e scende sotto centinaia di volte al secondo, anche l'uscita si accende e si spegne altrettanto velocemente; un solo battito produce una raffica di impulsi brevi che dura qualche decina di millisecondi. La maggior parte delle schede non ha isteresi sul comparatore, quindi con suoni vicini alla soglia l'uscita in più oscilla. Leggi quindi DO con un ciclo veloce senza delay() o con un interrupt, e conta come un solo evento gli impulsi molto ravvicinati.

  1. Collega il modulo e metti il sensore dove verrà usato, in un momento con il normale rumore di fondo; regolalo sempre nell'ambiente reale.
  2. Guarda il LED DO sulla scheda. Se resta acceso fisso nel silenzio, la soglia è troppo sensibile; gira il trimmer con un piccolo cacciavite finché il LED si spegne.
  3. Se il LED non si accende mai, gira nel verso opposto fino a trovare il punto in cui inizia ad accendersi.
  4. Da quel punto torna indietro di mezzo giro o di un giro verso il lato in cui il LED resta spento. Così i rumori continui, come un frigorifero o una ventola, non lo faranno scattare.
  5. Batti le mani a circa un metro: il LED dovrebbe lampeggiare per un istante. Se si accende anche parlando normalmente, gira un po' verso meno sensibile; se non si accende con un battito, un po' verso più sensibile.
Il trimmer blu di queste schede è di solito un multigiro tipo 3296 che richiede circa 25 giri da un estremo all'altro. Se lo giri qualche volta e il LED non cambia, non è rotto: devi solo continuare a girare. A fine corsa la vite inizia a girare a vuoto, quindi non serve forzarla.
Arduino (C++)
1// KY-038 DO testi: sesi algıla ve dahili LED'i yak / KY-038 DO test: detect sound and light the built-in LED
2const int SOUND_DO = 2;               // modülün DO pini / module DO pin
3const int SOUND_ACTIVE = HIGH;        // ses gelince HIGH; kartın tersse LOW / HIGH on sound; LOW if your board is inverted
4const unsigned long HOLD_MS = 200;    // yeni olay için gereken sessizlik / silence needed for a new event
5
6unsigned long lastSound = 0;
7unsigned long events = 0;
8
9void setup() {
10  Serial.begin(9600);
11  pinMode(SOUND_DO, INPUT);
12  pinMode(LED_BUILTIN, OUTPUT);
13}
14
15void loop() {
16  unsigned long now = millis();
17  if (digitalRead(SOUND_DO) == SOUND_ACTIVE) {
18    if (now - lastSound > HOLD_MS) {  // sessizlikten sonra ilk darbe / first pulse after silence
19      events++;
20      Serial.print(F("Ses algilandi / Sound detected #"));
21      Serial.println(events);
22    }
23    lastSound = now;                  // darbe yağmuru süreyi uzatır / the pulse burst extends the time
24  }
25  digitalWrite(LED_BUILTIN, now - lastSound < HOLD_MS ? HIGH : LOW);  // LED en az 200 ms yanar / LED stays on at least 200 ms
26}

Lo sketch legge il pin DO a ogni giro del ciclo senza delay(). Ogni volta che DO è attivo, il tempo lastSound viene aggiornato; un nuovo evento viene contato solo dopo 200 ms di silenzio, così la raffica di impulsi di un battito compare come una sola riga nel Monitor seriale. Anche il LED integrato resta acceso almeno 200 ms, altrimenti non potresti vedere a occhio impulsi di pochi millisecondi. Se il contatore continua a salire nel silenzio, o la soglia è troppo sensibile o l'uscita DO della tua scheda è invertita; nel secondo caso imposta SOUND_ACTIVE a LOW.

Perché la lettura analogica (AO) è così debole?

La maggior parte dei principianti collega AO ad A0, stampa il valore di analogRead() e vede un numero intorno a 500 che cambia appena con il suono. Il sensore non è guasto: il problema è la scala. L'ADC a 10 bit dell'Arduino Uno divide 0–5 V in 1024 passi, quindi un passo vale circa 4,9 mV. Con suoni normali il segnale prodotto dal microfono è molto più piccolo di questo passo:

SuonoLivello approssimativoUscita del microfono (picco-picco)Passi dell'ADC sull'Uno
Sussurro30 dB SPL~0,01 mV0
Conversazione normale (1 m)60 dB SPL~0,4 mV0 (invisibile)
TV ad alto volume, traffico80 dB SPL~3,6 mV0–1
Suono molto forte (1 Pa)94 dB SPL~18 mV3–4
Battito di mani secco o clacson da vicino110 dB SPL~110 mV~23

La tabella è stata calcolata con −44 dBV/Pa, la sensibilità di una tipica capsula a elettrete, supponendo un suono sinusoidale. A seconda della resistenza di polarizzazione del microfono sulla tua scheda, i valori reali possono essere alcune volte più grandi, ma la conclusione non cambia: AO vede chiaramente solo i suoni forti e vicini, mentre la conversazione normale e i sussurri restano sotto la risoluzione dell'Uno. Trovi più dettagli su come funziona l'ADC in Che cos'è un ADC?.

Il secondo motivo è la natura stessa del suono. Il suono è un'onda che oscilla su e giù intorno a un livello continuo. Una singola analogRead() cattura un istante casuale di quest'onda: può cadere su un picco, su una valle o proprio nel mezzo. Per questo il valore di una sola lettura non dice nulla sull'intensità del suono. Il terzo motivo è la velocità: l'Uno impiega circa 100 microsecondi per ogni lettura analogica, quindi fa al massimo circa 10.000 campioni al secondo. Basta per seguire il livello del suono, ma non per registrare audio o analizzare le frequenze. Infine il rumore dell'alimentazione a 5 V dell'USB finisce direttamente su AO. I primi due problemi si risolvono con il giusto metodo di misura.

Misurare l'ampiezza picco-picco: leggere correttamente l'intensità del suono

Il metodo giusto è prendere quanti più campioni possibile in una breve finestra di tempo e trovare il valore massimo e quello minimo. La loro differenza è l'ampiezza picco-picco (peak-to-peak) e indica quanto è forte il suono indipendentemente dal livello continuo. 50 ms sono una buona finestra: un periodo di 20 Hz, la frequenza più bassa che l'orecchio umano sente, dura esattamente 50 ms, quindi anche il suono più grave ci sta con un'onda intera. In questo tempo l'Uno prende circa 450–500 campioni.

Arduino (C++)
1// Tepe-tepe genlik ölçümü (Seri Çizici için) / Peak-to-peak amplitude (for the Serial Plotter)
2const int SOUND_AO = A0;                 // modülün AO pini / module AO pin
3const unsigned long WINDOW_MS = 50;      // 50 ms = 20 Hz'in bir periyodu / one period of 20 Hz
4
5void setup() {
6  Serial.begin(115200);
7}
8
9void loop() {
10  int minV = 1023, maxV = 0;
11  long sum = 0;
12  int count = 0;
13  unsigned long start = millis();
14  while (millis() - start < WINDOW_MS) { // yaklaşık 450-500 örnek / about 450-500 samples
15    int v = analogRead(SOUND_AO);
16    if (v < minV) minV = v;
17    if (v > maxV) maxV = v;
18    sum += v;
19    count++;
20  }
21  int p2p = maxV - minV;                 // tepe-tepe genlik / peak-to-peak amplitude
22  float mv = p2p * 5000.0 / 1024.0;      // milivolt karşılığı / in millivolts
23
24  Serial.print(F("p2p:"));
25  Serial.print(p2p);
26  Serial.print(F(" ortalama_avg:"));     // AO'nun DC seviyesi; istemezsen bu iki satırı sil / DC level of AO; delete these two lines if not needed
27  Serial.print(sum / count);
28  Serial.print(F(" mV:"));
29  Serial.println(mv, 1);
30}

Dopo aver caricato lo sketch, apri il Plotter seriale dal menu Strumenti e imposta la velocità a 115200. In una stanza silenziosa p2p resta di solito tra 0 e 3; sale di qualche unità se parli vicino al microfono e di decine di unità se batti le mani da vicino. Il valore ortalama_avg è il livello continuo di AO e, poiché allarga la scala del grafico, puoi cancellare le due righe di ortalama_avg se vuoi seguire p2p comodamente. Su alcune schede il trimmer sposta anche questo livello; se la media resta incollata a 0 o a 1023 il segnale viene tagliato, quindi gira il trimmer finché il valore torna verso il centro. Se usi il Plotter seriale per la prima volta, dai un'occhiata a Monitor seriale di Arduino.

Passo per passo: accendere e spegnere una lampada con un doppio battito di mani

La lampada che si accende battendo le mani è il progetto più famoso con un sensore di suono, ma un circuito che reagisce a un solo battito scatta anche con una porta sbattuta, un libro che cade o un colpo di tosse, e la lampada continua ad accendersi e spegnersi. La soluzione è cercare un ritmo: lo sketch seguente reagisce solo a esattamente due battiti distanti tra 0,12 e 0,7 secondi. Un suono isolato, oppure tre o più suoni (musica, applausi, un cane che abbaia), vengono ignorati.

  1. Collega il pin + del KY-038 a 5V, G a GND e DO a D2.
  2. Collega il pin VCC del modulo relè a 5V, GND a GND e IN a D7. Trovi come funziona un relè e come cablare il lato del carico in Che cos'è un modulo relè?; fai le prime prove con il LED del relè invece che con una lampada.
  3. Carica lo sketch e apri il Monitor seriale a 9600 baud.
  4. Batti le mani due volte a uno o due metri dal sensore. Per ogni battito dovresti vedere una sola riga «Alkis / Clap»; se un battito viene contato più volte, gira il trimmer un po' verso meno sensibile.
  5. Osserva la lampada cambiare stato circa 0,7 secondi dopo il secondo battito.
Arduino (C++)
1// Çift alkışla lamba (röle) / Double-clap lamp (relay)
2const int SOUND_DO = 2;                     // KY-038 DO pini / KY-038 DO pin
3const int RELAY = 7;                        // röle modülü IN / relay module IN
4const int SOUND_ACTIVE = HIGH;              // kartın tersse LOW / LOW if your board is inverted
5const int RELAY_ON = LOW;                   // aktif LOW röle modülü / active-LOW relay module
6const int RELAY_OFF = HIGH;
7const unsigned long QUIET_GAP_MS = 120;     // yeni alkış için gereken sessizlik / silence needed before a new clap
8const unsigned long CLAP_WINDOW_MS = 700;   // dizinin bittiğine karar verme süresi / time to decide the series is over
9const unsigned long LOCKOUT_MS = 1000;      // röle tıkırtısını yok say / ignore the relay click
10
11int clapCount = 0;
12unsigned long lastPulse = 0;                // DO'nun son aktif olduğu an / last time DO was active
13unsigned long lastToggle = 0;               // lambanın son değiştiği an / last time the lamp changed
14bool lampOn = false;
15
16void setup() {
17  Serial.begin(9600);
18  pinMode(SOUND_DO, INPUT);
19  pinMode(RELAY, OUTPUT);
20  digitalWrite(RELAY, RELAY_OFF);           // lamba kapalı başlar / lamp starts off
21}
22
23void loop() {
24  unsigned long now = millis();
25
26  if (digitalRead(SOUND_DO) == SOUND_ACTIVE) {
27    bool locked = now - lastToggle < LOCKOUT_MS;
28    if (!locked && now - lastPulse >= QUIET_GAP_MS) {  // sessizlikten sonra ilk darbe = yeni alkış / first pulse after silence = new clap
29      clapCount++;
30      Serial.print(F("Alkis / Clap: "));
31      Serial.println(clapCount);
32    }
33    lastPulse = now;                        // aynı alkışın darbeleri süreyi uzatır / pulses of the same clap extend the time
34  }
35
36  if (clapCount > 0 && now - lastPulse > CLAP_WINDOW_MS) {  // dizi bitti / the series is over
37    if (clapCount == 2) {                   // yalnız tam iki alkış / exactly two claps only
38      lampOn = !lampOn;
39      digitalWrite(RELAY, lampOn ? RELAY_ON : RELAY_OFF);
40      lastToggle = now;
41      if (lampOn) Serial.println(F("Lamba ACIK / Lamp ON"));
42      else Serial.println(F("Lamba KAPALI / Lamp OFF"));
43    }
44    clapCount = 0;                          // 1, 3 ve fazlası yok sayılır / 1, 3 or more are ignored
45  }
46}
CostanteValoreFunzione
SOUND_ACTIVEHIGHLivello che DO assume quando c'è suono; impostalo a LOW se la tua scheda è invertita
QUIET_GAP_MS120 msSilenzio necessario prima di contare un nuovo battito; la raffica di impulsi e l'eco di un battito contano come uno
CLAP_WINDOW_MS700 msDopo questo silenzio dall'ultimo suono la serie è finita e i battiti vengono valutati
LOCKOUT_MS1000 msDopo il cambio della lampada i suoni vengono ignorati, così il clic del relè non viene scambiato per un battito
RELAY_ON / RELAY_OFFLOW / HIGHPer un modulo relè attivo basso; scambiali su un modulo attivo alto

Lo sketch non usa delay(): misura tutto con millis(), così non perde il momento di nessun battito. Spieghiamo questo approccio in dettaglio in millis e delay a confronto. Il fatto che la lampada cambi 0,7 secondi dopo il secondo battito e non subito è una scelta voluta: lo sketch aspetta di vedere se arriva un terzo battito. Se vuoi una risposta più rapida puoi abbassare CLAP_WINDOW_MS a 400–500 ms, ma allora dovrai battere le mani più velocemente. Se la tua stanza rimbomba molto e un solo battito viene contato due volte, porta QUIET_GAP_MS a 150–200 ms.

Commutare la tensione di rete (230 V) con un relè può essere mortale. Fai i collegamenti con la spina staccata, non lasciare estremità di filo scoperte e metti il circuito in una scatola isolante e chiusa; se non sei sicuro, prova prima con una striscia LED a 12 V. Tieni inoltre il sensore lontano dal relè: se il clic del relè è molto vicino al microfono può dare problemi nonostante il tempo di blocco.

Indicatore del livello sonoro: VU meter a 8 LED

Mandare direttamente ai LED il valore picco-picco funziona, ma il risultato non sembra naturale, perché il nostro orecchio percepisce il suono in modo logaritmico: un suono con ampiezza doppia non ci sembra due volte più forte. Per questo il suono si misura in decibel (dB). Per l'ampiezza la formula è dB = 20 × log10(p2p / riferimento); il doppio dell'ampiezza vale +6 dB, dieci volte +20 dB. Lo sketch seguente misura all'avvio, per un secondo, il rumore di fondo della stanza e lo usa come riferimento; ogni LED rappresenta 3 dB sopra questo fondo. Collega i LED ai pin D3–D10, ognuno con una resistenza da 220 Ω; per LED di altri colori puoi trovare la resistenza giusta con il calcolatore di resistenza per LED.

Arduino (C++)
1// 8 LED'li ses seviyesi göstergesi (VU metre) / 8-LED sound level bar (VU meter)
2const int SOUND_AO = A0;                    // modülün AO pini / module AO pin
3const int LED_PINS[8] = {3, 4, 5, 6, 7, 8, 9, 10};  // her LED 220 Ω ile / each LED with 220 Ω
4const float DB_PER_LED = 3.0;               // her LED 3 dB / each LED is 3 dB
5const unsigned long FALL_MS = 80;           // LED'ler bu aralıkla birer birer söner / LEDs drop one by one at this rate
6
7float noiseFloor = 1.0;                     // sessiz ortamın p2p değeri / quiet-room p2p
8int shown = 0;                              // yanan LED sayısı / number of lit LEDs
9unsigned long lastFall = 0;
10
11int readPeakToPeak() {
12  int minV = 1023, maxV = 0;
13  unsigned long start = millis();
14  while (millis() - start < 50) {           // 50 ms pencere / 50 ms window
15    int v = analogRead(SOUND_AO);
16    if (v < minV) minV = v;
17    if (v > maxV) maxV = v;
18  }
19  return maxV - minV;
20}
21
22void setup() {
23  Serial.begin(115200);
24  for (int i = 0; i < 8; i++) pinMode(LED_PINS[i], OUTPUT);
25  long sum = 0;
26  for (int i = 0; i < 20; i++) sum += readPeakToPeak();  // 1 sn sessizlik ölç / measure 1 s of silence
27  noiseFloor = sum / 20.0;
28  if (noiseFloor < 1.0) noiseFloor = 1.0;
29}
30
31void loop() {
32  int p2p = readPeakToPeak();
33  if (p2p < 1) p2p = 1;
34  float db = 20.0 * log10(p2p / noiseFloor);  // tabana göre göreceli dB / relative dB above the floor
35  int level = constrain((int)(db / DB_PER_LED), 0, 8);
36
37  unsigned long now = millis();
38  if (level >= shown) {                     // yükselişte anında / rise instantly
39    shown = level;
40    lastFall = now;
41  } else if (now - lastFall >= FALL_MS) {   // inişte yavaşça / fall slowly
42    shown--;
43    lastFall = now;
44  }
45  for (int i = 0; i < 8; i++) digitalWrite(LED_PINS[i], i < shown ? HIGH : LOW);
46
47  Serial.print(F("dB:"));
48  Serial.println(db, 1);
49}

Ricordati di restare in silenzio per un secondo all'avvio; se parli in quel momento il fondo viene misurato troppo alto e l'indicatore reagisce meno. L'indicatore sale subito ma scende lentamente, un LED ogni 80 ms; per questo anche i veri VU meter appaiono fluidi e non nervosi. Dato che il segnale analogico del KY-038 è debole, 2–3 dB per LED vanno bene; se usi lo stesso sketch con un microfono amplificato come il MAX4466, puoi portare DB_PER_LED a 4–6 dB. Per un indicatore a colori puoi usare un anello NeoPixel al posto dei LED; i dettagli sono in LED NeoPixel WS2812B.

Sensore di suono con ESP32: rilevare i battiti con un interrupt

L'ADC dell'ESP32 è a 12 bit e dà valori da 0 a 4095; su un intervallo di 3,3 V un passo vale circa 0,8 mV, cioè una risoluzione circa 6 volte più fine dell'Uno. In compenso l'ADC dell'ESP32 è più rumoroso, quindi anche il valore p2p in una stanza silenziosa risulta più alto; il calcolo dei dB relativi compensa da solo questa differenza. Nello sketch seguente il pin DO è collegato a un interrupt: nessun impulso di battito va perso, anche mentre loop() misura per 50 ms il livello del suono su AO. La funzione di interrupt viene messa in RAM con IRAM_ATTR e tenuta breve; le variabili usate sia dall'interrupt sia da loop() sono dichiarate volatile e protette da una sezione critica.

Arduino (C++)
1// ESP32: kesmeyle çift alkış + ses seviyesi / ESP32: double clap via interrupt + sound level
2const int SOUND_AO = 34;                    // ADC1 pini, Wi-Fi açıkken de çalışır / ADC1 pin, works with Wi-Fi on
3const int SOUND_DO = 27;                    // modülün DO pini / module DO pin
4const int RELAY = 26;                       // röle modülü IN / relay module IN
5const int SOUND_ACTIVE = HIGH;              // kartın tersse LOW / LOW if your board is inverted
6const int RELAY_ON = LOW;                   // aktif LOW röle / active-LOW relay
7const int RELAY_OFF = HIGH;
8const unsigned long QUIET_GAP_MS = 120;     // yeni alkış için sessizlik / silence before a new clap
9const unsigned long CLAP_WINDOW_MS = 700;   // dizinin bitmesi / end of the series
10const unsigned long LOCKOUT_MS = 1000;      // röle tıkırtısını yok say / ignore the relay click
11
12portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;  // kesme ile loop arasında kilit / lock between ISR and loop
13volatile int clapCount = 0;
14volatile unsigned long lastPulse = 0;
15volatile unsigned long lastToggle = 0;
16bool lampOn = false;
17float noiseFloor = 1.0;
18
19void IRAM_ATTR onSound() {                  // kısa tutulur, RAM'den çalışır / kept short, runs from RAM
20  unsigned long now = millis();
21  portENTER_CRITICAL_ISR(&mux);
22  if (now - lastToggle >= LOCKOUT_MS && now - lastPulse >= QUIET_GAP_MS) clapCount++;
23  lastPulse = now;
24  portEXIT_CRITICAL_ISR(&mux);
25}
26
27int readPeakToPeak() {
28  int minV = 4095, maxV = 0;
29  unsigned long start = millis();
30  while (millis() - start < 50) {           // 50 ms pencere / 50 ms window
31    int v = analogRead(SOUND_AO);           // 0-4095 (12 bit)
32    if (v < minV) minV = v;
33    if (v > maxV) maxV = v;
34  }
35  return maxV - minV;
36}
37
38void setup() {
39  Serial.begin(115200);
40  pinMode(SOUND_DO, INPUT);
41  pinMode(RELAY, OUTPUT);
42  digitalWrite(RELAY, RELAY_OFF);
43  long sum = 0;
44  for (int i = 0; i < 20; i++) sum += readPeakToPeak();  // 1 sn sessiz ortam / 1 s of quiet room
45  noiseFloor = sum / 20.0;
46  if (noiseFloor < 1.0) noiseFloor = 1.0;
47  attachInterrupt(digitalPinToInterrupt(SOUND_DO), onSound, SOUND_ACTIVE == HIGH ? RISING : FALLING);
48}
49
50void loop() {
51  int p2p = readPeakToPeak();               // bu sırada alkışları kesme yakalar / the interrupt catches claps meanwhile
52  float db = 20.0 * log10((p2p < 1 ? 1 : p2p) / noiseFloor);
53  Serial.printf("p2p:%d dB:%.1f\n", p2p, db);
54
55  portENTER_CRITICAL(&mux);
56  unsigned long now = millis();
57  int claps = clapCount;
58  bool finished = claps > 0 && now - lastPulse > CLAP_WINDOW_MS;
59  if (finished) clapCount = 0;              // dizi bitti, sayacı sıfırla / series over, reset the counter
60  portEXIT_CRITICAL(&mux);
61
62  if (finished && claps == 2) {             // yalnız tam iki alkış / exactly two claps only
63    lampOn = !lampOn;
64    digitalWrite(RELAY, lampOn ? RELAY_ON : RELAY_OFF);
65    portENTER_CRITICAL(&mux);
66    lastToggle = millis();
67    portEXIT_CRITICAL(&mux);
68    Serial.println(lampOn ? "Lamba ACIK / Lamp ON" : "Lamba KAPALI / Lamp OFF");
69  }
70}

Lo sketch esegue la stessa logica del doppio battito dell'Uno, ma dentro l'interrupt, e stampa il livello del suono in dB circa ogni 50 ms. Collega il pin IN del modulo relè al GPIO 26; alcuni moduli relè attivi bassi alimentati a 5 V non si rilasciano del tutto con il livello HIGH a 3,3 V dell'ESP32, quindi in quel caso scegli un modulo comandabile a 3,3 V. La vera forza dell'ESP32 è il Wi-Fi: se il livello del suono resta sopra una soglia per qualche secondo (per esempio se un bambino piange o un cane abbaia), puoi inviare una notifica al telefono. Per farlo usa il metodo di bot Telegram con ESP32 e, per collegarlo a un sistema domotico, ESP32 con MQTT e Home Assistant.

Sensore di suono con Raspberry Pi Pico e MicroPython

Sul Raspberry Pi Pico alimenta il modulo dal pin 3V3(OUT), collega AO a GP26 e DO a GP15 e, al posto della lampada, metti un LED con una resistenza da 220 Ω su GP14. L'ADC del Pico è a 12 bit, ma in MicroPython read_u16() riporta il valore su 0–65535; per questo i numeri p2p sembrano molto più grandi che sull'Uno, mentre il calcolo dei dB relativi resta lo stesso. Per il pin DO si imposta un interrupt con Pin.irq().

MicroPython
1# Raspberry Pi Pico: çift alkış + ses seviyesi / double clap + sound level
2from machine import Pin, ADC
3import time, math
4
5sound_ao = ADC(26)                  # GP26 = ADC0, modülün AO pini / module AO pin
6sound_do = Pin(15, Pin.IN)          # modülün DO pini / module DO pin
7lamp = Pin(14, Pin.OUT, value=0)    # LED (220 Ω ile) / LED (with 220 Ω)
8
9QUIET_GAP_MS = 120                  # yeni alkış için sessizlik / silence before a new clap
10CLAP_WINDOW_MS = 700                # dizinin bitmesi / end of the series
11LOCKOUT_MS = 1000                   # değişimden sonra sesleri yok say / ignore sounds after a toggle
12
13claps = 0
14last_pulse = time.ticks_ms()
15last_toggle = time.ticks_ms()
16
17def on_sound(pin):                  # kesme fonksiyonu / interrupt handler
18    global claps, last_pulse
19    now = time.ticks_ms()
20    if (time.ticks_diff(now, last_toggle) >= LOCKOUT_MS
21            and time.ticks_diff(now, last_pulse) >= QUIET_GAP_MS):
22        claps += 1
23    last_pulse = now
24
25# DO sesle LOW oluyorsa IRQ_FALLING yaz / use IRQ_FALLING if DO goes LOW on sound
26sound_do.irq(trigger=Pin.IRQ_RISING, handler=on_sound)
27
28def peak_to_peak(window_ms=50):     # 50 ms boyunca en büyük - en küçük / max - min over 50 ms
29    lo, hi = 65535, 0
30    start = time.ticks_ms()
31    while time.ticks_diff(time.ticks_ms(), start) < window_ms:
32        v = sound_ao.read_u16()     # 0-65535
33        if v < lo:
34            lo = v
35        if v > hi:
36            hi = v
37    return hi - lo
38
39noise_floor = max(1, sum(peak_to_peak() for _ in range(20)) / 20)  # 1 sn sessizlik / 1 s of silence
40
41while True:
42    p2p = peak_to_peak()
43    db = 20 * math.log10(max(p2p, 1) / noise_floor)   # göreceli dB / relative dB
44    print("p2p:", p2p, "dB:", round(db, 1))
45
46    now = time.ticks_ms()
47    if claps and time.ticks_diff(now, last_pulse) > CLAP_WINDOW_MS:
48        if claps == 2:              # yalnız tam iki alkış / exactly two claps only
49            lamp.toggle()
50            last_toggle = now
51            print("Lamba / Lamp:", "ON" if lamp.value() else "OFF")
52        claps = 0

Quando esegui il codice in Thonny vedi i valori p2p e dB nella Shell; se apri il Plotter dal menu Visualizza puoi seguirli come grafico. Se l'uscita DO della tua scheda va a LOW con il suono, scrivi IRQ_FALLING invece di IRQ_RISING. Perché il programma parta da solo quando il Pico viene alimentato, salva il file sul Pico con il nome main.py. Se sei alle prime armi con MicroPython, le basi di MicroPython sono un buon punto di partenza.

Si possono misurare i decibel con un sensore di suono?

Risposta breve: no. In rete trovi moltissimi sketch che con map() convertono il valore picco-picco del KY-038 in un intervallo come 49–90 dB; sono stime, non misure. Per misurare un vero livello di pressione sonora (dB SPL) servono un microfono di sensibilità nota e un sistema tarato con un calibratore da 94 dB, un'amplificazione lineare del segnale, un valore efficace (RMS) calcolato su un tempo fisso (125 ms in modalità veloce, 1 s in modalità lenta) e un filtro di ponderazione A che imita la sensibilità dell'orecchio. Per questo i fonometri sono costruiti secondo la norma IEC 61672.

Il KY-038 non soddisfa nessuna di queste condizioni: il guadagno della scheda è sconosciuto, la sensibilità delle capsule varia di qualche dB da un esemplare all'altro, il trimmer e la tensione di alimentazione cambiano il livello del segnale e sull'Uno tutti i suoni normali sono schiacciati in pochi passi dell'ADC. La cosa più onesta che puoi fare è una misura relativa: dire «in questo momento c'è un rumore di 12 dB superiore alla stanza in silenzio». Anche solo questo basta e avanza per un allarme di rumore, un semaforo del rumore in classe o un VU meter. Puoi fare una taratura grossolana confrontandoti con un'app del telefono in un punto, ma quella taratura non vale più ad altri livelli sonori né su un'altra scheda.

Alternative: MAX4466, MAX9814 e INMP441

ModuloUscitaGuadagnoMisura in decibelSchede adatte
KY-038 / KY-037AO (grezza) + DO (soglia)NessunoNoTutte
MAX4466Analogica, centrata su VCC/2Da 25 a 125 volte, regolabileSolo relativaTutte
MAX9814Analogica, centrata su 1,25 V, max 2 Vpp40 / 50 / 60 dB + controllo automatico del guadagno (AGC)No, l'AGC comprime il livelloTutte
INMP441Digitale I2S, 24 bitNon servedB SPL approssimativiESP32, Pico (non l'Uno)
Modulo fonometro pronto (es. DFRobot SEN0232)Analogica, direttamente in dBATarato in fabbricaSì, 30–130 dBA, ±1,5 dBTutte

Il MAX4466 unisce lo stesso tipo di microfono a elettrete a un amplificatore operazionale a guadagno regolabile. La sua uscita resta a metà della tensione di alimentazione nel silenzio e, con una conversazione normale vicina, dà un segnale di centinaia di millivolt; in altre parole, il segnale di pochi passi di ADC del KY-038 diventa di decine o persino centinaia di passi. Gli sketch picco-picco e VU meter di questo articolo funzionano con il MAX4466 senza alcuna modifica. Se ti incuriosisce come si calcola il guadagno, guarda il calcolatore di guadagno dell'operazionale e Che cos'è un amplificatore operazionale?. Alimentare il modulo dal pin 3.3V dell'Uno, più pulito, riduce il rumore. Il MAX9814, invece, porta a un livello utile anche la voce lontana grazie al controllo automatico del guadagno; è ottimo per registrare e rilevare la voce, ma non è adatto a misurare il livello, perché avvicina tra loro gli ambienti silenziosi e quelli rumorosi.

L'INMP441 non è nemmeno analogico, ma un microfono MEMS digitale: converte internamente il suono in numeri a 24 bit e li invia su un bus I2S, così il rumore sui fili non entra nella misura. Il suo vantaggio principale è che il produttore ne indica la sensibilità con una tolleranza stretta: un suono di 94 dB SPL viene letto come −26 dBFS. Quindi, se converti in dBFS il valore RMS misurato e aggiungi 120, ottieni un valore approssimativo in dB SPL. Per l'I2S servono un ESP32 o un Pico; l'Arduino Uno non ha hardware I2S. I moduli INMP441 per hobbisti sono economici e facili da trovare, e l'ICS-43434 e l'SPH0645 sono microfoni I2S simili. Se ti serve davvero una misura del rumore precisa, la strada più semplice è un modulo fonometro pronto con uscita tarata e ponderata A; per esempio, moltiplicando per 50 la tensione di uscita del DFRobot SEN0232 ottieni direttamente il valore in dBA.

Idee di progetto con il sensore di suono

  • Lampada a battito di mani: Aggiungi un modulo relè allo sketch del doppio battito per comandare la lampada della scrivania o una striscia LED, e assegna tre battiti a un secondo dispositivo.
  • Semaforo del rumore in classe: Un indicatore che accende LED verdi, gialli e rossi in base al valore relativo in dB; gli insegnanti lo adorano.
  • Baby monitor e avviso per animali: Se il suono resta forte per più di 5 secondi, l'ESP32 invia un messaggio Telegram al tuo telefono.
  • Luci che reagiscono al suono: Un anello o una striscia NeoPixel che pulsa a ritmo di musica.
  • Rilevatore di colpi alla porta: Un circuito che ti avvisa con un buzzer o un LED quando qualcuno bussa; per catturare il colpo come vibrazione anziché come suono, anche il sensore di vibrazione SW-420 è un'ottima scelta.
  • Scenari di casa intelligente: Combina il suono con sensori di movimento e di luce per spegnere le luci quando nella stanza non c'è nessuno; per qualche idea guarda il progetto di casa intelligente con Arduino.

Errori comuni e soluzioni

SintomoCausa probabileSoluzione
Il LED DO resta sempre accesoLa soglia è troppo sensibile o c'è un rumore continuo (ventola, frigorifero)Gira il trimmer nel silenzio finché il LED si spegne e allontana il sensore dalla fonte di rumore
Battendo le mani non succede nullaLa soglia è troppo alta o DO è sul pin sbagliatoControlla prima che il LED della scheda lampeggi con il battito, poi il filo e il numero del pin nel codice
Il contatore sale nel silenzio e si ferma con il suonoL'uscita DO della scheda è attiva bassaImposta SOUND_ACTIVE a LOW; sul Pico usa IRQ_FALLING
analogRead resta intorno a 500 e cambia di 1–2 con il suonoAO non è amplificata e si fanno solo letture singoleUsa il metodo picco-picco, avvicina il suono o passa a un MAX4466
AO è sempre 0 o 1023AO e DO sono scambiati o il livello continuo è finito al limiteControlla i collegamenti e porta la media al centro con il trimmer
Un solo battito viene contato due volteLa stanza rimbomba o QUIET_GAP_MS è troppo brevePorta QUIET_GAP_MS a 150–200 ms e rendi la soglia un po' meno sensibile
La lampada si accende e si spegne da solaClic del relè, porte sbattute o musicaAumenta LOCKOUT_MS, allontana il sensore dal relè e mantieni la regola del doppio battito
Sull'ESP32 AO smette di leggere quando il Wi-Fi è attivoAO è su un pin ADC2Sposta AO su un pin ADC1 tra GPIO 32 e 39
Un modo pratico per provare il sensore di suono è un'app generatore di toni sul telefono. Riproduci un tono costante a 1 kHz e tieni il telefono a 10, 20 e 40 cm dal microfono: in campo libero, ogni volta che la distanza raddoppia la pressione sonora si dimezza, quindi p2p dovrebbe scendere più o meno alla metà e il valore in dB calare di circa 6 dB. Questo semplice esperimento verifica insieme collegamenti e codice.

Con pochi fili e un codice ben scritto, il KY-038 insegna in un colpo solo molte basi dell'elettronica: comparatori, conversione analogico-digitale, interrupt, temporizzazione e calcolo dei decibel. Comincia rilevando i battiti con DO, misura il livello del suono con il metodo picco-picco e passa a un MAX4466 o a un INMP441 quando ti serve una vera misura del suono. Nell'app BlueGrays trovi progetti di lampada con relè, LED in sequenza, illuminazione intelligente con ESP32 e striscia NeoPixel con schemi elettrici e codice passo per passo; aggiungere un sensore di suono è il modo più semplice per trasformarli in sistemi che rispondono ai battiti di mani o al rumore.

Domande frequenti

Come funziona un sensore di suono per Arduino?

Il sensore di suono confronta, tramite un comparatore LM393, la piccola tensione del suo microfono a elettrete con una soglia impostata dal trimmer. Quando il suono supera la soglia, il pin DO cambia stato e si accende il LED della scheda. Il pin AO fornisce il segnale grezzo del microfono, non amplificato, che si legge con analogRead().

Che differenza c'è tra KY-038 e KY-037?

Entrambi usano lo stesso circuito LM393 e lo stesso ordine dei pin AO, G, +, DO, e il codice è identico. Il KY-037 ha una capsula microfonica più grande ed è di solito un po' più sensibile; il KY-038 è più piccolo e più diffuso nei kit di sensori.

Come si regola la sensibilità di un sensore di suono?

Nel silenzio, gira il trimmer blu fino al punto in cui il LED DO tremola, poi torna indietro di mezzo giro o di un giro verso il lato in cui il LED resta spento. Essendo un trimmer multigiro, possono servire diversi giri prima di vedere un cambiamento. Regolalo sempre nel posto in cui userai il sensore.

Si possono misurare i decibel con un sensore di suono?

Con KY-038 e KY-037 non si possono misurare i veri decibel (dB SPL): guadagno della scheda e sensibilità del microfono sono sconosciuti, e mancano taratura e ponderazione A. Si possono calcolare solo dB relativi rispetto a una stanza silenziosa. Per misure reali usa un microfono I2S di sensibilità nota come l'INMP441 o un modulo fonometro tarato.

Perché il valore analogico del mio sensore di suono non cambia?

L'uscita AO è il segnale del microfono non amplificato e, con suoni normali, è più piccola di un passo dell'ADC dell'Uno, pari a 4,9 mV. Inoltre una singola analogRead() legge un istante casuale dell'onda sonora. Campiona per 50 ms e calcola la differenza tra il valore massimo e quello minimo (picco-picco): vedrai chiaramente la variazione.

Il sensore di suono funziona con ESP32 e Raspberry Pi Pico?

Sì, il modulo funziona anche a 3,3 V; su ESP32 e Pico alimentalo dal pin 3V3 così l'uscita DO non supera mai 3,3 V. Sull'ESP32 collega AO a un pin ADC1 (GPIO 32–39), che non va in conflitto con il Wi-Fi, e sul Pico a GP26, GP27 o GP28.

Vedi tutti i progetti
Accendere e spegnere un LED con un pulsante
#10Principiante

Accendere e spegnere un LED con un pulsante

Premi il pulsante una volta e la luce si accende, premilo di nuovo e si spegne, proprio come l'interruttore della tua stanza. L'Arduino si accorge di ogni pressione e porta il LED nello stato opposto,

4.8(100)
162
Controllo LED ESP32 con pulsante (Toggle)
#105Principiante

Controllo LED ESP32 con pulsante (Toggle)

Ogni volta che si preme il pulsante, lo stato del LED cambia: se è acceso si spegne, se è spento si accende. Classico schema toggle. Con il debounce puliamo il rumore meccanico del pulsante per garantire una singola commutazione con una sola pressione.

4.6(39)
57
LED in sequenza
#5Intermedio

LED in sequenza

Luci che si accendono una dopo l'altra, come se corressero. L'Arduino accende sei LED uno alla volta; ognuno brilla per un istante e si spegne, così la luce percorre la fila dall'inizio alla fine e po

4.6(85)
201
Accendere e spegnere una lampadina 220V con un pulsante
#20Avanzato
Premium

Accendere e spegnere una lampadina 220V con un pulsante

Vuoi accendere e spegnere una vera lampadina di casa con un piccolo pulsante? Ogni volta che lo premi, l'Arduino fa scattare un relè e la lampadina si accende; premendo di nuovo si spegne. Il relè è u

4.5(33)
44
Raspberry Pi Pico Pulsante Toggle LED (GP14 + GP2)
#156Principiante
Premium

Raspberry Pi Pico Pulsante Toggle LED (GP14 + GP2)

Pulsante + LED — livello successivo! 🔁 A differenza di #155, non serve tenere premuto. Premi e rilascia → LED acceso. Premi di nuovo → LED spento (toggle). Stesso circuito di #155, grande differenza di codice. Impara edge detection, state tracking e debounce.

0.0(0)
9
Illuminazione Intelligente ESP32 (PIR + LDR + Relè + OLED)
#141Avanzato
Premium

Illuminazione Intelligente ESP32 (PIR + LDR + Relè + OLED)

Trasforma il tuo corridoio, bagno o dispensa in illuminazione intelligente con ESP32! Utilizzando un sensore di movimento PIR, un sensore di luce LDR e un modulo relè, costruiamo lo scenario classico "la luce si accende quando viene rilevato movimento al buio" — se l'ambiente è già luminoso, il movimento NON attiva la luce, risparmiando energia durante il giorno. La luce rimane accesa per 30 secondi; se il movimento continua, il timer si azzera e la luce rimane accesa più a lungo. Il display OLE

4.3(6)
11
Sensore di parcheggio ESP32 (HC-SR04 + barra a 5 LED + cicalino + OLED)
#142Avanzato
Premium

Sensore di parcheggio ESP32 (HC-SR04 + barra a 5 LED + cicalino + OLED)

La versione ESP32 del sensore di parcheggio per auto! Grazie al sensore a ultrasuoni HC-SR04 misuriamo la distanza dall'oggetto davanti al veicolo. Man mano che la distanza diminuisce, la barra composta da 5 LED si riempie (da verde → giallo → rosso) e l'intervallo tra i bip del cicalino si accorcia. Quando ci si avvicina troppo (meno di 10 cm), l'allarme suona ininterrottamente e tutti i LED si accendono. Sul display OLED SSD1306 vengono visualizzati in caratteri grandi il valore istantaneo in

0.0(0)
14
Controllo della striscia LED NeoPixel WS2812B con ESP32
#126Intermedio
Premium

Controllo della striscia LED NeoPixel WS2812B con ESP32

I LED indirizzabili WS2812B (NeoPixel) sono LED RGB intelligenti che possono essere controllati in cascata tramite un unico pin dati. In questo progetto controlleremo una striscia WS2812B da 8 LED utilizzando la libreria Adafruit_NeoPixel per creare un'animazione fluida dell'arcobaleno. Sebbene il livello logico a 3,3 V dell'ESP32 funzioni senza problemi con la maggior parte dei componenti WS2812B, in caso di instabilità mostreremo la soluzione con una resistenza in serie da 470 Ω e un condensat

4.9(19)
30