Archivi tag: Arduino Sensor Kit

Lezione 11 – Corso di Elettronica Creativa con Arduino Sensor Kit

Accelerometro

L’accelerometro del Sensor Kit è un “sensore di movimento” a tre assi (X, Y, Z) capace di misurare come cambia la velocità di un oggetto nello spazio. Anche quando è fermo, l’accelerometro non rileva “zero accelerazione” in quanto misura la gravità terrestre, circa 1 g (≈ 9,81 m/s²). Questa caratteristica è utilissima perché ci permette sia di capire se e quanto ci stiamo muovendo, sia di stimare l’inclinazione del modulo rispetto alla verticale. In pratica: se appoggio la scheda piatta sul banco, il valore lungo Z sarà vicino a 1 g; se lo incliniamo, la gravità si “ridistribuisce” tra X e Y e possiamo ricavare l’angolo di inclinazione.

Con i dati che fornisce l’accelerometro possiamo fare molte cose: visualizzare scosse e vibrazioni (come un mini sismografo), creare un avviso di caduta, progettare giochi di equilibrio o semplicemente tracciare i movimenti sulla Serial Plotter. In questa lezione impareremo a leggere le tre componenti, a filtrare il rumore e a trasformare quei numeri in azioni concrete (LED, buzzer, messaggi su OLED).

Un briciolo di teoria

L’accelerometro misura accelerazioni lungo X, Y, Z e come dicevo sopra, da fermo “vede” la gravità (~1 g ≈ 9,81 m/s²).

Il modulo del vettore accelerazione è:

Con il dispositivo quasi fermo, possiamo stimare l’inclinazione rispetto alla verticale usando solo la gravità:

che rappresenta l’angolo rispetto all’asse Z (in gradi).

Caratteristiche tecniche (per i più esperti)

  • Tipo sensore: MEMS accelerometro triassiale digitale.
  • Interfacce: I²C e SPI digitali (il modulo Grove è normalmente usato in I²C sul Sensor Kit).
  • Indirizzo I²C: di default 0x19, commutabile a 0x18 (pin SA0/SDO a GND).
  • Campo di misura (full-scale): ±2 g, ±4 g, ±8 g, ±16 g (selezionabile via registro).
  • Risoluzione dati: uscita fino a 16-bit; modalità operative low-power/normal/high-resolution (fino a 12-bit effettivi).
  • Frequenza di campionamento (ODR): da 1 Hz fino a 5.3 kHz (a seconda della modalità).
  • Funzioni integrate:
    • 2 generatori di interrupt programmabili (motion, free-fall, wake-up).
    • Rilevamento orientamento 6D/4D, self-test, FIFO 32 campioni.
  • Alimentazione (chip): 1.71–3.6 V; consumo molto basso (fino a ~2 µA in ultra-low-power). Il modulo Grove è compatibile 3 V / 5 V.
  • Intervallo di temperatura operativa: −40 °C … +85 °C.

Informazioni utili per l’uso nell’Arduino Sensor Kit

  • Con la libreria Arduino_SensorKit.h leggete le tre componenti con Accelerometer.readX() / readY() / readZ(); i valori restituiti sono interpretati in g (gravità ≈ 1 g a riposo).
  • Il modulo Grove usato nel Sensor Kit documenta esplicitamente indirizzi I²C, range e compatibilità 3V/5V, utile se sorgono conflitti su bus I²C o serve cambiare indirizzo.

Collegamenti

Per quanto riguarda i collegamenti è sufficiente connettere il sensore ad uno degli ingressi I²C della Base Shield.

Esempio 01 – Lettura accelerometro 3 assi

/*
  Prof. Maffucci Michele
  02.10.2025
  Lettura accelerometro 3 assi – Arduino Sensor Kit
*/

#include <Arduino_SensorKit.h>   // Libreria unica per i moduli del Sensor Kit

const unsigned long intervalloMs = 500;  // intervallo tra una stampa e la successiva

void setup() {
  // Inizializzazione porta seriale per inviare i dati al PC
  Serial.begin(9600);

  // ATTENZIONE:
  // while(!Serial); serve ad ASPETTARE che il monitor seriale sia stato aperto
  // (utile sulle schede con USB nativa, esempio: Arduino UNO R4 WiFi, Leonardo, MKR).
  // Così non "perdi" le prime stampe.
  // Su schede senza USB nativa non è necessario e puoi rimuoverlo.
  while (!Serial) { ; }

  // Avvio dell'accelerometro a 3 assi
  Accelerometer.begin();
}

void loop() {
  // Lettura delle tre componenti di accelerazione (in g)
  float accelX = Accelerometer.readX();  // Asse X
  float accelY = Accelerometer.readY();  // Asse Y
  float accelZ = Accelerometer.readZ();  // Asse Z

  // Stampa in formato semplice: x:..  y:..  z:..
  Serial.print("x: "); 
  Serial.print(accelX, 3);   // 3 decimali per leggibilità
  Serial.print("  ");

  Serial.print("y: "); 
  Serial.print(accelY, 3);
  Serial.print("  ");

  Serial.print("z: "); 
  Serial.println(accelZ, 3);

  delay(intervalloMs);
}

Esempio 02: Accelerometro – Stampa su Serial Monitor e display OLED

Visualizzazione delle componenti x, y e z dell’accelerazione su Serial Monitor e display OLED

/*
  Prof. Maffucci Michele
  02.10.2025
  Lettura accelerometro 3 assi – Arduino Sensor Kit
  Stampa su Serial Monitor e display Oled
*/

#include <Arduino_SensorKit.h>  // Libreria unica per i moduli del Sensor Kit

const unsigned long intervalloMs = 500;  // intervallo tra una stampa e la successiva

void setup() {
  // Inizializzazione porta seriale per inviare i dati al PC
  Serial.begin(9600);

  // ATTENZIONE:
  // while(!Serial); serve ad ASPETTARE che il monitor seriale sia stato aperto
  // (utile sulle schede con USB nativa, esempio: Arduino UNO R4 WiFi, Leonardo, MKR).
  // Così non "perdi" le prime stampe.
  // Su schede senza USB nativa non è necessario e puoi rimuoverlo.
  while (!Serial) { ; }

  // Avvio dell'accelerometro a 3 assi
  Accelerometer.begin();
  Oled.begin();
  // Inizializza il display OLED.
  // Fa partire la comunicazione I2C e manda al display la sequenza di avvio.
  // Senza questa riga lo schermo non mostra nulla.

  Oled.setFlipMode(true);
  // Ruota il contenuto di 180° (utile se lo vedi capovolto).
  // Se nel tuo caso appare già dritto, puoi mettere false: Oled.setFlipMode(false);

  Oled.setFont(u8x8_font_chroma48medium8_r);
  // Sceglie il font (carattere) 8x8.
  // Con un font 8x8 il display 128x64 si comporta come una griglia 16 colonne × 8 righe.
  // Significa che setCursor(colonna, riga) userà numeri tra 0..15 (colonne) e 0..7 (righe).

  Oled.clear();
  // Pulisce lo schermo (cancella tutto quello che c’era prima).
}

void loop() {
  // Lettura delle tre componenti di accelerazione (in g)
  float accelX = Accelerometer.readX();  // Asse X
  float accelY = Accelerometer.readY();  // Asse Y
  float accelZ = Accelerometer.readZ();  // Asse Z

  // Stampa in formato semplice: x:..  y:..  z:..
  Serial.print("x: ");      // stampa la stringa x: su Serial Monitor
  Serial.print(accelX, 3);  // 3 decimali per leggibilità
  Serial.print("  ");

  Serial.print("y: ");      // stampa la stringa y: su Serial Monitor
  Serial.print(accelY, 3);  // 3 decimali per leggibilità
  Serial.print("  ");

  Serial.print("z: ");        // stampa la stringa z: su Serial Monitor
  Serial.println(accelZ, 3);  // 3 decimali per leggibilità

  Oled.setCursor(0, 0);           // colonna 0, riga 0
  Oled.println("ACCELERAZIONE");  // stampa la stringa e va a capo

  Oled.setCursor(0, 2);   // colonna 0, riga 2
  Oled.print("x: ");      // stampa la stringa x:
  Oled.print(accelX, 3);  // stampa la componente x dell'accelerazione con 3 cifre decimali

  Oled.setCursor(0, 3);   // colonna 0, riga 3
  Oled.print("y: ");      // stampa la stringa y:
  Oled.print(accelY, 3);  // stampa la componente y dell'accelerazione con 3 cifre decimali
  Oled.refreshDisplay();

  Oled.setCursor(0, 4);   // colonna 0, riga 4
  Oled.print("z: ");      // stampa la stringa z:
  Oled.print(accelZ, 3);  // stampa la componente z dell'accelerazione con 3 cifre decimali
  Oled.refreshDisplay();

  delay(intervalloMs);
}

