PROGETTI ARDUINO

  • HOME
  • 200 Progetti
  • Progetti e Tutorial
  • Reti
    • Impara le reti
    • internet fibra
    • wifi mesh
    • modem router
    • diagnostica reti
    • ethernet lan
    • sicurezza configurazione
  • Elettronica
  • Recensioni
  • Manuale
  • Contatti
  • HOME
  • 200 Progetti
  • Progetti e Tutorial
  • Reti
    • Impara le reti
    • internet fibra
    • wifi mesh
    • modem router
    • diagnostica reti
    • ethernet lan
    • sicurezza configurazione
  • Elettronica
  • Recensioni
  • Manuale
  • Contatti

Progetto 134
​Controllo volume con encoder e buzzer

🚀 Introduzione

Vuoi realizzare una manopola del volume simile a quella di una radio o di un amplificatore? 🎛️🔊

In questo progetto utilizzerai un encoder rotativo per aumentare o diminuire il volume di un buzzer, visualizzando il livello impostato su un display OLED.

Premendo la manopola potrai inoltre attivare o disattivare rapidamente l’audio tramite una funzione mute.
​
👉 Il progetto introduce il controllo di un’uscita sonora attraverso un’interfaccia semplice, compatta e intuitiva.

🎯 Cosa realizzerai
​

Con Arduino creerai un sistema che:
  • 🎛️ legge la rotazione di un encoder;
  • ➕ aumenta il volume;
  • ➖ diminuisce il volume;
  • 🔇 attiva e disattiva la modalità mute;
  • 🔊 riproduce un tono attraverso un buzzer;
  • 📟 mostra il volume su display OLED;
  • 📊 visualizza una barra grafica;
  • 💾 conserva il livello precedente durante il mute;
  • ⏱️ gestisce encoder e pulsante senza bloccare Arduino;
  • 🚫 limita il volume tra 0% e 100%.

🧰 Materiale necessario
​
  • 1x Arduino UNO;
  • 1x encoder rotativo KY-040 o compatibile;
  • 1x display OLED 0,96 pollici I2C SSD1306;
  • 1x buzzer passivo;
  • 1x resistenza da 100 Ω;
  • cavetti jumper;
  • breadboard;
  • cavo USB.
La resistenza da 100 Ω viene collegata in serie al buzzer per limitare la corrente.

🛒 Non hai ancora i componenti?

Molti dei progetti presenti su progettiarduino.com utilizzano componenti elettronici di base come LED, resistenze, sensori e breadboard.
Se stai iniziando con Arduino, il modo più semplice è utilizzare un kit completo per principianti, che include quasi tutti i componenti necessari per realizzare molti dei progetti presenti sul sito.

👉 Kit Arduino consigliato:
ℹ️ Link di affiliazione Amazon: in qualità di Affiliato Amazon ricevo un guadagno dagli acquisti idonei, senza alcun costo aggiuntivo per te.
https://amzn.to/4b3dxjW

📘 Vuoi imparare Arduino passo dopo passo?
Se vuoi approfondire e realizzare progetti più completi, puoi dare un'occhiata anche ai miei libri dedicati ad Arduino.
All'interno troverai spiegazioni semplici, schemi chiari e molti progetti pratici pensati per chi parte da zero.

👉 Scopri i miei libri su Arduino:
ℹ️ Link di affiliazione Amazon: in qualità di Affiliato Amazon ricevo un guadagno dagli acquisti idonei, senza alcun costo aggiuntivo per te.
https://amzn.to/4rfzjXE
​

📚 Librerie necessarie
​

Per utilizzare il display OLED devi installare:
  • Adafruit SSD1306;
  • Adafruit GFX Library.
La libreria Wire è già inclusa nell’Arduino IDE.
Per la gestione dell’encoder e del buzzer non sono necessarie librerie aggiuntive.

🔌 Schema di collegamento

Display OLED SSD1306
  • VCC → 5V;
  • GND → GND;
  • SDA → A4;
  • SCL → A5.
L’indirizzo I2C utilizzato nel codice è 0x3C.

Encoder rotativo KY-040
  • + → 5V;
  • GND → GND;
  • CLK → pin digitale 2;
  • DT → pin digitale 3;
  • SW → pin digitale 4.
