🚀 Introduzione
Vuoi creare un vero menu Arduino controllato con una sola manopola? 🎛️📋
In questo progetto utilizzerai un encoder rotativo con pulsante integrato per navigare tra diverse voci visualizzate su un display OLED.
Ruotando l’encoder potrai spostare il cursore. Premendo la manopola entrerai nella voce selezionata e potrai modificare i relativi valori.
👉 È la stessa logica utilizzata in stampanti 3D, termostati, amplificatori, centraline e dispositivi elettronici professionali.
Vuoi creare un vero menu Arduino controllato con una sola manopola? 🎛️📋
In questo progetto utilizzerai un encoder rotativo con pulsante integrato per navigare tra diverse voci visualizzate su un display OLED.
Ruotando l’encoder potrai spostare il cursore. Premendo la manopola entrerai nella voce selezionata e potrai modificare i relativi valori.
👉 È la stessa logica utilizzata in stampanti 3D, termostati, amplificatori, centraline e dispositivi elettronici professionali.
🎯 Cosa realizzerai
Con Arduino creerai un’interfaccia che:
Con Arduino creerai un’interfaccia che:
- 🎛️ utilizza un encoder rotativo;
- ⬆️ scorre le voci del menu;
- ✅ seleziona una funzione premendo la manopola;
- 🌡️ modifica una temperatura impostata;
- 💡 modifica il livello di luminosità;
- 🔔 attiva o disattiva un buzzer;
- ℹ️ mostra una schermata informativa;
- 🔙 permette di tornare al menu principale;
- 📟 visualizza tutto su display OLED;
- ⏱️ gestisce rotazione e pressione senza bloccare Arduino.
🧰 Materiale necessario
- 1x Arduino UNO;
- 1x encoder rotativo KY-040 o compatibile;
- 1x display OLED 0,96 pollici I2C SSD1306;
- 1x buzzer passivo;
- cavetti jumper;
- breadboard;
- cavo USB.
🛒 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
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:
Per la gestione dell’encoder non è richiesta alcuna libreria esterna.
Per utilizzare il display OLED devi installare:
- Adafruit SSD1306;
- Adafruit GFX Library.
Per la gestione dell’encoder non è richiesta alcuna libreria esterna.
🔌 Schema di collegamento
Display OLED SSD1306
Encoder rotativo KY-040
Buzzer passivo
Display OLED SSD1306
- VCC → 5V;
- GND → GND;
- SDA → A4;
- SCL → A5.
Encoder rotativo KY-040
- + → 5V;
- GND → GND;
- CLK → pin digitale 2;
- DT → pin digitale 3;
- SW → pin digitale 4.
Buzzer passivo
- terminale positivo → pin digitale 8;
- terminale negativo → GND.
💻 Codice Arduino
Il menu principale contiene quattro voci:
Premendo la manopola:
Il menu principale contiene quattro voci:
- Temperatura;
- Luminosità;
- Suono;
- Informazioni.
Premendo la manopola:
- si entra nella schermata selezionata;
- si conferma un valore;
- si ritorna al menu principale.
/*
============================================================
Progetto 133 - Navigazione menu con encoder
Menu OLED controllato tramite encoder rotativo KY-040
============================================================
*/
#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 e del buzzer
#define PIN_CLK 2
#define PIN_DT 3
#define PIN_SW 4
#define PIN_BUZZER 8
// Intervalli utilizzati per ridurre
// rimbalzi e letture multiple
const unsigned long TEMPO_DEBOUNCE_PULSANTE = 180;
const unsigned long TEMPO_MINIMO_ROTAZIONE = 3;
// Numero delle voci presenti nel menu
const byte NUMERO_VOCI = 4;
// Oggetto utilizzato per controllare il display OLED
Adafruit_SSD1306 display(
LARGHEZZA_DISPLAY,
ALTEZZA_DISPLAY,
&Wire,
RESET_OLED
);
// Nomi delle voci del menu principale
const char* vociMenu[NUMERO_VOCI] = {
"Temperatura",
"Luminosita",
"Suono",
"Informazioni"
};
// Schermate disponibili nel programma
enum Schermata {
MENU_PRINCIPALE,
MODIFICA_TEMPERATURA,
MODIFICA_LUMINOSITA,
MODIFICA_SUONO,
SCHERMATA_INFO
};
Schermata schermataAttuale = MENU_PRINCIPALE;
// Voce attualmente selezionata nel menu
byte voceSelezionata = 0;
// Parametri modificabili
int temperaturaImpostata = 22;
int luminositaImpostata = 50;
bool suonoAttivo = true;
// Stato precedente del segnale CLK
int statoPrecedenteClk = HIGH;
// Variabili temporali utilizzate
// per encoder e pulsante
unsigned long ultimaRotazione = 0;
unsigned long ultimaPressione = 0;
// Indica quando il display deve essere ridisegnato
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);
noTone(PIN_BUZZER);
// 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();
mostraSchermata();
aggiornamentoDisplayRichiesto = false;
}
void loop() {
// Controlla continuamente la rotazione
gestisciEncoder();
// Controlla il pulsante dell'encoder
gestisciPulsante();
// Ridisegna il display soltanto
// quando qualcosa è cambiato
if (aggiornamentoDisplayRichiesto) {
mostraSchermata();
aggiornamentoDisplayRichiesto = false;
}
}
void gestisciEncoder() {
// Legge lo stato attuale del segnale CLK
int statoAttualeClk = digitalRead(PIN_CLK);
// Rileva soltanto il fronte di discesa
// per contare una volta ogni scatto
if (statoPrecedenteClk == HIGH &&
statoAttualeClk == LOW &&
millis() - ultimaRotazione >=
TEMPO_MINIMO_ROTAZIONE) {
ultimaRotazione = millis();
// Confronta DT con CLK per stabilire
// la direzione della rotazione
if (digitalRead(PIN_DT) != statoAttualeClk) {
ruotaDestra();
} else {
ruotaSinistra();
}
aggiornamentoDisplayRichiesto = true;
}
// Salva lo stato per il ciclo 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();
// Emette un breve feedback acustico
emettiClick();
// Esegue l'azione associata
// alla schermata attualmente visibile
confermaSelezione();
aggiornamentoDisplayRichiesto = true;
}
}
void ruotaDestra() {
// Nel menu principale sposta
// il cursore alla voce successiva
if (schermataAttuale == MENU_PRINCIPALE) {
voceSelezionata++;
if (voceSelezionata >= NUMERO_VOCI) {
voceSelezionata = 0;
}
return;
}
// Nella schermata temperatura
// aumenta il valore di un grado
if (schermataAttuale ==
MODIFICA_TEMPERATURA) {
temperaturaImpostata++;
temperaturaImpostata = constrain(
temperaturaImpostata,
10,
35
);
return;
}
// Nella schermata luminosità
// aumenta il valore di cinque punti
if (schermataAttuale ==
MODIFICA_LUMINOSITA) {
luminositaImpostata += 5;
luminositaImpostata = constrain(
luminositaImpostata,
0,
100
);
return;
}
// Nella schermata suono
// attiva il feedback acustico
if (schermataAttuale == MODIFICA_SUONO) {
suonoAttivo = true;
}
}
void ruotaSinistra() {
// Nel menu principale sposta
// il cursore alla voce precedente
if (schermataAttuale == MENU_PRINCIPALE) {
if (voceSelezionata == 0) {
voceSelezionata = NUMERO_VOCI - 1;
} else {
voceSelezionata--;
}
return;
}
// Diminuisce la temperatura impostata
if (schermataAttuale ==
MODIFICA_TEMPERATURA) {
temperaturaImpostata--;
temperaturaImpostata = constrain(
temperaturaImpostata,
10,
35
);
return;
}
// Diminuisce la luminosità impostata
if (schermataAttuale ==
MODIFICA_LUMINOSITA) {
luminositaImpostata -= 5;
luminositaImpostata = constrain(
luminositaImpostata,
0,
100
);
return;
}
// Nella schermata suono
// disattiva il feedback acustico
if (schermataAttuale == MODIFICA_SUONO) {
suonoAttivo = false;
}
}
void confermaSelezione() {
// Dal menu principale entra
// nella voce selezionata
if (schermataAttuale == MENU_PRINCIPALE) {
switch (voceSelezionata) {
case 0:
schermataAttuale =
MODIFICA_TEMPERATURA;
break;
case 1:
schermataAttuale =
MODIFICA_LUMINOSITA;
break;
case 2:
schermataAttuale =
MODIFICA_SUONO;
break;
case 3:
schermataAttuale =
SCHERMATA_INFO;
break;
}
return;
}
// Da qualsiasi schermata secondaria,
// una nuova pressione torna al menu principale
schermataAttuale = MENU_PRINCIPALE;
}
void mostraSchermata() {
// Pulisce completamente il display
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
switch (schermataAttuale) {
case MENU_PRINCIPALE:
mostraMenu();
break;
case MODIFICA_TEMPERATURA:
mostraTemperatura();
break;
case MODIFICA_LUMINOSITA:
mostraLuminosita();
break;
case MODIFICA_SUONO:
mostraSuono();
break;
case SCHERMATA_INFO:
mostraInformazioni();
break;
}
// Invia al display tutti gli elementi disegnati
display.display();
}
void mostraMenu() {
display.setTextSize(1);
// Titolo del menu
display.setCursor(0, 0);
display.print("MENU PRINCIPALE");
display.drawLine(
0,
10,
127,
10,
SSD1306_WHITE
);
// Calcola la prima voce da mostrare.
// Il display visualizza tre voci alla volta.
int primaVoce;
if (voceSelezionata <= 1) {
primaVoce = 0;
} else if (voceSelezionata >=
NUMERO_VOCI - 1) {
primaVoce = NUMERO_VOCI - 3;
} else {
primaVoce = voceSelezionata - 1;
}
// Disegna le tre voci visibili
for (byte riga = 0; riga < 3; riga++) {
byte indiceVoce = primaVoce + riga;
int coordinataY = 16 + riga * 15;
// Evidenzia la voce selezionata
if (indiceVoce == voceSelezionata) {
display.fillRect(
0,
coordinataY - 2,
128,
12,
SSD1306_WHITE
);
display.setTextColor(SSD1306_BLACK);
} else {
display.setTextColor(SSD1306_WHITE);
}
display.setCursor(4, coordinataY);
display.print(vociMenu[indiceVoce]);
}
// Ripristina il colore normale
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 61);
display.print("Ruota e premi");
}
void mostraTemperatura() {
display.setTextSize(1);
display.setCursor(0, 0);
display.print("IMPOSTA TEMPERATURA");
display.drawLine(
0,
10,
127,
10,
SSD1306_WHITE
);
// Mostra il valore con caratteri grandi
display.setTextSize(3);
display.setCursor(25, 20);
display.print(temperaturaImpostata);
display.print((char)247);
display.print("C");
display.setTextSize(1);
display.setCursor(13, 53);
display.print("Ruota per modificare");
display.setCursor(18, 62);
display.print("Premi per salvare");
}
void mostraLuminosita() {
display.setTextSize(1);
display.setCursor(0, 0);
display.print("IMPOSTA LUMINOSITA");
display.drawLine(
0,
10,
127,
10,
SSD1306_WHITE
);
display.setTextSize(2);
display.setCursor(44, 17);
display.print(luminositaImpostata);
display.print("%");
// Disegna la barra del valore impostato
display.drawRect(
8,
39,
112,
10,
SSD1306_WHITE
);
int larghezzaBarra = map(
luminositaImpostata,
0,
100,
0,
108
);
display.fillRect(
10,
41,
larghezzaBarra,
6,
SSD1306_WHITE
);
display.setTextSize(1);
display.setCursor(18, 56);
display.print("Premi per salvare");
}
void mostraSuono() {
display.setTextSize(1);
display.setCursor(0, 0);
display.print("FEEDBACK ACUSTICO");
display.drawLine(
0,
10,
127,
10,
SSD1306_WHITE
);
display.setTextSize(2);
display.setCursor(30, 23);
if (suonoAttivo) {
display.print("ATTIVO");
} else {
display.print("SPENTO");
}
display.setTextSize(1);
display.setCursor(9, 49);
display.print("Ruota per cambiare");
display.setCursor(18, 60);
display.print("Premi per salvare");
}
void mostraInformazioni() {
display.setTextSize(1);
display.setCursor(0, 0);
display.print("INFORMAZIONI");
display.drawLine(
0,
10,
127,
10,
SSD1306_WHITE
);
display.setCursor(0, 18);
display.print("Progetto: 133");
display.setCursor(0, 31);
display.print("Display: SSD1306");
display.setCursor(0, 44);
display.print("Comando: KY-040");
display.setCursor(12, 58);
display.print("Premi per tornare");
}
void emettiClick() {
// Non produce alcun suono
// se il feedback è disattivato
if (!suonoAttivo) {
return;
}
// Emette un breve tono senza utilizzare delay()
tone(
PIN_BUZZER,
1800,
40
);
}
void mostraAvvio() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(22, 14);
display.print("Menu con encoder");
display.setCursor(24, 30);
display.print("Navigazione OLED");
display.setCursor(28, 47);
display.print("Progetto 133");
display.display();
delay(1800);
}
============================================================
Progetto 133 - Navigazione menu con encoder
Menu OLED controllato tramite encoder rotativo KY-040
============================================================
*/
#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 e del buzzer
#define PIN_CLK 2
#define PIN_DT 3
#define PIN_SW 4
#define PIN_BUZZER 8
// Intervalli utilizzati per ridurre
// rimbalzi e letture multiple
const unsigned long TEMPO_DEBOUNCE_PULSANTE = 180;
const unsigned long TEMPO_MINIMO_ROTAZIONE = 3;
// Numero delle voci presenti nel menu
const byte NUMERO_VOCI = 4;
// Oggetto utilizzato per controllare il display OLED
Adafruit_SSD1306 display(
LARGHEZZA_DISPLAY,
ALTEZZA_DISPLAY,
&Wire,
RESET_OLED
);
// Nomi delle voci del menu principale
const char* vociMenu[NUMERO_VOCI] = {
"Temperatura",
"Luminosita",
"Suono",
"Informazioni"
};
// Schermate disponibili nel programma
enum Schermata {
MENU_PRINCIPALE,
MODIFICA_TEMPERATURA,
MODIFICA_LUMINOSITA,
MODIFICA_SUONO,
SCHERMATA_INFO
};
Schermata schermataAttuale = MENU_PRINCIPALE;
// Voce attualmente selezionata nel menu
byte voceSelezionata = 0;
// Parametri modificabili
int temperaturaImpostata = 22;
int luminositaImpostata = 50;
bool suonoAttivo = true;
// Stato precedente del segnale CLK
int statoPrecedenteClk = HIGH;
// Variabili temporali utilizzate
// per encoder e pulsante
unsigned long ultimaRotazione = 0;
unsigned long ultimaPressione = 0;
// Indica quando il display deve essere ridisegnato
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);
noTone(PIN_BUZZER);
// 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();
mostraSchermata();
aggiornamentoDisplayRichiesto = false;
}
void loop() {
// Controlla continuamente la rotazione
gestisciEncoder();
// Controlla il pulsante dell'encoder
gestisciPulsante();
// Ridisegna il display soltanto
// quando qualcosa è cambiato
if (aggiornamentoDisplayRichiesto) {
mostraSchermata();
aggiornamentoDisplayRichiesto = false;
}
}
void gestisciEncoder() {
// Legge lo stato attuale del segnale CLK
int statoAttualeClk = digitalRead(PIN_CLK);
// Rileva soltanto il fronte di discesa
// per contare una volta ogni scatto
if (statoPrecedenteClk == HIGH &&
statoAttualeClk == LOW &&
millis() - ultimaRotazione >=
TEMPO_MINIMO_ROTAZIONE) {
ultimaRotazione = millis();
// Confronta DT con CLK per stabilire
// la direzione della rotazione
if (digitalRead(PIN_DT) != statoAttualeClk) {
ruotaDestra();
} else {
ruotaSinistra();
}
aggiornamentoDisplayRichiesto = true;
}
// Salva lo stato per il ciclo 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();
// Emette un breve feedback acustico
emettiClick();
// Esegue l'azione associata
// alla schermata attualmente visibile
confermaSelezione();
aggiornamentoDisplayRichiesto = true;
}
}
void ruotaDestra() {
// Nel menu principale sposta
// il cursore alla voce successiva
if (schermataAttuale == MENU_PRINCIPALE) {
voceSelezionata++;
if (voceSelezionata >= NUMERO_VOCI) {
voceSelezionata = 0;
}
return;
}
// Nella schermata temperatura
// aumenta il valore di un grado
if (schermataAttuale ==
MODIFICA_TEMPERATURA) {
temperaturaImpostata++;
temperaturaImpostata = constrain(
temperaturaImpostata,
10,
35
);
return;
}
// Nella schermata luminosità
// aumenta il valore di cinque punti
if (schermataAttuale ==
MODIFICA_LUMINOSITA) {
luminositaImpostata += 5;
luminositaImpostata = constrain(
luminositaImpostata,
0,
100
);
return;
}
// Nella schermata suono
// attiva il feedback acustico
if (schermataAttuale == MODIFICA_SUONO) {
suonoAttivo = true;
}
}
void ruotaSinistra() {
// Nel menu principale sposta
// il cursore alla voce precedente
if (schermataAttuale == MENU_PRINCIPALE) {
if (voceSelezionata == 0) {
voceSelezionata = NUMERO_VOCI - 1;
} else {
voceSelezionata--;
}
return;
}
// Diminuisce la temperatura impostata
if (schermataAttuale ==
MODIFICA_TEMPERATURA) {
temperaturaImpostata--;
temperaturaImpostata = constrain(
temperaturaImpostata,
10,
35
);
return;
}
// Diminuisce la luminosità impostata
if (schermataAttuale ==
MODIFICA_LUMINOSITA) {
luminositaImpostata -= 5;
luminositaImpostata = constrain(
luminositaImpostata,
0,
100
);
return;
}
// Nella schermata suono
// disattiva il feedback acustico
if (schermataAttuale == MODIFICA_SUONO) {
suonoAttivo = false;
}
}
void confermaSelezione() {
// Dal menu principale entra
// nella voce selezionata
if (schermataAttuale == MENU_PRINCIPALE) {
switch (voceSelezionata) {
case 0:
schermataAttuale =
MODIFICA_TEMPERATURA;
break;
case 1:
schermataAttuale =
MODIFICA_LUMINOSITA;
break;
case 2:
schermataAttuale =
MODIFICA_SUONO;
break;
case 3:
schermataAttuale =
SCHERMATA_INFO;
break;
}
return;
}
// Da qualsiasi schermata secondaria,
// una nuova pressione torna al menu principale
schermataAttuale = MENU_PRINCIPALE;
}
void mostraSchermata() {
// Pulisce completamente il display
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
switch (schermataAttuale) {
case MENU_PRINCIPALE:
mostraMenu();
break;
case MODIFICA_TEMPERATURA:
mostraTemperatura();
break;
case MODIFICA_LUMINOSITA:
mostraLuminosita();
break;
case MODIFICA_SUONO:
mostraSuono();
break;
case SCHERMATA_INFO:
mostraInformazioni();
break;
}
// Invia al display tutti gli elementi disegnati
display.display();
}
void mostraMenu() {
display.setTextSize(1);
// Titolo del menu
display.setCursor(0, 0);
display.print("MENU PRINCIPALE");
display.drawLine(
0,
10,
127,
10,
SSD1306_WHITE
);
// Calcola la prima voce da mostrare.
// Il display visualizza tre voci alla volta.
int primaVoce;
if (voceSelezionata <= 1) {
primaVoce = 0;
} else if (voceSelezionata >=
NUMERO_VOCI - 1) {
primaVoce = NUMERO_VOCI - 3;
} else {
primaVoce = voceSelezionata - 1;
}
// Disegna le tre voci visibili
for (byte riga = 0; riga < 3; riga++) {
byte indiceVoce = primaVoce + riga;
int coordinataY = 16 + riga * 15;
// Evidenzia la voce selezionata
if (indiceVoce == voceSelezionata) {
display.fillRect(
0,
coordinataY - 2,
128,
12,
SSD1306_WHITE
);
display.setTextColor(SSD1306_BLACK);
} else {
display.setTextColor(SSD1306_WHITE);
}
display.setCursor(4, coordinataY);
display.print(vociMenu[indiceVoce]);
}
// Ripristina il colore normale
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 61);
display.print("Ruota e premi");
}
void mostraTemperatura() {
display.setTextSize(1);
display.setCursor(0, 0);
display.print("IMPOSTA TEMPERATURA");
display.drawLine(
0,
10,
127,
10,
SSD1306_WHITE
);
// Mostra il valore con caratteri grandi
display.setTextSize(3);
display.setCursor(25, 20);
display.print(temperaturaImpostata);
display.print((char)247);
display.print("C");
display.setTextSize(1);
display.setCursor(13, 53);
display.print("Ruota per modificare");
display.setCursor(18, 62);
display.print("Premi per salvare");
}
void mostraLuminosita() {
display.setTextSize(1);
display.setCursor(0, 0);
display.print("IMPOSTA LUMINOSITA");
display.drawLine(
0,
10,
127,
10,
SSD1306_WHITE
);
display.setTextSize(2);
display.setCursor(44, 17);
display.print(luminositaImpostata);
display.print("%");
// Disegna la barra del valore impostato
display.drawRect(
8,
39,
112,
10,
SSD1306_WHITE
);
int larghezzaBarra = map(
luminositaImpostata,
0,
100,
0,
108
);
display.fillRect(
10,
41,
larghezzaBarra,
6,
SSD1306_WHITE
);
display.setTextSize(1);
display.setCursor(18, 56);
display.print("Premi per salvare");
}
void mostraSuono() {
display.setTextSize(1);
display.setCursor(0, 0);
display.print("FEEDBACK ACUSTICO");
display.drawLine(
0,
10,
127,
10,
SSD1306_WHITE
);
display.setTextSize(2);
display.setCursor(30, 23);
if (suonoAttivo) {
display.print("ATTIVO");
} else {
display.print("SPENTO");
}
display.setTextSize(1);
display.setCursor(9, 49);
display.print("Ruota per cambiare");
display.setCursor(18, 60);
display.print("Premi per salvare");
}
void mostraInformazioni() {
display.setTextSize(1);
display.setCursor(0, 0);
display.print("INFORMAZIONI");
display.drawLine(
0,
10,
127,
10,
SSD1306_WHITE
);
display.setCursor(0, 18);
display.print("Progetto: 133");
display.setCursor(0, 31);
display.print("Display: SSD1306");
display.setCursor(0, 44);
display.print("Comando: KY-040");
display.setCursor(12, 58);
display.print("Premi per tornare");
}
void emettiClick() {
// Non produce alcun suono
// se il feedback è disattivato
if (!suonoAttivo) {
return;
}
// Emette un breve tono senza utilizzare delay()
tone(
PIN_BUZZER,
1800,
40
);
}
void mostraAvvio() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(22, 14);
display.print("Menu con encoder");
display.setCursor(24, 30);
display.print("Navigazione OLED");
display.setCursor(28, 47);
display.print("Progetto 133");
display.display();
delay(1800);
}
⚙️ Come funziona
Il programma utilizza due modalità principali:
Quando entri in una schermata di modifica, la rotazione agisce invece sul valore.
Per esempio:
👉 La funzione della manopola dipende quindi dalla schermata attiva.
Il programma utilizza due modalità principali:
- navigazione nel menu;
- modifica di una voce.
Quando entri in una schermata di modifica, la rotazione agisce invece sul valore.
Per esempio:
- nella voce Temperatura modifica i gradi;
- nella voce Luminosità modifica la percentuale;
- nella voce Suono attiva o disattiva il buzzer.
👉 La funzione della manopola dipende quindi dalla schermata attiva.
📋 Menu principale
Il display OLED mostra tre voci contemporaneamente.
La voce selezionata viene evidenziata con:
Quando il cursore supera l’ultima voce, torna automaticamente alla prima.
Ruotando nella direzione opposta dalla prima voce, si passa invece all’ultima.
Questa tecnica viene chiamata navigazione circolare.
Il display OLED mostra tre voci contemporaneamente.
La voce selezionata viene evidenziata con:
- un rettangolo bianco;
- testo nero su sfondo bianco.
Quando il cursore supera l’ultima voce, torna automaticamente alla prima.
Ruotando nella direzione opposta dalla prima voce, si passa invece all’ultima.
Questa tecnica viene chiamata navigazione circolare.
🌡️ Modifica della temperatura
La temperatura può essere regolata tra:
Premendo la manopola, il nuovo valore viene confermato e Arduino torna al menu principale.
La temperatura può essere regolata tra:
- minimo: 10 °C;
- massimo: 35 °C.
Premendo la manopola, il nuovo valore viene confermato e Arduino torna al menu principale.
💡 Modifica della luminosità
La luminosità può essere regolata tra 0% e 100%.
Ogni scatto dell’encoder modifica il valore di 5 punti percentuali.
Il display mostra anche una barra grafica proporzionale al valore impostato.
La luminosità può essere regolata tra 0% e 100%.
Ogni scatto dell’encoder modifica il valore di 5 punti percentuali.
Il display mostra anche una barra grafica proporzionale al valore impostato.
🔔 Attivazione del suono
La voce Suono permette di attivare o disattivare il feedback acustico.
Quando il suono è attivo, il buzzer emette un breve tono:
La voce Suono permette di attivare o disattivare il feedback acustico.
Quando il suono è attivo, il buzzer emette un breve tono:
- quando viene premuto l’encoder;
- quando viene confermata una voce.
🧭 Gestione delle schermate
Il programma utilizza un’enumerazione per identificare la schermata attiva:
enum Schermata {
MENU_PRINCIPALE,
MODIFICA_TEMPERATURA,
MODIFICA_LUMINOSITA,
MODIFICA_SUONO,
SCHERMATA_INFO
};
Questa organizzazione rende il codice più leggibile e permette di aggiungere facilmente nuove funzioni.
Il programma utilizza un’enumerazione per identificare la schermata attiva:
enum Schermata {
MENU_PRINCIPALE,
MODIFICA_TEMPERATURA,
MODIFICA_LUMINOSITA,
MODIFICA_SUONO,
SCHERMATA_INFO
};
Questa organizzazione rende il codice più leggibile e permette di aggiungere facilmente nuove funzioni.
🎛️ Lettura dell’encoder
L’encoder produce due segnali digitali:
In questo modo stabilisce se la manopola è stata ruotata:
L’encoder produce due segnali digitali:
- CLK;
- DT.
In questo modo stabilisce se la manopola è stata ruotata:
- verso destra;
- verso sinistra.
🧠 Perché è un progetto importante
Con questo progetto impari a:
👉 Questa struttura può diventare la base di termostati, timer, controlli motore e centraline domotiche.
Con questo progetto impari a:
- creare un menu navigabile;
- utilizzare un encoder rotativo;
- gestire più schermate;
- cambiare il comportamento dei comandi;
- evidenziare graficamente una selezione;
- modificare parametri numerici;
- attivare impostazioni booleane;
- utilizzare un buzzer come feedback;
- organizzare il codice tramite enumerazioni;
- costruire un’interfaccia riutilizzabile.
👉 Questa struttura può diventare la base di termostati, timer, controlli motore e centraline domotiche.
🔄 Varianti possibili
Vuoi migliorare il progetto?
Vuoi migliorare il progetto?
- 💾 salva le impostazioni nella EEPROM;
- 🌡️ collega un sensore reale di temperatura;
- 💡 controlla un LED tramite PWM;
- ⚡ aggiungi il controllo di un relè;
- 📋 crea sottomenu con più livelli;
- ⏰ aggiungi un modulo RTC DS3231;
- 🔒 inserisci una schermata di blocco;
- 🎵 aggiungi suoni differenti;
- 📊 mostra grafici e barre;
- 🔘 riconosci una pressione lunga;
- 📟 utilizza un display OLED più grande;
- 🏠 trasforma il menu in una centralina domotica.