Esempio 03: Accelerometro – Uscita per Serial Plotter (3 curve: X, Y, Z)

Stampa i tre assi con etichette e tab in un’unica riga per campione, in questo modo l’IDE mostra tre curve (X, Y, Z).

/*
  Prof. Maffucci Michele
  02.10.2025
  Accelerometro – Uscita per Serial Plotter (3 curve: X, Y, Z)

  Nota: una riga = un campione; valori etichettati e separati da TAB -> 3 curve nel Plotter.
*/

#include <Arduino_SensorKit.h&gt

const unsigned long periodoCampionamentoMs = 10;  // circa 100 Hz (riduci/aumenta a piacere)

void setup() {
  Serial.begin(115200);
  // Attende l'apertura del Monitor/Plotter Seriali sulle schede con USB nativa
  while (!Serial) { ; }

  Accelerometer.begin();

  // Messaggio di avvio (facoltativo)
  Serial.println("Traccio X,Y,Z (g) - dati GREZZI (nessun filtro)");
}

void loop() {
  // Letture grezze in g
  float x = Accelerometer.readX();
  float y = Accelerometer.readY();
  float z = Accelerometer.readZ();

  // Stampa “label:valore” separati da TAB → il Plotter disegna tre curve
  Serial.print("X:");
  Serial.print(x, 3);
  Serial.print('\t');
  Serial.print("Y:");
  Serial.print(y, 3);
  Serial.print('\t');
  Serial.print("Z:");
  Serial.println(z, 3);

  delay(periodoCampionamentoMs);
}

Versione per esperti

Esempio 04: Accelerometro – Uscita per Serial Plotter (3 curve: X, Y, Z) con filtro passa-basso

Come avete potuto notare nella versione precedente le curve delle tre componenti dell’accelerazione erano seghettate e venivano rappresentate anche piccoli tremolii.

Per evitare questo problema useremo nello sketch che segue un filtro IIR (passa-basso) che smusserà il rumore.

Quali sono i vantaggi nell’utilizzo di un filtro passa basso:

  • Rumore: piccole variazioni veloci e indesiderate nei dati (tremolio della mano, vibrazioni del banco, disturbi elettrici).
  • Passa-basso: un filtro che lascia passare i cambiamenti lenti (il “trend” reale del movimento) e attenua i cambiamenti veloci (dovuti al rumore).
  • IIR (Infinite Impulse Response): significa che l’uscita del filtro dipende sia dal valore attuale sia dall’uscita precedente. In pratica: il filtro “ricorda” un po’ del passato -> è una media mobile esponenziale.

Formule per ogni asse:

uscita_filtrata(t) = α * ingresso(t) + (1−α) * uscita_filtrata(t−1)

α è un numero tra 0 e 1:

  • α piccolo (es. 0.1) > molto liscio (tanto filtraggio) ma più lento a seguire i cambiamenti.
  • α grande (es. 0.6) > meno liscio (meno filtraggio) ma più reattivo.

In sintesi:
scegliere α in base al compromesso “più liscio vs più rapido”.

/*
  Prof. Maffucci Michele
  02.10.2025
  Accelerometro - Uscita per Serial Plotter (3 curve: X, Y, Z) con filtro IIS (passa-basso)

  Note:
  - Il Serial Plotter IDE riconosce coppie "etichetta:valore" sulla stessa riga,
    separate da TAB. Ogni riga = un campione nel tempo.
*/

#include <Arduino_SensorKit.h&gt

const unsigned long periodoCampionamentoMs = 10;  // circa 100 Hz
const bool usaFiltro = true;                      // metti false se vuoi i dati grezzi
const float alfa = 0.2;                           // 0..1 (più piccolo = più filtrato)

float xF = 0, yF = 0, zF = 0;  // stati del filtro

void setup() {
  Serial.begin(115200);

  // Serve ad attendere l'apertura del Monitor/Plotter Seriali sulle schede con USB nativa,
  // così non perdete le prime stampe (su UNO "classico" puoi toglierlo senza problemi).
  while (!Serial) { ; }

  Accelerometer.begin();

  // (Facoltativo) riga di "header" informale: non necessaria, ma utile a chi guarda il log
  Serial.println("Pronto: traccio X,Y,Z (g) su Serial Plotter");
}

void loop() {
  // Letture in g
  float x = Accelerometer.readX();
  float y = Accelerometer.readY();
  float z = Accelerometer.readZ();

  if (usaFiltro) {
    // Filtro IIR (passa-basso) molto semplice per smussare il rumore
    xF = alfa * x + (1.0f - alfa) * xF;
    yF = alfa * y + (1.0f - alfa) * yF;
    zF = alfa * z + (1.0f - alfa) * zF;

    // Stampa "label:valore" separati da TAB > tre curve nel Plotter
    Serial.print("X:");
    Serial.print(xF, 3);
    Serial.print('\t');
    Serial.print("Y:");
    Serial.print(yF, 3);
    Serial.print('\t');
    Serial.print("Z:");
    Serial.println(zF, 3);
  } else {
    Serial.print("X:");
    Serial.print(x, 3);
    Serial.print('\t');
    Serial.print("Y:");
    Serial.print(y, 3);
    Serial.print('\t');
    Serial.print("Z:");
    Serial.println(z, 3);
  }

  delay(periodoCampionamentoMs);
}

Analizziamo nel dettaglio la parte del filtro.

xF = alfa * x + (1.0f - alfa) * xF;
yF = alfa * y + (1.0f - alfa) * yF;
zF = alfa * z + (1.0f - alfa) * zF;

xF = alfa * x + (1.0f - alfa) * xF;

  • x è il dato grezzo appena letto dall’accelerometro sull’asse X.
  • xF è il dato filtrato (uscita del filtro) per l’asse X.
  • alfa * x prende una frazione del dato nuovo (quanto “peso” dai alla misura attuale).
  • (1.0f - alfa) * xF prende una frazione del valore filtrato precedente (la “memoria”).
  • La somma dei due termini fornisce un valore ammorbidito: meno sensibile ai picchi improvvisi.

Nota sul suffisso f: indica un float letterale (utile per evitare promozioni a double in alcune piattaforme).

yF = alfa * y + (1.0f - alfa) * yF;

  • Identico ragionamento, ma applicato all’asse Y: nuova misura y + memoria del filtrato yF.
  • Mantieni alfa uguale sugli assi per coerenza visiva nel Plotter.

zF = alfa * z + (1.0f - alfa) * zF;

  • Stessa cosa per l’asse Z: la componente verticale (spesso contiene circa 1 g).
  • Filtrare Z aiuta a vedere meglio oscillazioni lente e a ridurre tremolii.

Qualche nota pratica

  1. Inizializzazione: se impostate xF = yF = zF = 0 all’inizio, i primi campioni possono “salire” gradualmente verso il valore reale (breve transitorio). Se volete partire subito “allineati”, potete inizializzare xF=yF=zF al primo dato letto.
  2. Scelta di alfa:
    0.1-0.3 > grafico molto liscio (meno rumore), risposta più lenta.
    0.4-0.7 > più reattivo, ma un po’ più “seghettato”.

Buon Coding a tutti 🙂

Lezione 10 – Corso di Elettronica Creativa con Arduino Sensor Kit

Cenni teorici

Cos’è la pressione atmosferica?

La pressione atmosferica è la forza esercitata dall’aria su ogni unità di superficie. Viene misurata in pascal (Pa) o, più comunemente, in hectopascal (hPa) dove 1 hPa = 100 Pa.

Il sensore BMP280

Il BMP280 è un sensore barometrico assoluto prodotto da Bosch Sensortec. Le sue caratteristiche principali:

  • Campo di misura: 300 – 1100 hPa (≈ -500 m / +9000 m s.l.m.)
  • Accuratezza assoluta tip. ±1 hPa; accuratezza relativa ±0.12 hPa (≈ ±1 m)
  • Interfacce: I²C (fino a 3.4 MHz) e SPI
  • Consumo: 2.7 µA @ 1 Hz in modalità normale
  • Range termico: –40 … +85 °C

Collegamenti

Collegate il cavo Grove tra il connettore del sensore e la porta I²C (qualsiasi) sullo shield.

Installazione libreria

Sicuramente è un’operazione che avete già eseguito, in ogni caso lo ricordo:

  • Arduino IDE > Gestione librerie > cerca “Arduino_SensorKit”.
  • Installate la libreria (include automaticamente LPS22HB, HTS221, OLED, ecc.)

 Esempio 01: Sketch base – Lettura e stampa dati su Serial Monitor

/*
  Prof. Maffucci Michele
  02.10.2025
  LPS22HB del Sensor Kit
  Stampa valori su Serial Monitor
*/

#include &lt;Arduino_SensorKit.h&gt;   // include unico per tutti i sensori

void setup() {
  Serial.begin(9600);
  Pressure.begin();              // inizializza il barometro
}