Il pin SW corrisponde al pulsante integrato nella manopola.

Buzzer passivo
  • terminale positivo → resistenza da 100 Ω;
  • resistenza → pin digitale 9;
  • terminale negativo → GND.
Il pin 9 viene utilizzato come uscita PWM per regolare l’intensità del segnale.
Foto

💻 Codice Arduino
​

Il programma controlla il volume attraverso l’encoder.
Ogni scatto modifica il livello di 5 punti percentuali.
Il volume può assumere valori compresi tra:
  • 0%;
  • 100%.
​
Premendo la manopola viene attivata la modalità mute.
Premendola nuovamente, il volume torna al valore precedente.
​/*
  ============================================================
  Progetto 134 - Controllo volume con encoder e buzzer
  Regola il livello audio e gestisce la funzione mute
  ============================================================
*/

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// Dimensioni e indirizzo del display OLED
#define LARGHEZZA_DISPLAY 128
#define ALTEZZA_DISPLAY 64
#define RESET_OLED -1
#define INDIRIZZO_OLED 0x3C

// Collegamenti dell'encoder rotativo
#define PIN_CLK 2
#define PIN_DT 3
#define PIN_SW 4

// Pin collegato al buzzer passivo
#define PIN_BUZZER 9

// Frequenza del tono generato
const unsigned int FREQUENZA_TONO = 1000;

// Incremento applicato a ogni scatto
const byte PASSO_VOLUME = 5;

// Tempi utilizzati per ridurre
// rimbalzi e letture multiple
const unsigned long TEMPO_DEBOUNCE_PULSANTE = 180;
const unsigned long TEMPO_MINIMO_ROTAZIONE = 3;

// Oggetto utilizzato per controllare il display OLED
Adafruit_SSD1306 display(
  LARGHEZZA_DISPLAY,
  ALTEZZA_DISPLAY,
  &Wire,
  RESET_OLED
);

// Volume corrente espresso in percentuale
byte volume = 50;

// Memorizza il volume prima dell'attivazione del mute
byte volumePrecedente = 50;

// Indica se il sistema è in modalità mute
bool muteAttivo = false;

// Stato precedente del segnale CLK
int statoPrecedenteClk = HIGH;

// Variabili temporali dell'interfaccia
unsigned long ultimaRotazione = 0;
unsigned long ultimaPressione = 0;

// Variabili utilizzate per generare il segnale audio
unsigned long ultimoCambioSegnale = 0;
bool uscitaBuzzerAlta = false;

// Indica quando il display deve essere aggiornato
bool aggiornamentoDisplayRichiesto = true;

void setup() {
  // I pin dell'encoder utilizzano
  // le resistenze interne di Arduino
  pinMode(PIN_CLK, INPUT_PULLUP);
  pinMode(PIN_DT, INPUT_PULLUP);
  pinMode(PIN_SW, INPUT_PULLUP);

  // Configura il buzzer come uscita
  pinMode(PIN_BUZZER, OUTPUT);
  digitalWrite(PIN_BUZZER, LOW);

  // Memorizza lo stato iniziale del segnale CLK
  statoPrecedenteClk = digitalRead(PIN_CLK);

  // Inizializza il display OLED
  if (!display.begin(
        SSD1306_SWITCHCAPVCC,
        INDIRIZZO_OLED
      )) {
    // Se il display non viene rilevato,
    // il programma rimane bloccato
    while (true) {
    }
  }

  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextWrap(false);

  mostraAvvio();
  mostraInterfaccia();

  aggiornamentoDisplayRichiesto = false;
}

void loop() {
  // Controlla continuamente la rotazione
  gestisciEncoder();

  // Controlla il pulsante integrato
  gestisciPulsante();

  // Genera il segnale del buzzer
  // senza utilizzare delay()
  aggiornaBuzzer();

  // Ridisegna il display soltanto
  // quando cambia il volume o lo stato mute
  if (aggiornamentoDisplayRichiesto) {
    mostraInterfaccia();
    aggiornamentoDisplayRichiesto = false;
  }
}

