🚀 Introduzione
Vuoi controllare un progetto Arduino con una manopola, proprio come nei dispositivi elettronici professionali? 🎛️
In questo progetto utilizzerai un encoder rotativo con pulsante integrato per modificare un valore visualizzato su display OLED.
Ruotando la manopola potrai aumentare o diminuire il valore selezionato. Premendo l’encoder potrai invece cambiare parametro.
👉 L’encoder rotativo è ideale per menu, regolazioni, timer, termostati, controlli di velocità e pannelli di configurazione.
Vuoi controllare un progetto Arduino con una manopola, proprio come nei dispositivi elettronici professionali? 🎛️
In questo progetto utilizzerai un encoder rotativo con pulsante integrato per modificare un valore visualizzato su display OLED.
Ruotando la manopola potrai aumentare o diminuire il valore selezionato. Premendo l’encoder potrai invece cambiare parametro.
👉 L’encoder rotativo è ideale per menu, regolazioni, timer, termostati, controlli di velocità e pannelli di configurazione.
🎯 Cosa realizzerai
Con Arduino creerai un’interfaccia che:
Con Arduino creerai un’interfaccia che:
- 🎛️ rileva la rotazione dell’encoder;
- ➕ aumenta il valore ruotando verso destra;
- ➖ diminuisce il valore ruotando verso sinistra;
- ✅ rileva la pressione della manopola;
- 🌡️ permette di modificare una temperatura impostata;
- 💡 permette di modificare una luminosità;
- 📟 mostra i valori su display OLED;
- 🔄 cambia il parametro selezionato;
- ⏱️ utilizza un controllo antirimbalzo;
- 🚫 impedisce ai valori di superare i limiti stabiliti.
🧰 Materiale necessario
Il modulo KY-040 integra normalmente le resistenze necessarie per i segnali dell’encoder.
- 1x Arduino UNO;
- 1x encoder rotativo KY-040 o compatibile;
- 1x display OLED 0,96 pollici I2C SSD1306;
- cavetti jumper;
- breadboard;
- cavo USB.
Il modulo KY-040 integra normalmente le resistenze necessarie per i segnali dell’encoder.
🛒 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 lettura dell’encoder non è necessaria alcuna libreria esterna.
Per utilizzare il display OLED devi installare:
- Adafruit SSD1306;
- Adafruit GFX Library.
Per la lettura dell’encoder non è necessaria alcuna libreria esterna.
🔌 Schema di collegamento
Display OLED SSD1306
Encoder rotativo KY-040
Il pin SW corrisponde al pulsante integrato nella manopola.
Nel codice viene utilizzata la modalità INPUT_PULLUP, quindi il pulsante premuto viene letto come LOW.
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.
Il pin SW corrisponde al pulsante integrato nella manopola.
Nel codice viene utilizzata la modalità INPUT_PULLUP, quindi il pulsante premuto viene letto come LOW.
💻 Codice Arduino
Il programma gestisce due parametri:
Il programma gestisce due parametri:
- temperatura impostata;
- luminosità impostata.
- il valore aumenta verso destra;
- il valore diminuisce verso sinistra.
/*
============================================================
Progetto 132 - Interfaccia con encoder rotativo
Modifica temperatura e luminosita tramite encoder 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 rotativo
#define PIN_CLK 2
#define PIN_DT 3
#define PIN_SW 4
// Intervalli 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
);
// Parametri regolabili
int temperaturaImpostata = 22;
int luminositaImpostata = 50;
// Indica quale parametro è selezionato
enum ParametroSelezionato {
PARAMETRO_TEMPERATURA,
PARAMETRO_LUMINOSITA
};
ParametroSelezionato parametroAttuale =
PARAMETRO_TEMPERATURA;
// Memorizza lo stato precedente del segnale CLK
int statoPrecedenteClk = HIGH;
// Variabili temporali 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 segnali dell'encoder utilizzano
// le resistenze interne di Arduino
pinMode(PIN_CLK, INPUT_PULLUP);
pinMode(PIN_DT, INPUT_PULLUP);
pinMode(PIN_SW, INPUT_PULLUP);
// 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();
// Ridisegna il display soltanto
// quando cambia un valore o una selezione
if (aggiornamentoDisplayRichiesto) {
mostraInterfaccia();
aggiornamentoDisplayRichiesto = false;
}
}
void gestisciEncoder() {
// Legge lo stato attuale del segnale CLK
int statoAttualeClk = digitalRead(PIN_CLK);
// Rileva soltanto il fronte di discesa,
// evitando di contare due volte 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) {
aumentaValore();
} else {
diminuisciValore();
}
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();
// Passa da un parametro all'altro
if (parametroAttuale ==
PARAMETRO_TEMPERATURA) {
parametroAttuale =
PARAMETRO_LUMINOSITA;
} else {
parametroAttuale =
PARAMETRO_TEMPERATURA;
}
aggiornamentoDisplayRichiesto = true;
}
}
void aumentaValore() {
// Modifica il parametro attualmente selezionato
if (parametroAttuale ==
PARAMETRO_TEMPERATURA) {
temperaturaImpostata++;
// Limita la temperatura al valore massimo
temperaturaImpostata = constrain(
temperaturaImpostata,
10,
35
);
} else {
luminositaImpostata += 5;
// Limita la luminosità al 100%
luminositaImpostata = constrain(
luminositaImpostata,
0,
100
);
}
}
void diminuisciValore() {
// Modifica il parametro attualmente selezionato
if (parametroAttuale ==
PARAMETRO_TEMPERATURA) {
temperaturaImpostata--;
// Limita la temperatura al valore minimo
temperaturaImpostata = constrain(
temperaturaImpostata,
10,
35
);
} else {
luminositaImpostata -= 5;
// Impedisce valori inferiori a zero
luminositaImpostata = constrain(
luminositaImpostata,
0,
100
);
}
}
void mostraInterfaccia() {
// Pulisce completamente il display
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
// Titolo dell'interfaccia
display.setCursor(0, 0);
display.print("ENCODER ROTATIVO");
display.drawLine(
0,
10,
127,
10,
SSD1306_WHITE
);
// Mostra la voce temperatura
display.setCursor(0, 18);
if (parametroAttuale ==
PARAMETRO_TEMPERATURA) {
display.print("> ");
} else {
display.print(" ");
}
display.print("Temperatura");
display.setCursor(91, 18);
display.print(temperaturaImpostata);
display.print((char)247);
display.print("C");
// Mostra la voce luminosità
display.setCursor(0, 34);
if (parametroAttuale ==
PARAMETRO_LUMINOSITA) {
display.print("> ");
} else {
display.print(" ");
}
display.print("Luminosita");
display.setCursor(97, 34);
display.print(luminositaImpostata);
display.print("%");
// Disegna una barra grafica
// relativa al valore di luminosità
display.drawRect(
3,
48,
100,
9,
SSD1306_WHITE
);
int larghezzaBarra = map(
luminositaImpostata,
0,
100,
0,
96
);
display.fillRect(
5,
50,
larghezzaBarra,
5,
SSD1306_WHITE
);
// Indicazioni per l'utente
display.setCursor(106, 48);
display.print("RUOTA");
display.setCursor(106, 57);
display.print("PREMI");
// Invia al display tutti gli elementi disegnati
display.display();
}
void mostraAvvio() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(15, 15);
display.print("Encoder rotativo");
display.setCursor(20, 31);
display.print("Interfaccia OLED");
display.setCursor(28, 47);
display.print("Progetto 132");
display.display();
delay(1800);
}
============================================================
Progetto 132 - Interfaccia con encoder rotativo
Modifica temperatura e luminosita tramite encoder 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 rotativo
#define PIN_CLK 2
#define PIN_DT 3
#define PIN_SW 4
// Intervalli 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
);
// Parametri regolabili
int temperaturaImpostata = 22;
int luminositaImpostata = 50;
// Indica quale parametro è selezionato
enum ParametroSelezionato {
PARAMETRO_TEMPERATURA,
PARAMETRO_LUMINOSITA
};
ParametroSelezionato parametroAttuale =
PARAMETRO_TEMPERATURA;
// Memorizza lo stato precedente del segnale CLK
int statoPrecedenteClk = HIGH;
// Variabili temporali 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 segnali dell'encoder utilizzano
// le resistenze interne di Arduino
pinMode(PIN_CLK, INPUT_PULLUP);
pinMode(PIN_DT, INPUT_PULLUP);
pinMode(PIN_SW, INPUT_PULLUP);
// 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();
// Ridisegna il display soltanto
// quando cambia un valore o una selezione
if (aggiornamentoDisplayRichiesto) {
mostraInterfaccia();
aggiornamentoDisplayRichiesto = false;
}
}
void gestisciEncoder() {
// Legge lo stato attuale del segnale CLK
int statoAttualeClk = digitalRead(PIN_CLK);
// Rileva soltanto il fronte di discesa,
// evitando di contare due volte 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) {
aumentaValore();
} else {
diminuisciValore();
}
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();
// Passa da un parametro all'altro
if (parametroAttuale ==
PARAMETRO_TEMPERATURA) {
parametroAttuale =
PARAMETRO_LUMINOSITA;
} else {
parametroAttuale =
PARAMETRO_TEMPERATURA;
}
aggiornamentoDisplayRichiesto = true;
}
}
void aumentaValore() {
// Modifica il parametro attualmente selezionato
if (parametroAttuale ==
PARAMETRO_TEMPERATURA) {
temperaturaImpostata++;
// Limita la temperatura al valore massimo
temperaturaImpostata = constrain(
temperaturaImpostata,
10,
35
);
} else {
luminositaImpostata += 5;
// Limita la luminosità al 100%
luminositaImpostata = constrain(
luminositaImpostata,
0,
100
);
}
}
void diminuisciValore() {
// Modifica il parametro attualmente selezionato
if (parametroAttuale ==
PARAMETRO_TEMPERATURA) {
temperaturaImpostata--;
// Limita la temperatura al valore minimo
temperaturaImpostata = constrain(
temperaturaImpostata,
10,
35
);
} else {
luminositaImpostata -= 5;
// Impedisce valori inferiori a zero
luminositaImpostata = constrain(
luminositaImpostata,
0,
100
);
}
}
void mostraInterfaccia() {
// Pulisce completamente il display
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
// Titolo dell'interfaccia
display.setCursor(0, 0);
display.print("ENCODER ROTATIVO");
display.drawLine(
0,
10,
127,
10,
SSD1306_WHITE
);
// Mostra la voce temperatura
display.setCursor(0, 18);
if (parametroAttuale ==
PARAMETRO_TEMPERATURA) {
display.print("> ");
} else {
display.print(" ");
}
display.print("Temperatura");
display.setCursor(91, 18);
display.print(temperaturaImpostata);
display.print((char)247);
display.print("C");
// Mostra la voce luminosità
display.setCursor(0, 34);
if (parametroAttuale ==
PARAMETRO_LUMINOSITA) {
display.print("> ");
} else {
display.print(" ");
}
display.print("Luminosita");
display.setCursor(97, 34);
display.print(luminositaImpostata);
display.print("%");
// Disegna una barra grafica
// relativa al valore di luminosità
display.drawRect(
3,
48,
100,
9,
SSD1306_WHITE
);
int larghezzaBarra = map(
luminositaImpostata,
0,
100,
0,
96
);
display.fillRect(
5,
50,
larghezzaBarra,
5,
SSD1306_WHITE
);
// Indicazioni per l'utente
display.setCursor(106, 48);
display.print("RUOTA");
display.setCursor(106, 57);
display.print("PREMI");
// Invia al display tutti gli elementi disegnati
display.display();
}
void mostraAvvio() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(15, 15);
display.print("Encoder rotativo");
display.setCursor(20, 31);
display.print("Interfaccia OLED");
display.setCursor(28, 47);
display.print("Progetto 132");
display.display();
delay(1800);
}
⚙️ Come funziona
Un encoder rotativo genera due segnali digitali chiamati normalmente:
Durante la rotazione, i due segnali cambiano stato con un piccolo sfasamento.
Arduino confronta i segnali per capire la direzione della rotazione.
Se il segnale DT è diverso da CLK, la rotazione viene interpretata in una direzione.
Se i due segnali sono uguali, viene interpretata nella direzione opposta.
Un encoder rotativo genera due segnali digitali chiamati normalmente:
- CLK;
- DT.
Durante la rotazione, i due segnali cambiano stato con un piccolo sfasamento.
Arduino confronta i segnali per capire la direzione della rotazione.
Se il segnale DT è diverso da CLK, la rotazione viene interpretata in una direzione.
Se i due segnali sono uguali, viene interpretata nella direzione opposta.
🎛️ Differenza tra encoder e potenziometro
Un potenziometro possiede una posizione minima e una posizione massima.
Un encoder rotativo può invece ruotare continuamente in entrambe le direzioni.
Questo permette di:
👉 Il valore minimo e massimo vengono stabiliti nel programma, non dalla posizione fisica della manopola.
Un potenziometro possiede una posizione minima e una posizione massima.
Un encoder rotativo può invece ruotare continuamente in entrambe le direzioni.
Questo permette di:
- modificare valori senza limiti meccanici;
- navigare in menu molto lunghi;
- controllare più parametri;
- creare interfacce più compatte.
👉 Il valore minimo e massimo vengono stabiliti nel programma, non dalla posizione fisica della manopola.
🌡️ Regolazione della temperatura
La temperatura impostata può variare tra:
La funzione constrain() impedisce di superare questi limiti.
La temperatura impostata può variare tra:
- minimo: 10 °C;
- massimo: 35 °C.
La funzione constrain() impedisce di superare questi limiti.
💡 Regolazione della luminosità
La luminosità può variare da 0% a 100%.
Ogni scatto modifica il valore di 5 punti percentuali.
Questo parametro potrebbe essere successivamente utilizzato per controllare un LED tramite PWM.
La luminosità può variare da 0% a 100%.
Ogni scatto modifica il valore di 5 punti percentuali.
Questo parametro potrebbe essere successivamente utilizzato per controllare un LED tramite PWM.
✅ Pulsante integrato
Premendo l’encoder, Arduino cambia il parametro selezionato.
Il display evidenzia la voce attiva attraverso il simbolo >.
Per esempio:
> Temperatura
oppure:
> Luminosita
Il pulsante viene gestito con un controllo antirimbalzo basato su millis().
Premendo l’encoder, Arduino cambia il parametro selezionato.
Il display evidenzia la voce attiva attraverso il simbolo >.
Per esempio:
> Temperatura
oppure:
> Luminosita
Il pulsante viene gestito con un controllo antirimbalzo basato su millis().
📟 Interfaccia OLED
Il display mostra:
La schermata viene aggiornata soltanto quando cambia un valore o viene premuto il pulsante.
Il display mostra:
- titolo del progetto;
- temperatura impostata;
- luminosità impostata;
- parametro attualmente selezionato;
- indicazione della pressione dell’encoder.
La schermata viene aggiornata soltanto quando cambia un valore o viene premuto il pulsante.
⚠️ Direzione invertita
Alcuni encoder possono aumentare il valore quando vengono ruotati verso sinistra.
In questo caso puoi:
Alcuni encoder possono aumentare il valore quando vengono ruotati verso sinistra.
In questo caso puoi:
- invertire i collegamenti CLK e DT;
- invertire nel codice le istruzioni di incremento e decremento.
🧠 Perché è un progetto importante
Con questo progetto impari a:
👉 Nel prossimo progetto utilizzeremo l’encoder per navigare in un vero menu.
Con questo progetto impari a:
- utilizzare un encoder rotativo;
- riconoscere la direzione di rotazione;
- leggere un pulsante integrato;
- modificare più parametri;
- creare un’interfaccia compatta;
- gestire valori minimi e massimi;
- utilizzare un display OLED;
- ridurre gli aggiornamenti inutili;
- applicare un controllo antirimbalzo;
- preparare la base per menu più complessi.
👉 Nel prossimo progetto utilizzeremo l’encoder per navigare in un vero menu.
🔄 Varianti possibili
Vuoi migliorare il progetto?
Vuoi migliorare il progetto?
- 💡 collega un LED PWM;
- 🌡️ collega un sensore di temperatura;
- ⚡ controlla un relè;
- 🔊 aggiungi un buzzer alla rotazione;
- 💾 salva i valori nella EEPROM;
- 📋 crea più parametri;
- ⏱️ regola un timer;
- 🚗 controlla la velocità di un motore;
- 🎚️ modifica la sensibilità dell’encoder;
- 📟 utilizza un display OLED più grande;
- 🔐 aggiungi una schermata di blocco;
- 🎛️ usa una pressione lunga per azzerare i valori.