void loop() {
  // La libreria restituisce:
  // - pressione in pascal
  // - temperatura in gradi Celsius
  // - altitudine in metri rispetto a 1013,25 hPa

float pressionePa  = Pressure.readPressure();
  float temperaturaC = Pressure.readTemperature();
  float altitudineM  = Pressure.readAltitude();

// conversione pa → hPa per leggibilità
  float pressioneHpa = pressionePa / 100.0;

Serial.print(F("Pressione: "));
  Serial.print(pressioneHpa, 2);
  Serial.print(F(" hPa\tTemperatura: "));
  Serial.print(temperaturaC, 2);
  Serial.print(F(" °C\tAltitudine: "));
  Serial.print(altitudineM, 1);
  Serial.println(F(" m"));

delay(1000);
}

Ricordo che, come già indicato nelle precedenti lezioni, la F(…) (maiuscola), inserita all’interno delle Serial.print(), è una macro di Arduino che serve a mettere una stringa letterale in memoria flash (PROGMEM) invece che copiarla nella SRAM al momento della stampa.

Perché è utile utilizzare F

  • Le board come Arduino UNO (AVR) hanno poca SRAM (2 KB).
  • Senza (), ogni stringa tra virgolette ("Pressione: ") viene copiata in SRAM prima di stamparla > spreco di RAM.
  • Con F("Pressione: "), la stringa resta in flash e Serial.print() la legge direttamente da lì > RAM risparmiata.

Come si usa

Funziona con tutte le funzioni che derivano da Print (es. Serial.print, Serial.println, spesso anche display che usano print in stile Arduino):

Serial.print(F("Pressione: "));
Serial.println(F(" hPa"));

Quando usarla

  • Frasi/titoli/menu costanti e ripetute (log su Serial, messaggi di errore, etichette).
  • Con progetti in cui si ha scarsa disponibilità di RAM (UNO/Nano classici) può fare la differenza.

Limiti

  • Non puoi concatenare direttamente elementi come F(“A”) + F(“B”).
  • Evitare di mescolarla con String in modo implicito (meglio stampare pezzi separati).
  • Funzioni come sprintf non leggono da flash; su AVR esistono versioni “_P” (es. sprintf_P) per farlo.

La struttura delle funzioni (Pressure.begin(), Pressure.readPressure(), ecc.) è la stessa mostrata negli esempi ufficiali di Arduino.

 Esempio 02: Lettura e stampa dati su Serial Monitor e display OLED

Abbiamo già visto l’uso del display OLED nella lezione: Lezione 9 – Corso di Elettronica Creativa con Arduino Sensor Kit vediamo ora come mostrare i valori di: pressione, temperatura e altitudine anche sul display OLED.

/*
  Prof. Maffucci Michele
  02.10.2025
  BMP280 - Arduino Sensor Kit
  Stampa valori su Serial Monitor e OLED
*/

#include <Arduino_SensorKit.h>  // include unico per tutti i sensori

void setup() {
  Serial.begin(9600);
  Pressure.begin();  // inizializza il barometro

Oled.begin();
  // Inizializza il display OLED.
  // Fa partire la comunicazione I2C e manda al display la sequenza di avvio.
  // Senza questa riga lo schermo non mostra nulla.

Oled.setFlipMode(true);
  // Ruota il contenuto di 180° (utile se lo vedi capovolto).
  // Se nel tuo caso appare già dritto, puoi mettere false: Oled.setFlipMode(false);

Oled.setFont(u8x8_font_chroma48medium8_r);
  // Sceglie il font (carattere) 8x8.
  // Con un font 8x8 il display 128x64 si comporta come una griglia 16 colonne × 8 righe.
  // Significa che setCursor(colonna, riga) userà numeri tra 0..15 (colonne) e 0..7 (righe).

Oled.clear();
  // Pulisce lo schermo (cancella tutto quello che c’era prima).
}

void loop() {
  // La libreria restituisce:
  // - pressione in pascal
  // - temperatura in gradi Celsius
  // - altitudine in metri rispetto a 1013,25 hPa

float pressionePa = Pressure.readPressure();
  float temperaturaC = Pressure.readTemperature();
  float altitudineM = Pressure.readAltitude();

// conversione pa → hPa per leggibilità
  float pressioneHpa = pressionePa / 100.0;

// --- Intestazione ---

Oled.setCursor(0, 0);             // colonna 0, riga 0
  Oled.println("STAZIONE METEO");   // stampa la stringa e va a capo
  Oled.println("P - Pressione");    // stampa la stringa e va a capo
  Oled.println("T - Temperatura");  // stampa la stringa e va a capo
  Oled.println("A - Altitudine");   // stampa la stringa e va a capo

Oled.setCursor(0, 5);         // colonna 0, riga 2
  Oled.print("P: ");            // stampa la stringa P:
  Oled.print(pressioneHpa, 2);  // stampa valore della pressione con 2 numeri decimali

Oled.setCursor(0, 6);         // colonna 0, riga 3
  Oled.print("T: ");            // stampa la stringa T:
  Oled.print(temperaturaC, 2);  // stampa valore della temperatura con 2 numeri decimali
  Oled.refreshDisplay();

Oled.setCursor(0, 7);        // colonna 0, riga 4
  Oled.print("A: ");           // stampa la stringa A:
  Oled.print(altitudineM, 2);  // stampa valore dell'altitudine con 2 numeri decimali
  Oled.refreshDisplay();

// Aggiorna fisicamente il display (altrimenti potresti non vedere le modifiche).
  delay(60);

Serial.print(F("Pressione: "));
  Serial.print(pressioneHpa, 2);
  Serial.print(F(" hPa\tTemperatura: "));
  Serial.print(temperaturaC, 2);
  Serial.print(F(" °C\tAltitudine: "));
  Serial.print(altitudineM, 1);
  Serial.println(F(" m"));

delay(1000);
}

Buon Coding a tutti 🙂

Lezione 9 – Corso di Elettronica Creativa con Arduino Sensor Kit

Sensore di temperatura ed umidità (DHT22)

Ho parlato in precedenti post dei sensori di temperatura ed umidità, nello specifico l’uso del diffusissimo DHT11. L’Arduino Sensor Kit li può usare entrambi, ma nel kit è presente il DHT22.

Caratteristiche tecniche del DHT22

Il DHT22 è un sensore digitale che integra:

  • un elemento capacitivo per l’umidità relativa (RH),
  • un sensore termico per la temperatura,
  • un microcontrollore che invia i dati su un’unica linea (single-wire digitale, non analogica).
  • Range tipici e specifiche:
    • Temperatura: –40…+80 °C (risoluzione 0,1 °C, tip. ±0,5 °C),
    • Umidità relativa: 0…100 % RH (risoluzione 0,1 % RH, tip. ±2 % RH, max ±5 %),
  • Alimentazione: 3,3–5 V,
  • Frequenza di campionamento: max 0,5 Hz (una misura ogni ~2 s).

Cos’è l’umidità relativa

L’umidità relativa (RH) indica quanta vapor d’acqua è presente nell’aria rispetto alla quantità massima che quell’aria potrebbe contenere alla stessa temperatura.

  • 50 % RH = l’aria contiene metà del vapore “possibile” a quella temperatura.
  • 100 % RH = saturazione (rischio di condensa).
    Poiché la capacità dell’aria di trattenere vapore cresce con la temperatura, la RH dipende dalla temperatura: per questo i sensori come il DHT22 misurano entrambe le grandezze.

Mi è capitato spesso rispondere alla domanda: “ma Prof. cosa è meglio usare il DHT11 o il DHT22”

Se si dispone di entrambi certamente scegliere il DHT22 è da preferire, ma perché?

  • Precisione e range migliori: DHT22 copre –40…+80 °C (vs 0…+50 °C del DHT11) con ±0,5 °C tipici; RH 0…100 % con ±2–5 % (DHT11 è meno preciso e più limitato).
  • Risoluzione più fine: 0,1 °C / 0,1 % RH (utile per realizzare grafici e verificare trend).

Un vantaggio derivante dall’uso dell’Arduino Sensor Kit è che il DHT22 viene connesso all’Arduino mediante connessione I²C pertanto per il suo utilizzo è possibile collegarlo ad una delle uscite I²C presenti sulla Base Shield.

Veniamo ora agli esempi pratici, ne indico 6 di base, come sempre nei commenti la spiegazione. In classe ne realizzerò altri in cui mostreremo ad esempio la rilevazione della temperatura a media mobile a 10 campioni, attivazione di allarmi e ventole e molto altro.

Connessioni usate in questa lezione:

  • Sensore di Temperatura ed Umidità: connesso ad una qualsiasi dei pin I²C della Base Shield.
  • Display OLED: connesso ad una qualsiasi dei pin I²C della Base Shield.
  • Diodo LED: connesso al D6.