void gestisciEncoder() {
  // Legge lo stato attuale del segnale CLK
  int statoAttualeClk = digitalRead(PIN_CLK);

  // Rileva il fronte di discesa del segnale
  if (statoPrecedenteClk == HIGH &&
      statoAttualeClk == LOW &&
      millis() - ultimaRotazione >=
      TEMPO_MINIMO_ROTAZIONE) {
    ultimaRotazione = millis();

    // Se il sistema era in mute,
    // la rotazione riattiva automaticamente l'audio
    if (muteAttivo) {
      muteAttivo = false;
      volume = volumePrecedente;
    }

    // Confronta DT con CLK per determinare
    // la direzione della rotazione
    if (digitalRead(PIN_DT) != statoAttualeClk) {
      aumentaVolume();
    } else {
      diminuisciVolume();
    }

    aggiornamentoDisplayRichiesto = true;
  }

  // Salva lo stato per il controllo successivo
  statoPrecedenteClk = statoAttualeClk;
}

void gestisciPulsante() {
  // Con INPUT_PULLUP il pulsante premuto
  // viene letto come livello LOW
  if (digitalRead(PIN_SW) == LOW &&
      millis() - ultimaPressione >=
      TEMPO_DEBOUNCE_PULSANTE) {
    ultimaPressione = millis();

    cambiaMute();
    aggiornamentoDisplayRichiesto = true;
  }
}

void aumentaVolume() {
  // Aumenta il volume del passo impostato
  int nuovoVolume = volume + PASSO_VOLUME;

  // Impedisce di superare il 100%
  volume = constrain(
    nuovoVolume,
    0,
    100
  );

  // Memorizza l'ultimo volume valido
  volumePrecedente = volume;
}

void diminuisciVolume() {
  // Diminuisce il volume del passo impostato
  int nuovoVolume = volume - PASSO_VOLUME;

  // Impedisce di scendere sotto lo 0%
  volume = constrain(
    nuovoVolume,
    0,
    100
  );

  // Memorizza l'ultimo volume valido
  volumePrecedente = volume;
}

void cambiaMute() {
  // Se il mute è già attivo,
  // ripristina il livello precedente
  if (muteAttivo) {
    muteAttivo = false;
    volume = volumePrecedente;
    return;
  }

  // Prima di silenziare il buzzer,
  // conserva l'ultimo volume maggiore di zero
  if (volume > 0) {
    volumePrecedente = volume;
  }

  muteAttivo = true;
}

void aggiornaBuzzer() {
  // Spegne completamente il buzzer
  // quando il mute è attivo o il volume è zero
  if (muteAttivo || volume == 0) {
    digitalWrite(PIN_BUZZER, LOW);
    uscitaBuzzerAlta = false;
    return;
  }

  // Calcola la durata di mezzo periodo
  // necessaria per generare la frequenza impostata
  unsigned long mezzoPeriodo =
    500000UL / FREQUENZA_TONO;

  unsigned long momentoAttuale = micros();

  // Cambia lo stato del segnale
  // quando è trascorso mezzo periodo
  if (momentoAttuale - ultimoCambioSegnale >=
      mezzoPeriodo) {
    ultimoCambioSegnale = momentoAttuale;

    uscitaBuzzerAlta = !uscitaBuzzerAlta;

    // Il volume viene simulato applicando
    // il segnale solo per una parte dei cicli
    if (uscitaBuzzerAlta &&
        faseVolumeAttiva()) {
      digitalWrite(PIN_BUZZER, HIGH);
    } else {
      digitalWrite(PIN_BUZZER, LOW);
    }
  }
}

bool faseVolumeAttiva() {
  // Divide il segnale audio in 20 livelli.
  // Un volume del 50% attiva circa metà dei cicli.
  static byte fase = 0;

  fase++;

  if (fase >= 20) {
    fase = 0;
  }

  byte livelliAttivi = map(
    volume,
    0,
    100,
    0,
    20
  );

  return fase < livelliAttivi;
}

