
Nella scorsa lezione abbiamo visto come gestire un attuatore, un servomotore SG90, la cui rotazione non bloccava l’accensione di un LED controllata da un pulsante. Vediamo ora in questa breve lezione come gestire un sensore di temperatura e umidità DHT11. Nell’esempio che segue abbiamo 4 task che lavorano in multitasking nel seguente modo:
- TASK 1: Lampeggio LED su D9
- TASK 2: Pulsante su D2 (INPUT_PULLUP) + debounce -> commuta LED2 su D8
- TASK 3: Lettura DHT11 su D3 ogni 2000 ms (no blocchi nel loop)
- TASK 4: Stampa su Serial ogni 1000 ms dei valori letti (se validi)
Nota: il DHT11 è lento mi piace definirlo “capriccioso” 🙂 leggerlo troppo spesso può dare errori. Come già indicato in precedenti post, intervalli da 1–2 sec sono ideali.
Collegamenti
Ricordo che se usate il modulo DHT11 a 3 pin:
- VCC > 5V
- GND > GND
- DATA > D3 (nel codice)
Se invece usate il DHT11 a 4 pin che non è su breakoutboard , serve una resistenza di pull-up (tipicamente 10 kΩ) tra Vcc e DATA.
Per gli esempi è necessario installare la libreria DHT sensor library (Adafruit).
Nello sketch che segue il trucco “da multitasking” è la cache: leggiamo il DHT11 solo ogni 2 s (task 3), ma possiamo stampare i dati ogni 1 s (task 4) senza impegnare troppo il sensore e senza bloccare il loop.
Schema di collegamento