Esempio 01: sensore ambiente – lettura base (temperatura – umidità)

/*
  Prof. Maffucci Michele
  01.10.2025
  Sensore Ambiente – Lettura base (Temperatura + Umidità)

  NOTE:
    - DHT20 (I2C): decommenta la define Environment_I2C e abilita Wire.begin()
    - DHT11 (pin D3 via Base Shield): commenta la define, la libreria gestisce il pin di default
*/

#include <Arduino_SensorKit.h>

// >>> Decommenta se il sensore è DHT20 (I2C) <<<
#define Environment Environment_I2C

void setup() {
  Serial.begin(9600);
  // Necessario per DHT20 (I2C); non influisce negativamente su DHT11
  Wire.begin();

  Environment.begin();  // inizializza il sensore ambiente (DHT11 o DHT20)
}

void loop() {
  float temperaturaC = Environment.readTemperature(); // °C
  float umiditaRH    = Environment.readHumidity();    // %RH

  // Stampa della temperatura e dell'umidità sulla Serial Monitor ogni secondo
  Serial.print("Temperatura: ");
  Serial.print(temperaturaC, 1);
  Serial.print(" °C   Umidità: ");
  Serial.print(umiditaRH, 1);
  Serial.println(" %");

  delay(1000);
}

Esempio 02: Lettura Temperatura e Umidità con allarme su D6 (LED)

In questo esempio utilizziamo il diodo LED connesso al D6 come allarme, pertanto verrà acceso se la temperatura supera un valore di soglia impostato.

/*
  Prof. Maffucci Michele
  01.10.2025
  Lettura Temperatura e Umidità con allarme su D6 (LED)

  - Allarme: LED su D6 si accende se T > soglia.
  - Messaggi su Serial Monitor: ALERT all'attivazione, DISATTIVATO allo spegnimento.
  - DHT20 (I2C): lascia attiva la define Environment_I2C.
  - DHT11: commenta la define sotto; la libreria gestisce il pin del Base Shield.
*/

#include "Arduino_SensorKit.h"

#define Environment Environment_I2C

// Configurazione allarme
const int pinLedAllarme = 6;            // LED collegato al pin D6
const float sogliaTemperaturaC = 25.0;  // soglia in °C

bool allarmeAttivo = false;  // stato attuale dell'allarme

void setup() {
  Serial.begin(9600);

  // Necessario per DHT20 e per eventuali altre periferiche I2C (OLED, ecc.)
  Wire.begin();

  // Inizializza il sensore ambiente (DHT11 o DHT20 a seconda della define)
  Environment.begin();

  // LED di allarme
  pinMode(pinLedAllarme, OUTPUT);
  digitalWrite(pinLedAllarme, LOW);

  Serial.println("== Avvio lettura Temperatura & Umidita' con allarme su D6 ==");
  Serial.print("Soglia T = ");
  Serial.print(sogliaTemperaturaC, 1);
  Serial.println(" C");
}

void loop() {
  // Letture dal sensore
  float temperaturaC = Environment.readTemperature();  // °C
  float umiditaRH = Environment.readHumidity();        // %RH

// --- Gestione allarme con isteresi ---
// Usiamo DUE soglie diverse per evitare ON/OFF continui vicino al limite.
//  - Soglia di ACCENSIONE  (T_on):  temperaturaC > sogliaTemperaturaC
//  - Soglia di SPEGNIMENTO (T_off): temperaturaC < sogliaTemperaturaC // Finché T resta tra T_off e T_on, manteniamo lo stato attuale (nessun cambiamento). if (!allarmeAttivo && temperaturaC > sogliaTemperaturaC) {
  // Caso 1: l'allarme è attualmente OFF e la temperatura SUPERA la soglia di ACCENSIONE.
  // Accendiamo l'allarme (LED ON) e stampiamo un messaggio di ALERT.
  allarmeAttivo = true;
  digitalWrite(pinLedAllarme, HIGH);

  Serial.print("!!! ALERT: Temperatura sopra soglia: ");
  Serial.print(temperaturaC, 1);
  Serial.println(" C");

} else if (allarmeAttivo && temperaturaC < sogliaTemperaturaC) { // Caso 2: l'allarme è attualmente ON e la temperatura SCENDE sotto la soglia di SPEGNIMENTO // Spegniamo l'allarme (LED OFF) e informiamo che è rientrato. allarmeAttivo = false; digitalWrite(pinLedAllarme, LOW); Serial.print("Allarme DISATTIVATO: Temperatura rientrata: "); Serial.print(temperaturaC, 1); Serial.println(" C"); } // Nota sui casi limite: // - Se temperaturaC == sogliaTemperaturaC, NON si accende (serve ">" strettamente).
// - Se temperaturaC == (sogliaTemperaturaC, NON si spegne (serve "<" strettamente).

  // Stampa della temperatura e dell'umidità sulla Serial Monitor
  Serial.print("T=");
  Serial.print(temperaturaC, 1);
  Serial.print(" C   RH=");
  Serial.print(umiditaRH, 1);
  Serial.print(" %   ALLARME=");
  if (allarmeAttivo) {
    Serial.println("ON");
  } else {
    Serial.println("OFF");
  }

  delay(1000);
}

Esempio 03: Lettura Temperatura e Umidità con allarme su D6 (LED) con isteresi

Premessa

In elettronica, isteresi è la presenza di due soglie diverse per il passaggio tra due stati, così l’uscita dipende non solo dal valore istantaneo dell’ingresso, ma anche dalla sua storia. Serve a evitare commutazioni rapide e instabili quando il segnale oscilla vicino a una soglia.

Come nell’esempio precedente utilizziamo il diodo LED connesso al D6 come allarme, inoltre useremo l’isteresi per evitare che il LED “sfarfalli” (ON/OFF ripetuti) quando la temperatura oscilla vicino alla soglia a causa di rumore o piccole variazioni.

Nello sketch che segue l’isteresi funziona in questo modo:

  • Soglia di attivazione: sogliaTemperaturaC = 26.0 °C
    L’allarme si accende appena T > 26.0 °C.
  • Isteresi: isteresiC = 0.5 °C
    L’allarme si spegne solo quando T < 26.0 − 0.5 = 25.5 °C.

Quindi usi due soglie:

  • T_on = 26.0 °C (accendo quando la supero)
  • T_off = 25.5 °C (spengo solo quando scendo sotto)

Senza isteresi, se la temperatura è nell’intorno di intorno a 26 °C (es. 25.9 ↔ 26.1 per il rumore), l’allarme continuerebbe ad accendersi e spegnersi rapidamente. Con l’isteresi, una volta acceso, resta acceso finché non rientra ben al di sotto della soglia, evitando lampeggi/ronzii fastidiosi e messaggi “ALERT” ripetuti.

Quindi come regola generale per i sensori DHT che utilizziamo in laboratorio valori tra 0,3 e 1°C sono di solito sufficienti. Se è presente ancora sfarfallio, aumentare leggermente; se la risposta è troppo lenta a spegnersi, ridurre.

Come schema logico si tenga in conto:

  • Se allarme OFF e T > T_on → accendere
  • Se allarme ON e T < T_off → spegnere
  • Altrimenti mantenere lo stato corrente

È la stessa logica usata nei termostati: due soglie (accensione/spegnimento) invece di una sola, per ottenere un comportamento stabile.

/*
  Prof. Maffucci Michele
  01.10.2025
  Lettura Temperatura e Umidità con allarme su D6 (LED) con isteresi

  - Allarme: LED su D6 si accende se T > soglia.
  - Messaggi su Serial Monitor: ALERT all'attivazione, DISATTIVATO allo spegnimento.
  - DHT20 (I2C): lascia attiva la define Environment_I2C.
  - DHT11: commenta la define sotto; la libreria gestisce il pin del Base Shield.
*/

#include <Arduino_SensorKit.h>

#define Environment Environment_I2C

// Configurazione allarme
const int pinLedAllarme = 6;            // LED collegato al pin D6
const float sogliaTemperaturaC = 25.0;  // soglia in °C
const float isteresiC = 0.5;            // isteresi per evitare lampeggi (spegnimento sotto soglia - isteresi)

bool allarmeAttivo = false;  // stato attuale dell'allarme

void setup() {
  Serial.begin(9600);

  // Necessario per DHT20 e per eventuali altre periferiche I2C (OLED, ecc.)
  Wire.begin();

  // Inizializza il sensore ambiente (DHT11 o DHT20 a seconda della define)
  Environment.begin();

  // LED di allarme
  pinMode(pinLedAllarme, OUTPUT);
  digitalWrite(pinLedAllarme, LOW);

  Serial.println("== Avvio lettura Temperatura & Umidita' con allarme su D6 ==");
  Serial.print("Soglia T = ");
  Serial.print(sogliaTemperaturaC, 1);
  Serial.println(" C");
}