void mostraInterfaccia() {
  // Pulisce completamente il display
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);

  // Titolo della schermata
  display.setCursor(0, 0);
  display.print("CONTROLLO VOLUME");

  display.drawLine(
    0,
    10,
    127,
    10,
    SSD1306_WHITE
  );

  // Mostra il livello oppure lo stato mute
  if (muteAttivo) {
    display.setTextSize(2);
    display.setCursor(38, 18);
    display.print("MUTE");
  } else {
    display.setTextSize(2);
    display.setCursor(42, 18);
    display.print(volume);
    display.print("%");
  }

  // Disegna il bordo della barra grafica
  display.drawRect(
    8,
    39,
    112,
    11,
    SSD1306_WHITE
  );

  // Calcola la larghezza proporzionale al volume
  int larghezzaBarra = map(
    muteAttivo ? 0 : volume,
    0,
    100,
    0,
    108
  );

  // Riempie la barra con il livello corrente
  display.fillRect(
    10,
    41,
    larghezzaBarra,
    7,
    SSD1306_WHITE
  );

  // Mostra le istruzioni principali
  display.setTextSize(1);
  display.setCursor(0, 55);
  display.print("Ruota: volume");

  display.setCursor(78, 55);
  display.print("Premi: mute");

  // Invia al display tutti gli elementi disegnati
  display.display();
}

void mostraAvvio() {
  display.clearDisplay();
  display.setTextSize(1);

  display.setCursor(17, 15);
  display.print("Controllo volume");

  display.setCursor(16, 31);
  display.print("Encoder e buzzer");

  display.setCursor(28, 47);
  display.print("Progetto 134");

  display.display();

  delay(1800);
}

⚙️ Come funziona
​

Il buzzer passivo riproduce un tono con frequenza fissa.

Il volume viene simulato modificando il duty cycle del segnale PWM applicato al buzzer.

Arduino converte il valore percentuale in un livello compreso tra 0 e 255:
int valorePwm = map(volume, 0, 100, 0, 255);

Un valore basso produce un segnale meno intenso.
Un valore alto produce un segnale più marcato.
​
👉 La regolazione effettiva può variare in base al buzzer utilizzato.

🔇 Modalità mute
​

Premendo il pulsante integrato nell’encoder, Arduino attiva la modalità mute.
​
Durante il mute:
  • il buzzer viene spento;
  • il display mostra la scritta MUTE;
  • il valore del volume rimane memorizzato.
​
Premendo nuovamente il pulsante, il suono viene ripristinato allo stesso livello precedente.

📊 Barra grafica del volume
​

Il display OLED mostra:
  • percentuale del volume;
  • barra grafica;
  • stato attivo o mute;
  • indicazioni per la manopola.
La larghezza della barra viene calcolata in proporzione al livello impostato.
Con il volume al 100%, la barra risulta completamente piena.

🧠 Perché è un progetto importante
​

Con questo progetto impari a:
  • utilizzare un encoder rotativo;
  • controllare un parametro percentuale;
  • creare una funzione mute;
  • pilotare un buzzer passivo;
  • generare un segnale audio;
  • utilizzare micros() senza bloccare Arduino;
  • visualizzare una barra grafica;
  • convertire valori con map();
  • limitare i valori tramite constrain();
  • costruire un’interfaccia simile a una manopola del volume.
​
👉 Queste tecniche possono essere riutilizzate in radio, amplificatori, timer sonori e pannelli di controllo.

🔄 Varianti possibili
​

Vuoi migliorare il progetto?
  • 🎵 aggiungi più frequenze selezionabili;
  • 💾 salva il volume nella EEPROM;
  • 🔘 riconosci una pressione lunga;
  • 🔊 collega un piccolo altoparlante;
  • ⚡ utilizza un transistor per pilotare il carico;
  • 🎚️ aggiungi bassi, medi e alti;
  • 📋 crea un menu audio completo;
  • 🌈 aggiungi LED che seguono il volume;
  • 📟 utilizza un display OLED più grande;
  • 🎶 riproduci una melodia;
  • 🔇 aggiungi un’icona grafica per il mute;
  • 📶 controlla il volume tramite Bluetooth.

Foto
Foto

© ProgettiArduino.com 2026 - Fancello Salvatore
​ Layout, immagini e testi sono di esclusiva proprietà di www.progettiarduino.com 
Privacy Policy