I commenti spiegano il funzionamento del codice.
Esempio 01
#include <DHT.h>
// DHT sensor library di Adafruit
/*
Prof. Maffucci Michele
16.03.26
=====================================================
MULTITASKING (senza delay)
- TASK 1: Lampeggio LED su D9
- TASK 2: Pulsante su D2 (INPUT_PULLUP) + debounce -> commuta LED2 su D8
- TASK 3: Lettura DHT11 su D3 ogni 2000 ms (no blocchi nel loop)
- TASK 4: Stampa su Serial ogni 1000 ms dei valori letti (se validi)
=====================================================
*/
// -----------------------
// PIN HARDWARE
// -----------------------
#define PIN_LED_LAMPEGGIO 9
#define PIN_LED_PULSANTE 8
#define PIN_PULSANTE 2
#define PIN_DHT 3
#define TIPO_DHT DHT11
// -----------------------
// OGGETTO DHT
// -----------------------
DHT dht(PIN_DHT, TIPO_DHT);
// -----------------------
// TIMING (millis)
// -----------------------
unsigned long tempoPrecedenteLed = 0; // TASK 1
unsigned long tempoPrecedenteDht = 0; // TASK 3
unsigned long tempoPrecedenteSerial = 0; // TASK 4
const unsigned long INTERVALLO_LED = 500;
const unsigned long INTERVALLO_DHT = 2000; // DHT11: non leggere troppo spesso
const unsigned long INTERVALLO_SERIAL = 1000;
// -----------------------
// STATI LED
// -----------------------
bool statoLedLampeggio = LOW;
bool statoLed2 = LOW; // LED su D8
// -----------------------
// DATI SENSORI (cache)
// Qui salviamo l'ultima lettura valida del DHT
// così possiamo stamparla quando vogliamo senza rileggere il sensore.
// -----------------------
float ultimaTemperatura = NAN;
float ultimaUmidita = NAN;
bool datiDhtValidi = false;
void setup() {
pinMode(PIN_LED_LAMPEGGIO, OUTPUT);
pinMode(PIN_LED_PULSANTE, OUTPUT);
// Pulsante con pull-up interna: a riposo HIGH, premuto LOW
pinMode(PIN_PULSANTE, INPUT_PULLUP);
// Stati iniziali
digitalWrite(PIN_LED_LAMPEGGIO, statoLedLampeggio);
digitalWrite(PIN_LED_PULSANTE, statoLed2);
Serial.begin(9600);
// Inizializza sensore DHT
dht.begin();
Serial.println("Avvio multitasking con DHT11 (senza delay)...");
}
void loop() {
taskLampeggioLed(); // TASK 1
taskLeggiPulsante(); // TASK 2
taskLeggiDht11(); // TASK 3
taskStampaSeriale(); // TASK 4
}
// =====================================================
// TASK 1: Lampeggio LED (non bloccante)
// =====================================================
void taskLampeggioLed() {
if (millis() - tempoPrecedenteLed >= INTERVALLO_LED) {
tempoPrecedenteLed = millis();
statoLedLampeggio = !statoLedLampeggio;
digitalWrite(PIN_LED_LAMPEGGIO, statoLedLampeggio);
}
}
// =====================================================
// TASK 2: Pulsante + debounce + toggle LED2 (non bloccante)
// =====================================================
void taskLeggiPulsante() {
static bool ultimaLettura = HIGH;
static bool statoStabile = HIGH;
static unsigned long ultimoCambio = 0;
const unsigned long RITARDO_DEBOUNCE = 50;
bool letturaAttuale = digitalRead(PIN_PULSANTE);
// Se cambia la lettura grezza, resetto il timer di debounce
if (letturaAttuale != ultimaLettura) {
ultimoCambio = millis();
ultimaLettura = letturaAttuale;
}
// Se la lettura resta stabile abbastanza, la consideriamo valida
if (millis() - ultimoCambio >= RITARDO_DEBOUNCE) {
if (letturaAttuale != statoStabile) {
statoStabile = letturaAttuale;
// Evento su pressione (INPUT_PULLUP: premuto = LOW)
if (statoStabile == LOW) {
statoLed2 = !statoLed2;
digitalWrite(PIN_LED_PULSANTE, statoLed2);
Serial.print("LED2 (D8) ora e': ");
if (statoLed2 == true) {
Serial.println("ACCESO");
} else {
Serial.println("SPENTO");
}
}
}
}
}
// =====================================================
// TASK 3: Lettura DHT11 (non bloccante nel progetto complessivo)
// Nota: la chiamata dht.read... impiega un po' di tempo, ma la eseguiamo
// solo ogni INTERVALLO_DHT, quindi non "congela" il progetto in modo percepibile.
// =====================================================
void taskLeggiDht11() {
if (millis() - tempoPrecedenteDht >= INTERVALLO_DHT) {
tempoPrecedenteDht = millis();
float umidita = dht.readHumidity();
float temperatura = dht.readTemperature(); // Celsius
// Controllo validità: se NAN, lettura fallita
if (isnan(umidita) || isnan(temperatura)) {
datiDhtValidi = false;
Serial.println("Errore lettura DHT11 (dato non valido).");
return;
}
// Salvo i valori come "ultima lettura valida"
ultimaUmidita = umidita;
ultimaTemperatura = temperatura;
datiDhtValidi = true;
}
}
// =====================================================
// TASK 4: Stampa su Serial (non bloccante)
// Stampa ogni secondo i dati più recenti "in cache".
// =====================================================
void taskStampaSeriale() {
if (millis() - tempoPrecedenteSerial >= INTERVALLO_SERIAL) {
tempoPrecedenteSerial = millis();
Serial.print("Blink D9 | LED2 D8: ");
Serial.print(statoLed2 ? "ON" : "OFF");
Serial.print(" | DHT11 -> ");
if (datiDhtValidi == true) {
Serial.print("T: ");
Serial.print(ultimaTemperatura, 1);
Serial.print(" C, U: ");
Serial.print(ultimaUmidita, 0);
Serial.println(" %");
} else {
Serial.println("dati non disponibili");
}
}
}
Il pulsante non “fa tutto”: genera un evento e mette una variabile (richiestaLetturaDht = true).
Un altro task esegue la lettura quando vede quella richiesta.
Vediamo ora una seconda versione in cui il DHT11 viene letto solo quando serve alla pressione pulsante di un pulsante-
Esempio 02
Come sappiamo il DHT11 è un sensore lento: non ha senso leggerlo in continuazione se vi serve solo su richiesta, quindi usiamo il pulsante come “richiesta”, quando premete, Arduino chiede una lettura al sensore. Per restare in multitasking, la pressione del pulsante non legge direttamente il DHT11, imposta solo un flag (una variabile) che dice: “Appena puoi, fai una lettura”, un task dedicato controlla questoa flag e fa la lettura.
Specifiche
- LED su D9 lampeggia ogni 500 ms;
- pulsante su D2 con INPUT_PULLUP;
- LED2 su D8 commuta ON/OFF ad ogni pressione;
- DHT11 su D3 viene letto solo quando premete;
- Serial stampa subito il risultato della lettura richiesta.
Importante
- Il pulsante non “fa tutto”: genera un evento e mette una variabile (richiestaLetturaDht = true);
- un altro task esegue la lettura quando vede quella richiesta;
#include <DHT.h>
// DHT sensor library di Adafruit
/*
Prof. Maffucci Michele
16.03.26
=====================================================
MULTITASKING (senza delay) - LETTURA DHT SU RICHIESTA
- TASK 1: Lampeggio LED su D9
- TASK 2: Pulsante (debounce) su D2 -> toggle LED2 su D8 + richiesta lettura DHT
- TASK 3: Lettura DHT11 su D3 SOLO quando richiesta
=====================================================
*/
// Pin
#define PIN_LED_LAMPEGGIO 9
#define PIN_LED2 8
#define PIN_PULSANTE 2
#define PIN_DHT 3
#define TIPO_DHT DHT11
DHT dht(PIN_DHT, TIPO_DHT);
// Timing LED
unsigned long tempoPrecLed = 0;
const unsigned long INTERVALLO_LED = 500;
bool statoLedLampeggio = LOW;
// Stato LED2
bool statoLed2 = LOW;
// "Richiesta" lettura DHT (bandierina)
bool richiestaLetturaDht = false;
void setup() {
pinMode(PIN_LED_LAMPEGGIO, OUTPUT);
pinMode(PIN_LED2, OUTPUT);
pinMode(PIN_PULSANTE, INPUT_PULLUP);
digitalWrite(PIN_LED_LAMPEGGIO, statoLedLampeggio);
digitalWrite(PIN_LED2, statoLed2);
Serial.begin(9600);
dht.begin();
Serial.println("Sketch A: DHT11 letto solo su richiesta (pressione pulsante).");
}
void loop() {
taskLampeggioLed(); // TASK 1
taskPulsante(); // TASK 2
taskLetturaDhtOnDemand(); // TASK 3
}
// -------------------------
// TASK 1: lampeggio LED
// -------------------------
void taskLampeggioLed() {
if (millis() - tempoPrecLed >= INTERVALLO_LED) {
tempoPrecLed = millis();
statoLedLampeggio = !statoLedLampeggio;
digitalWrite(PIN_LED_LAMPEGGIO, statoLedLampeggio);
}
}
// -------------------------
// TASK 2: pulsante + debounce
// - ad ogni pressione: toggle LED2
// - e chiede una lettura del DHT
// -------------------------
void taskPulsante() {
static bool ultimaLettura = HIGH;
static bool statoStabile = HIGH;
static unsigned long ultimoCambio = 0;
const unsigned long RITARDO_DEBOUNCE = 50;
bool letturaAttuale = digitalRead(PIN_PULSANTE);
if (letturaAttuale != ultimaLettura) {
ultimoCambio = millis();
ultimaLettura = letturaAttuale;
}
if (millis() - ultimoCambio >= RITARDO_DEBOUNCE) {
if (letturaAttuale != statoStabile) {
statoStabile = letturaAttuale;
// INPUT_PULLUP: premuto = LOW
if (statoStabile == LOW) {
// Toggle LED2
statoLed2 = !statoLed2;
digitalWrite(PIN_LED2, statoLed2);
Serial.print("Pulsante: LED2 ora e': ");
if (statoLed2 == true) Serial.println("ACCESO");
else Serial.println("SPENTO");
// Richiedo una lettura del DHT
richiestaLetturaDht = true;
Serial.println("Richiesta lettura DHT11...");
}
}
}
}
// -------------------------
// TASK 3: lettura DHT su richiesta
// - legge il sensore SOLO se richiestaLetturaDht è true
// - poi resetta la richiesta (così non legge di continuo)
// -------------------------
void taskLetturaDhtOnDemand() {
if (richiestaLetturaDht == false) return;
// Eseguo UNA lettura e poi azzero la richiesta
richiestaLetturaDht = false;
float umidita = dht.readHumidity();
float temperatura = dht.readTemperature(); // °C
if (isnan(umidita) || isnan(temperatura)) {
Serial.println("DHT11: lettura NON valida (riprovare).");
return;
}
Serial.print("DHT11 -> Temperatura: ");
Serial.print(temperatura, 1);
Serial.print(" C | Umidita: ");
Serial.print(umidita, 0);
Serial.println(" %");
}
Buon Making a tutti 🙂