void loop() {
  // Letture dal sensore
  float temperaturaC = Environment.readTemperature();  // °C
  float umiditaRH = Environment.readHumidity();        // %RH

// --- Gestione allarme con isteresi ---
// Usiamo DUE soglie diverse per evitare ON/OFF continui vicino al limite.
//  - Soglia di ACCENSIONE  (T_on):  temperaturaC > sogliaTemperaturaC
//  - Soglia di SPEGNIMENTO (T_off): temperaturaC < (sogliaTemperaturaC - isteresiC) // Finché T resta tra T_off e T_on, manteniamo lo stato attuale (nessun cambiamento). if (!allarmeAttivo && temperaturaC > sogliaTemperaturaC) {
  // Caso 1: l'allarme è attualmente OFF e la temperatura SUPERA la soglia di ACCENSIONE.
  // Accendiamo l'allarme (LED ON) e stampiamo un messaggio di ALERT.
  allarmeAttivo = true;
  digitalWrite(pinLedAllarme, HIGH);

  Serial.print("!!! ALERT: Temperatura sopra soglia: ");
  Serial.print(temperaturaC, 1);
  Serial.println(" C");

} else if (allarmeAttivo && temperaturaC < (sogliaTemperaturaC - isteresiC)) { // Caso 2: l'allarme è attualmente ON e la temperatura SCENDE sotto la soglia di SPEGNIMENTO // (cioè sotto la soglia di accensione meno l'isteresi). // Spegniamo l'allarme (LED OFF) e informiamo che è rientrato. allarmeAttivo = false; digitalWrite(pinLedAllarme, LOW); Serial.print("Allarme DISATTIVATO: Temperatura rientrata: "); Serial.print(temperaturaC, 1); Serial.println(" C"); } // Nota sui casi limite: // - Se temperaturaC == sogliaTemperaturaC, NON si accende (serve ">" strettamente).
// - Se temperaturaC == (sogliaTemperaturaC - isteresiC), NON si spegne (serve "<" strettamente).
// Questo evita cambi di stato ripetuti quando il valore oscilla esattamente sulla soglia.

  // Stampa della temperatura e dell'umidità sulla Serial Monitor
  Serial.print("T=");
  Serial.print(temperaturaC, 1);
  Serial.print(" C   RH=");
  Serial.print(umiditaRH, 1);
  Serial.print(" %   ALLARME=");
  if (allarmeAttivo) {
    Serial.println("ON");
  } else {
    Serial.println("OFF");
  }

  delay(1000);
}

Esempio 04: Lettura Temperatura e Umidità con stampa su OLED e Serial Monitor

Abbiamo visto nella precedente lezione l’uso del display OLED dell’Arduino Sensor Kit, utilizziamolo ora per mostrare temperatura ed umidità che stamperemo anche sulla Serial Monitor.

/*
  Prof. Maffucci Michele
  01.10.2025
  Lettura Temperatura e Umidità con stampa su OLED e Serial Monitor

  - DHT20 (I2C): lascia attiva la define Environment_I2C.
  - DHT11: commenta la define sotto; la libreria gestisce il pin del Base Shield.
*/

#include <Arduino_SensorKit.h>

#define Environment Environment_I2C

void setup() {
  Serial.begin(9600);
  Wire.begin();         // necessario con DHT20/OLED su I2C
  Environment.begin();  // DHT11 o DHT20 (in base alla define)
  Oled.begin();         // inizializza OLED

  // Orientamento e font leggibile
  Oled.setFlipMode(true);
  Oled.setFont(u8x8_font_chroma48medium8_r);

  // Pulisci UNA volta all’avvio
  Oled.clearDisplay();

  // Etichette fisse (non cambiano > non serve riscriverle)
  Oled.setCursor(0, 2);
  Oled.print("T=");
  Oled.setCursor(0, 4);
  Oled.print("RH=");
}

void loop() {

  float tC = Environment.readTemperature();  // °C
  float rH = Environment.readHumidity();     // %RH

  // --Stampa su OLED

  // Sovrascrivo soltanto il campo variabile, SENZA clearDisplay
  Oled.setCursor(2, 2);  // subito dopo "T="
  Oled.print(tC);

  Oled.setCursor(3, 4);  // subito dopo "RH="
  Oled.print(rH);

  // --Stampa su seriale
  Serial.print("T=");
  Serial.print(tC);
  Serial.print(" C   RH=");
  Serial.print(rH);
  Serial.println(" %");

  delay(500);  // aggiorna 2 volte al secondo (meno sfarfallio)
}

Esempio 05: Lettura Temperatura e Umidità con stampa su OLED e Serial Monitor ed accensione LED con isteresi

Aggiungiamo alla versione precedente l’allarme dato con il LED.

/*
  Prof. Maffucci Michele
  01.10.2025
  Lettura Temperatura e Umidità con stampa su OLED e Serial Monitor
  ed accensione LED con isteresi

  - DHT20 (I2C): lascia attiva la define Environment_I2C.
  - DHT11: commenta la define sotto; la libreria gestisce il pin del Base Shield.
*/

#include <Arduino_SensorKit.h>

#define Environment Environment_I2C

// Configurazione allarme
const int pinLedAllarme = 6;            // LED collegato al pin D6
const float sogliaTemperaturaC = 25.0;  // soglia in °C
const float isteresiC = 0.5;            // isteresi per evitare lampeggi (spegnimento sotto soglia - isteresi)

bool allarmeAttivo = false;  // stato attuale dell'allarme

void setup() {
  Serial.begin(9600);
  Wire.begin();         // necessario con DHT20/OLED su I2C
  Environment.begin();  // DHT11 o DHT20 (in base alla define)
  Oled.begin();         // inizializza OLED

  // Orientamento e font leggibile
  Oled.setFlipMode(true);
  Oled.setFont(u8x8_font_chroma48medium8_r);

  // Pulisci UNA volta all’avvio
  Oled.clearDisplay();

  // Etichette fisse (non cambiano → non serve riscriverle)
  Oled.setCursor(0, 2);
  Oled.print("T=");
  Oled.setCursor(0, 4);
  Oled.print("RH=");

  pinMode(pinLedAllarme, OUTPUT);
  digitalWrite(pinLedAllarme, LOW);

  Serial.println("== Avvio lettura Temperatura & Umidita' con allarme su D6 ==");
  Serial.print("Soglia T = ");
  Serial.print(sogliaTemperaturaC, 1);
  Serial.println(" C");
}

void loop() {

  float tC = Environment.readTemperature();  // °C
  float rH = Environment.readHumidity();     // %RH

// --- Gestione allarme con isteresi ---
// Usiamo DUE soglie diverse per evitare ON/OFF continui vicino al limite.
//  - Soglia di ACCENSIONE  (T_on):  temperaturaC > sogliaTemperaturaC
//  - Soglia di SPEGNIMENTO (T_off): temperaturaC < (sogliaTemperaturaC - isteresiC) // Finché T resta tra T_off e T_on, manteniamo lo stato attuale (nessun cambiamento). if (!allarmeAttivo && tC > sogliaTemperaturaC) {
  // Caso 1: l'allarme è attualmente OFF e la temperatura SUPERA la soglia di ACCENSIONE.
  // Accendiamo l'allarme (LED ON) e stampiamo un messaggio di ALERT.
  allarmeAttivo = true;
  digitalWrite(pinLedAllarme, HIGH);

  Serial.print("!!! ALERT: Temperatura sopra soglia: ");
  Serial.print(tC, 1);
  Serial.println(" C");

} else if (allarmeAttivo && tC < (sogliaTemperaturaC - isteresiC)) {
  // Caso 2: l'allarme è attualmente ON e la temperatura SCENDE sotto la soglia di SPEGNIMENTO
  // (cioè sotto la soglia di accensione meno l'isteresi).
  // Spegniamo l'allarme (LED OFF) e informiamo che è rientrato.
  allarmeAttivo = false;
  digitalWrite(pinLedAllarme, LOW);

  Serial.print("Allarme DISATTIVATO: Temperatura rientrata: ");
  Serial.print(tC, 1);
  Serial.println(" C");
}

  // -- Stampa su OLED --

  // Sovrascrivo soltanto il campo variabile, SENZA clearDisplay
  Oled.setCursor(2, 2);  // subito dopo "T="
  Oled.print(tC);

  Oled.setCursor(3, 4);  // subito dopo "RH="
  Oled.print(rH);

  // -- Stampa su seriale --
  Serial.print("T=");
  Serial.print(tC);
  Serial.print(" C   RH=");
  Serial.print(rH);
  Serial.println(" %");

  delay(500);  // aggiorna 2 volte al secondo (meno sfarfallio)
}

Esempio 06: lettura Temperatura & Umidità con stampa su OLED e Serial Monitor ed accensione LED – su OLED viene mostrato allarme

Aggiungiamo allo sketch precedente la visualizzazione del messaggio di alert sul display. Per semplicità di lettura ho tolto i commenti nella sezione: “Gestione allarme con isteresi”, lasciando solo quelli che si riferiscono alla stampa dell’alert sul display.

/*
  Prof. Maffucci Michele
  01.10.2025
  Lettura Temperatura & Umidità con stampa su OLED e Serial Monitor
  ed accensione LED - su OLED viene mostrato allarme

  - DHT20 (I2C): lascia attiva la define Environment_I2C.
  - DHT11: commenta la define sotto; la libreria gestisce il pin del Base Shield.
*/

#include <Arduino_SensorKit.h>

#define Environment Environment_I2C

// Configurazione allarme
const int pinLedAllarme = 6;            // LED collegato al pin D6
const float sogliaTemperaturaC = 25.0;  // soglia in °C
const float isteresiC = 0.5;            // isteresi per evitare lampeggi (spegnimento sotto soglia - isteresi)

bool allarmeAttivo = false;  // stato attuale dell'allarme

void setup() {
  Serial.begin(9600);
  Wire.begin();         // necessario con DHT20/OLED su I2C
  Environment.begin();  // DHT11 o DHT20 (in base alla define)
  Oled.begin();         // inizializza OLED

  // Orientamento e font leggibile
  Oled.setFlipMode(true);
  Oled.setFont(u8x8_font_chroma48medium8_r);

  // Pulisci UNA volta all’avvio
  Oled.clearDisplay();

  // Etichette fisse (non cambiano → non serve riscriverle)
  Oled.setCursor(0, 2);
  Oled.print("T=");
  Oled.setCursor(0, 4);
  Oled.print("RH=");

  pinMode(pinLedAllarme, OUTPUT);
  digitalWrite(pinLedAllarme, LOW);

  Serial.println("== Avvio lettura Temperatura & Umidita' con allarme su D6 ==");
  Serial.print("Soglia T = ");
  Serial.print(sogliaTemperaturaC, 1);
  Serial.println(" C");
}

void loop() {

  float tC = Environment.readTemperature();  // °C
  float rH = Environment.readHumidity();     // %RH

  // --- Gestione allarme con isteresi ---
  if (!allarmeAttivo && tC > sogliaTemperaturaC) {
    allarmeAttivo = true;
    digitalWrite(pinLedAllarme, HIGH);

    // cursore nell'angolo in alto a destra
    Oled.setCursor(0, 0);
    // stampa del messaggio di alert
    Oled.print("ALERT: t>tMax");
    Serial.print("!!! ALERT: Temperatura sopra soglia: ");
    Serial.print(tC, 1);
    Serial.println(" C");
  } else if (allarmeAttivo && tC < (sogliaTemperaturaC - isteresiC)) {
    allarmeAttivo = false;
    digitalWrite(pinLedAllarme, LOW);

    // cursore nell'angolo in alto a destra
    Oled.setCursor(0, 0);
    // cancellazione con spazi del messaggio di alert
    Oled.print("             ");
    Serial.print("Allarme DISATTIVATO: Temperatura rientrata: ");
    Serial.print(tC, 1);
    Serial.println(" C");
  }

  // -- Stampa su OLED --

  // Sovrascrivo soltanto il campo variabile, SENZA clearDisplay
  Oled.setCursor(2, 2);  // subito dopo "T="
  Oled.print(tC);

  Oled.setCursor(3, 4);  // subito dopo "RH="
  Oled.print(rH);

  // -- Stampa su seriale --
  Serial.print("T=");
  Serial.print(tC);
  Serial.print(" C   RH=");
  Serial.print(rH);
  Serial.println(" %");

  delay(500);  // aggiorna 2 volte al secondo (meno sfarfallio)
}

Buon Coding a tutti 🙂

Lezione 8 – Corso di Elettronica Creativa con Arduino Sensor Kit

Lo schermo OLED

Questo modulo è un display OLED monocromatico 128×64 con interfaccia Grove a 4 pin I²C, adatto a mostrare testi e semplici indicatori grafici direttamente dall’Arduino Sensor Kit. Rispetto agli LCD, gli OLED offrono autoluminescenza, alto contrasto, ampio angolo di visione e basso consumo, perché non richiedono retroilluminazione.

L’OLED (Organic Light-Emitting Diode) usa materiali organici che emettono luce quando attraversati da corrente; non avendo una retroilluminazione, ogni pixel deve essere acceso/aggiornato dal controller. Nel Sensor Kit l’OLED 0,96″ (famiglia SSD1306/SSD1315) si controlla in modo semplificato tramite la libreria Arduino_SensorKit, che fornisce la classe Oled con metodi pronti per inizializzazione, posizionamento del cursore e stampa del testo.

Collegamento

  • Inserire il modulo/display sul connettore I2C del Grove Base Shield, monta lo shield su Arduino UNO e collega via USB.
  • Impostare l’interruttore del Base Shield su 5V (necessario per alimentare correttamente il display).
  • Su Arduino UNO i pin I²C sono SDA=A4 e SCL=A5; l’indirizzo I²C tipico dei moduli SSD1306 è 0x3C (alcuni esemplari possono usare 0x3D). Se non risponde, esegui uno scanner I²C per verificarlo.
  • Sull’Arduino Sensor Kit collegare il display al connettore I2C come mostrato nell’immagine che segue.

Librerie da utilizzare

  • Oled.begin() inizializza il controller con l’indirizzo corretto e imposta modalità/parametri base di comunicazione I²C.
  • Oled.setCursor(x,y) posiziona il cursore: con l’API U8x8 esposta dal kit lavori in celle di carattere 8×8 (circa 16 colonne × 8 righe su 128×64).
  • Oled.print(...) scrive testo/valori;
  • Oled.refreshDisplay() aggiorna lo schermo.

L’API U8x8 è “testo-only” e non richiede buffer RAM; per disegni pixel-level bisogna usare l’API grafica U8g2 (con font e funzioni grafiche più ricche).

Le differenze tra le due API:

  • U8x8 = velocità e semplicità e solo per testo;
  • U8g2 = grafica avanzata con e richiede più memoria.

Per i più curiosi

Il controller SSD1306 gestisce la RAM del display per pagine e supporta vari modi di indirizzamento (orizzontale/verticale/pagina). Le librerie si occupano dei dettagli, ma sapere che l’aggiornamento avviene “a blocchi” aiuta a capire perché alcune operazioni grafiche richiedono più tempo/buffer.

Specifiche del display

  • Alimentazione: 3,3–5 V (compatibile con UNO).
  • Interfaccia: I²C (Grove 4 pin).
  • Indirizzo: 0x3C (varianti 0x3D).
  • Caratteristiche d’uso: alto contrasto, basso consumo, ampia temperatura operativa (fino a –40…+85 °C su molte versioni).

Qualche consiglio da tenere a mente durante le sperimentazioni

  • Non lasciare per ore la stessa immagine ad alto contrasto; meglio aggiornare periodicamente o usare una schermata di riposo.
  • Stabilità del contenuto: se il testo “sfarfalla”, stampare prima su Serial Monitor per verificare i valori e ridurre la frequenza di refresh (es. ogni 100–200 ms).
  • Differenza tra griglia di caratteri (U8x8) e coordinate in pixel (U8g2): una “barra” fatta di caratteri ha 16 step, mentre a pixel può averne 128.

Esempi pratici

Versione con commenti per gli studenti in cui viene dettagliato il funzionamento di ogni parte del codice.

Esempio 1 (semplice)

/*
Prof. Maffucci Michele
25/09/2025
OLED – Scrivere nome e cognome - versione 1
Inizializzare il display OLED del Sensor Kit e mostrare
"Allievo:" su una riga, poi Nome e Cognome sulla riga sotto.
*/

#include <Arduino_SensorKit.h>  // Include la libreria del Sensor Kit.
// Questa libreria mette a disposizione l’oggetto 'Oled' (già pronto)
// per usare facilmente il display senza dover scrivere codice di basso livello (I2C).

void setup() {
Oled.begin();
// Inizializza il display OLED.
// Fa partire la comunicazione I2C e manda al display la sequenza di avvio.
// Senza questa riga lo schermo non mostra nulla.

Oled.setFlipMode(true);
// Ruota il contenuto di 180° (utile se lo vedi capovolto).
// Se nel tuo caso appare già dritto, puoi mettere false: Oled.setFlipMode(false);

Oled.setFont(u8x8_font_chroma48medium8_r);
// Sceglie il font (carattere) 8x8.
// Con un font 8x8 il display 128x64 si comporta come una griglia 16 colonne × 8 righe.
// Significa che setCursor(colonna, riga) userà numeri tra 0..15 (colonne) e 0..7 (righe).

Oled.clear();
// Pulisce lo schermo (cancella tutto quello che c’era prima).

Oled.setCursor(0, 2);
// Posiziona il cursore alla colonna 0, riga 2 (terza riga dall’alto).
// Le coordinate sono "a caratteri" (non in pixel).

Oled.print("Allievo:");
// Stampa il testo "Allievo:" nella posizione corrente.

Oled.setCursor(0, 4);
// Sposta il cursore alla riga 4 (quinta riga), colonna 0.
// Qui stamperemo nome e cognome.

Oled.print("Michele");
// Stampa il nome.

Oled.print(" ");
// Stampa uno spazio tra nome e cognome.

Oled.print("Maffucci");
// Stampa il cognome.

Oled.refreshDisplay();
// Aggiorna fisicamente lo schermo.
// Finché non richiami refreshDisplay(), il display potrebbe non mostrare i nuovi testi.
}

void loop() {
// Vuoto: non dobbiamo aggiornare nulla in continuazione.
// Il display mantiene il testo finché non lo cambiamo nel codice.
}

Esempio 1 – senza commenti

Nel caso servisse copiare ed incollare solamente il codice per poi inserire i propri commenti vi lascio anche la versione senza commenti:

#include <Arduino_SensorKit.h> 

void setup() {
Oled.begin();
Oled.setFlipMode(true);
Oled.setFont(u8x8_font_chroma48medium8_r);
Oled.clear();
Oled.setCursor(0, 2);
Oled.print("Allievo:");
Oled.setCursor(0, 4);
Oled.print("Michele");
Oled.print(" ");
Oled.print("Maffucci");
Oled.refreshDisplay();
}

void loop() {
}

Esempio 1 – avanzato

Versione con commenti per gli studenti in cui viene dettagliato il funzionamento di ogni parte del codice.

/*
Prof. Maffucci Michele
25/09/2025
Scrive nome e cognome dell’allievo sul display OLED del Sensor Kit.
- Usa la libreria Arduino_SensorKit (oggetto Oled).
- Dimostrazione uso di: const char*, Oled.begin(), setFlipMode, setFont, setCursor, print, clear, refreshDisplay.
*/
#include <Arduino_SensorKit.h>  // Include la libreria che espone l’oggetto 'Oled'.

// -----------------------------------------------------------------------------
// DICHIARAZIONE DELLE STRINGHE
// 'const char*' = puntatore a caratteri costanti (stringa C in sola lettura).
// Puntano a letterali con terminatore '\0' (durata statica, non vanno modificati).
// -----------------------------------------------------------------------------
const char* nomeAllievo = "Michele"; // sostituisci con il nome reale (es. "Luca")
const char* cognomeAllievo = "Maffucci"; // sostituisci con il cognome (es. "Rossi")

void setup() {
// ---------------------------------------------------------------------------
// INIZIALIZZAZIONE DEL DISPLAY
// Oled.begin() avvia l'I2C e programma il controller del display (SSD1306/1315).
// Senza questa chiamata, il display non mostrerà nulla.
// ---------------------------------------------------------------------------
Oled.begin();

// setFlipMode(true) ruota il contenuto di 180°.
// Usarlo se il testo appare "capovolto" a causa dell’orientamento fisico.
// Mettere false se già si vede diritto.
Oled.setFlipMode(true);

// Seleziona il font 8x8 "chroma48medium8_r".
// Con font 8x8, lo schermo 128x64 si comporta come una griglia 16 colonne × 8 righe.
Oled.setFont(u8x8_font_chroma48medium8_r);

// ---------------------------------------------------------------------------
// PULIZIA E STAMPA DEL CONTENUTO
// ---------------------------------------------------------------------------

// Cancella tutto il contenuto precedente del display.
Oled.clear();

// Posiziona il cursore (colonna=0, riga=2) in coordinate "a caratteri" (non pixel).
// (0,2) significa: prima colonna, terza riga della griglia 16x8.
Oled.setCursor(0, 2);

// Stampa un’etichetta. Con la macro F("...") il testo resta in flash (serve per risparmiare RAM).
Oled.print(F("Allievo:"));

// Vai a riga 4, colonna 0, e stampa nome + cognome separati da spazio.
Oled.setCursor(0, 4);
Oled.print(nomeAllievo); // stampa la stringa puntata da 'nomeAllievo'
Oled.print(" "); // spazio tra nome e cognome
Oled.print(cognomeAllievo);

// Aggiorna fisicamente lo schermo: senza refresh, la nuova scritta potrebbe non apparire.
Oled.refreshDisplay();
}

void loop() {
// Nessuna azione periodica: il display mantiene il contenuto finché non lo cambiate.
// (Se volete far lampeggiare o scorrere il testo, lo fareste nel loop)
}

Esempio 1 – avanzato – senza commenti

#include <Arduino_SensorKit.h> 

const char* nomeAllievo = "Michele";
const char* cognomeAllievo = "Maffucci";

void setup() {
Oled.begin();
Oled.setFlipMode(true);
Oled.setFont(u8x8_font_chroma48medium8_r);
Oled.clear();
Oled.setCursor(0, 2);
Oled.print(F("Allievo:"));
Oled.setCursor(0, 4);
Oled.print(nomeAllievo);
Oled.print(" ");
Oled.print(cognomeAllievo);
Oled.refreshDisplay();
}

void loop() {
}

Che cosa significa char*? Perché const char* qui?

  • char è il tipo carattere in C/C++ (1 byte).
  • char* è un puntatore a char: invece di contenere direttamente un carattere, contiene l’indirizzo di memoria dove si trova una sequenza di caratteri (una stringa in stile C).
  • Le stringhe letterali scritte tra virgolette, es. "Nome", sono array di char terminati da \0 (null terminator). Hanno durata statica: esistono per tutta l’esecuzione del programma e sono solitamente in sola lettura.

Per questo si usa:

const char* nomeAllievo = "Nome";
  • const indica che non vogliamo (e non dobbiamo) modificare quei caratteri (sono un letterale costante).
  • Il tipo completo si legge: “puntatore a char costanti“. Potete cambiare il puntatore (farlo puntare ad un’altra stringa), ma non i caratteri a cui punta.

Alternative possibili

  • const char nomeAllievo[] = "Nome";
    (array di char costanti: il compilatore conosce la lunghezza e non potete riassegnare il nome dell’array).
  • String nomeAllievo = "Nome";
    (classe Arduino String: comoda ma usa più RAM dinamica; in progetti grandi può frammentare l’heap).

Nota su Arduino/AVR: i letterali come "testo" possono occupare SRAM a runtime se non si usa la macro F("testo") o PROGMEM. Nel nostro sketch la dimensione è minuscola, ma per testi lunghi conviene Oled.print(F("Allievo:")) per risparmiare RAM.

A cosa serve Oled.begin()

Oled.begin() inizializza il display OLED del Sensor Kit. In pratica:

  • Avvia la comunicazione I²C verso il controller del display (SSD1306/SSD1315) all’indirizzo corretto.
  • Manda la sequenza di setup al controller (accensione, modalità, contrasto di base, orientamento di default, ecc.).
  • Prepara l’oggetto Oled a ricevere comandi come setCursor, print, clear, refreshDisplay.

Senza Oled.begin() il display non risponde ai comandi, quindi va chiamato una volta nel setup().

Esempio 2

Lettura del valore analogico del potenziometro, visualizza il valore numerico grezzo dell’ADC e del valore percentuale sul display con barra (a carattere) di avanzamento.

Collegare il potenziometro all’ingresso A0.

/*
Prof. Maffucci Michele
25/09/2025
OLED
- Leggere il valore analogico dal potenziometro (0..1023 su Arduino UNO).
- Converte il valore in percentuale (0..100%).
- Visualizza il valore grezzo (ADC), la percentuale e una barra orizzontale su OLED.

Note:
- Usiamo la libreria Arduino_SensorKit che fornisce l'oggetto 'Oled' (display SSD1306/1315 via I2C).
- La barra è disegnata come sequenza di caratteri ASCII ('#').
*/

#include <Arduino_SensorKit.h>  // Include l'API semplificata per i sensori e l'OLED del Sensor Kit

// --------------------- CONFIGURAZIONE INGRESSO ANALOGICO ---------------------
// PIN del potenziometro: collega il cursore del pot al pin A0 (e gli altri due capi a +5V e GND).
const int PIN_POT = A0;

// Variabili per memorizzare il valore letto (grezzo) e la percentuale calcolata.
int valoreADC = 0; // Gamma tipica su UNO: 0..1023 (10 bit)
int percento = 0; // 0..100 (%)

// L'OLED in modalità font 8x8 ha circa 16 colonne: la barra avrà da 0 a 16 "blocchi" pieni.
const uint8_t LARGHEZZA_BAR = 16;

// -----------------------------------------------------------------------------
// Funzione di utilità: disegna una barra percentuale su una riga 'y' del display.
// Parametri:
// - y: indice riga (0..7 se font 8x8; 0 è la prima riga in alto).
// - percent: valore 0..100 che determina la lunghezza della barra.
// -----------------------------------------------------------------------------
void disegnaBarraPercento(uint8_t y, uint8_t percent) {
// Converte la percentuale 0..100 nel numero di "blocchi" (0..16)
// (uint32_t) evita overflow nella moltiplicazione su microcontrollori a 16 bit.
uint8_t pieni = (uint32_t)percent * LARGHEZZA_BAR / 100;

// 1) Pulisce la riga della barra: stampa 16 spazi per "cancellare" ciò che c'era prima.
Oled.setCursor(0, y); // posiziona il cursore all'inizio riga
for (uint8_t i = 0; i < LARGHEZZA_BAR; i++) {
Oled.print(' '); // spazio = cella vuota
}

// 2) Ridisegna i "blocchi" pieni (da sinistra verso destra) usando un carattere visibile e portabile ('#').
Oled.setCursor(0, y); // torna all'inizio riga
for (uint8_t i = 0; i < pieni; i++) {
Oled.print('#'); // carattere della barra
}
}

void setup() {
// ------------------------ INIZIALIZZAZIONE OLED ----------------------------
Oled.begin(); // inizializza I2C e il controller del display
Oled.setFlipMode(true); // ruota 180° se il testo appare capovolto (mettere false se OK)
Oled.setFont(u8x8_font_chroma48medium8_r); // font 8x8: griglia circa 16 colonne × 8 righe

// Pulizia e titolo
Oled.clear(); // cancella lo schermo
Oled.setCursor(0, 0); // colonna 0, riga 0 (prima riga)
Oled.print("Potenziometro"); // titolo
Oled.refreshDisplay(); // aggiorna la visualizzazione
}

void loop() {
// ----------------------------- LETTURA ADC --------------------------------
// Per stabilizzare il valore (ridurre rumore), facciamo una media di 4 campioni.
long somma = 0;
for (int i = 0; i < 4; i++) { somma += analogRead(PIN_POT); // legge l'ingresso analogico A0: 0..1023 delay(2); // piccola pausa per lasciare stabilizzare } valoreADC = somma / 4; // media semplice dei 4 campioni // ----------------------- SCALATURA IN PERCENTUALE ------------------------- // 'map' converte da una scala a un'altra: qui 0..1023 > 0..100.
// Nota: 'map' restituisce un intero; per scale diverse potresti usare una formula float.
percento = map(valoreADC, 0, 1023, 0, 100);

// ----------------------------- STAMPA TESTO -------------------------------
// Riga 2: mostriamo il valore ADC grezzo.
Oled.setCursor(0, 2); // colonna 0, riga 2
Oled.print("ADC: "); // spazi finali per "coprire" cifre residue
Oled.setCursor(5, 2); // posiziona circa a metà riga
Oled.print(valoreADC); // valore numerico 0..1023

// Riga 3: mostriamo la percentuale.
Oled.setCursor(0, 3);
Oled.print("Perc: ");
Oled.setCursor(6, 3);
Oled.print(percento); // 0..100
Oled.print("%");

// ------------------------------ BARRA GRAFICA -----------------------------
// Disegna la barra percentuale alla riga 5 (sesta riga).
disegnaBarraPercento(5, percento);

// Aggiorna fisicamente il display (altrimenti potresti non vedere le modifiche).
Oled.refreshDisplay();

// Piccolo delay per fluidità; valori troppo bassi aumentano il "flicker",
// valori troppo alti rendono meno reattivo l'aggiornamento.
delay(60);
}

Buon Coding a tutti 🙂

Lezione 7 – Corso di Elettronica Creativa con Arduino Sensor Kit

Utilizzo del microfono analogico

In questa lezione vedremo come utilizzare il sensore di suono integrato nell’Arduino Sensor Kit, leggeremo il segnale analogico prodotto con l’istruzione analogRead() e ne interpreteremo i valori.
Verrà introdotto, in modo estremamente semplice il concetto di decibel e vedremo come procedere alla calibrazione del microfono in funzione delle attività di sperimentazione che verranno proposte.

Il microfono del Sensor Kit è pre‑cablat​o sulla linea analogica A0 tramite il connettore Grove, quindi non sono necessari ulteriori collegamenti.

Principio di funzionamento

Il modulo Grove Sound Sensor è un ottimo strumento per misurare i rumori intorno a voi. Quando l’aria vibra a causa di un suono, una sottile membrana nel microfono si piega avanti e indietro. Questi movimenti generano una variazione di tensione: più forte è il suono, più grande è la variazione e quindi più alto sarà il numero che andremo a leggere con Arduino mediante l’istruzione analogRead().

Approfondimento tecnico

Per chi ha qualche competenza in più in elettronica aggiungo che all’interno del modulo è presente un microfono a elettrete o microfono electret collegato a un piccolo amplificatore (LM358). L’amplificatore rende il segnale abbastanza grande da poter essere rilevabile da Arduino. Un circuito chiamato rivelatore di inviluppo converte le onde sonore in un valore di tensione continua che rappresenta l’intensità del suono istantaneo.

  • Il segnale in uscita varia da 0 V (silenzio) a 5 V (suono molto forte).
  • Arduino lo misura con il convertitore A/D a 10 bit, producendo numeri da 0 a 1023.
  • Il modulo è sensibile a frequenze fino a ~20 kHz (oltre il limite dell’udito umano).
  • L’amplificatore amplifica il segnale di circa 26 dB, così anche suoni deboli diventano misurabili.
  • Il consumo di corrente è basso, circa 4‑5 mA.

Nelle specifiche del dispositivo parlo di convertitore A/D a 10 bit e decibel (dB) e indico che l’amplificatore amplifica, in modo più semplice, ingrandisce di 26 dB, vediamo cosa vuol dire.

Qualche concetto tecnico spiegato in modo semplice

Cos’è un convertitore A/D a 10 bit

Un convertitore A/D (Analogico → Digitale) è come un traduttore: trasforma la tensione continua che esce dal sensore in numeri che il microcontrollore può elaborare.

10 bit significa che abbiamo 2¹⁰ = 1024 possibili valori, da 0 (0 V) a 1023 (5 V circa). Ogni “scalino” vale quindi circa 5 V / 1023 ≈ 0,005 V (5 millivolt). Più bit, più la scala è fine e la misura precisa.

Che cosa sono i decibel (dB) e perché l’amplificatore “ingrandisce” di 26 dB?

Il decibel (dB) è una grandezza adimensionale ed è un modo logaritmico di confrontare due grandezze: dice “quante volte più grande” è un segnale rispetto a un altro, ma usa il logaritmo per compattare numeri dimensionalmente diversi in una scala più gestibile. Inoltre il nostro orecchio non percepisce l’intensità del suono in modo lineare: se la potenza acustica raddoppia non ci sembra “due volte più forte”, ma solo un po’ più intensa. Questa risposta psicoacustica si descrive bene con una scala logaritmica, perciò usiamo i decibel.

Per le tensioni si usa la formula:

dB = 20 × log10(V2 / V1)

  • 0 dB ⇒ stessa tensione
  • +6 dB ⇒ tensione circa doppia
  • −6 dB ⇒ tensione circa metà

Dire che l’amplificatore aumenta il segnale di 26 dB significa che la tensione in uscita è circa 20× (volte) più grande di quella che entra (perché 20× ≈ 26 dB). Così anche un suono debole crea un segnale abbastanza grande da essere misurato da Arduino.

ATTENZIONE

Questo sensore è pensato per percepire la presenza di suoni e valutarne l’intensità, non per registrare l’audio né per misurazioni professionali in decibel. Per avere dati certificati servono microfoni calibrati e convertitori più veloci.

Esempio di base

/*
  Prof. Maffucci Michele
  24.06.25
  LED reagisce al suono
  Accende il LED sul pin 6 se il valore supera la soglia impostata.
*/

const int pinSuono   = A2;    // pin a cui è connesso il sensore
const int pinLED     = 6;     // LED del Sensor Kik
const int sogliaRumore = 200; // valore da calibrare in base all'ambiente

void setup() {
  pinMode(pinLED, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int livello = analogRead(pinSuono);
  bool rumoreForte;
  // per approfondimenti sui tipi di dati:
  // https://www.maffucci.it/2020/11/15/arduino-tipi-di-dati-ripasso/

if (livello > sogliaRumore) {
    rumoreForte = true;
  } else {
    rumoreForte = false;
  }

if (rumoreForte) {
    digitalWrite(pinLED, HIGH);  // se supera la soglia il LED viene acceso
  } else {
    digitalWrite(pinLED, LOW);   // se non supera la soglia il led viene mantenuto apento
  }

Serial.print("Livello: ");
  Serial.print(livello);
  Serial.print("  Rumore forte? ");
  Serial.println(rumoreForte ? "SI" : "NO");

delay(500);
}

Continua a leggere