Come costruire un termometro con Arduino, termistore NTC e LCD
Descrizione
Questo progetto è un termometro digitale basato su una scheda Arduino, un display LCD 16x2 I2C e un termistore NTC 3950 10k collegato al pin analogico A0 tramite una resistenza di pull-up da 10k. Arduino legge il partitore di tensione formato dalla resistenza di pull-up e dal termistore, calcola la resistenza del termistore, la converte in temperatura Celsius usando l’equazione Beta e mostra il risultato sul display LCD con un simbolo personalizzato dei gradi. Grazie all’interfaccia I2C, il display richiede solo due linee di comunicazione, rendendo il cablaggio semplice e lasciando più pin liberi. Il progetto è utile per imparare l’uso dei termistori, dei partitori di tensione analogici, dei display LCD I2C, dei caratteri personalizzati e della misura della temperatura con Arduino.
Componenti necessari:
- 1x Arduino UNO
- 1x Display LCD 16x2 con modulo I2C integrato
- 1x Termistore NTC 3950 10k
- 1x Resistenza di pull-up da 10k
- Cavi jumper (breadboard opzionale)
Schema:
Codice:
// https://nemiatools.com
#include <Wire.h> // Includi la libreria di comunicazione I2C
#include <LiquidCrystal_I2C.h> // Includi la libreria LCD I2C
#include <math.h> // Includi la funzione logaritmo
LiquidCrystal_I2C lcd_1(0x27, 16, 2); // Oggetto LCD
#define THERMISTOR_PIN A0 // Pin di segnale del termistore
const float PULLUP_RESISTOR = 10000.0; // Resistenza di pull-up da 10k
const float NOMINAL_RESISTANCE = 10000.0; // Resistenza NTC a 25°C
const float NOMINAL_TEMPERATURE_K = 25.0 + 273.15; // 25°C in Kelvin
const float BETA_COEFFICIENT = 3950.0; // Valore beta del NTC 3950
byte degree_symbol[8] = { // Simbolo di grado
B00110, // Riga 1
B01001, // Riga 2
B01001, // Riga 3
B00110, // Riga 4
B00000, // Riga 5
B00000, // Riga 6
B00000, // Riga 7
B00000 // Riga 8
};
float readTemperatureC() { // Legge la temperatura dal termistore
float adcValue = analogRead(THERMISTOR_PIN); // Legge il valore analogico del partitore
if (adcValue <= 0) adcValue = 1; // Evita divisioni per zero
if (adcValue >= 1023) adcValue = 1022; // Evita divisioni per zero
float thermistorResistance = PULLUP_RESISTOR * adcValue / (1023.0 - adcValue); // Calcola la resistenza del NTC
float temperatureK = 1.0 / ( // Converte la resistenza in Kelvin
(1.0 / NOMINAL_TEMPERATURE_K) +
(1.0 / BETA_COEFFICIENT) * log(thermistorResistance / NOMINAL_RESISTANCE)
);
return temperatureK - 273.15; // Restituisce la temperatura in Celsius
}
void setup()
{
lcd_1.init(); // Inizializza il display LCD
pinMode(THERMISTOR_PIN, INPUT); // Ingresso del partitore del termistore
lcd_1.backlight(); // Attiva la retroilluminazione
lcd_1.createChar(0, degree_symbol); // Crea il simbolo di grado
lcd_1.setCursor(3, 0); // Prima riga
lcd_1.print("TERMOMETER"); // Mostra il titolo
lcd_1.setCursor(2, 1); // Seconda riga
lcd_1.print("by Nemiatools"); // Mostra l'autore
delay(3000); // 3 secondi per la schermata iniziale
lcd_1.clear(); // Cancella il display
lcd_1.setCursor(0, 0); // Prima riga
lcd_1.print("Temperature:"); // Testo statico
lcd_1.setCursor(10, 1); // Posizione del simbolo di grado
lcd_1.write(byte(0)); // Scrive il simbolo di grado
lcd_1.setCursor(11, 1); // Posizione dell'unità
lcd_1.print("C"); // Unità in gradi Celsius
}
void loop()
{
lcd_1.setCursor(3, 1); // Posizione del valore della temperatura
lcd_1.print(" "); // Cancella il valore precedente
lcd_1.setCursor(3, 1); // Torna alla posizione del valore
lcd_1.print(readTemperatureC(), 1); // Stampa la temperatura con un decimale
delay(500); // Aggiorna due volte al secondo
}
Come funziona:
Questo progetto usa Arduino per creare un termometro con un termistore NTC 3950 10k e un display LCD 16x2 I2C. Il termistore non invia direttamente un valore di temperatura: la sua resistenza cambia con la temperatura, e Arduino trasforma questa variazione elettrica in gradi Celsius.
Le righe #include <Wire.h> e #include <LiquidCrystal_I2C.h> aggiungono le librerie necessarie per il display. Wire.h abilita la comunicazione I2C, mentre LiquidCrystal_I2C.h fornisce le funzioni per inizializzare l’LCD, spostare il cursore, stampare testo, accendere la retroilluminazione e creare caratteri personalizzati.
L’interfaccia I2C è utile perché un normale LCD 16x2 senza adattatore richiede diversi pin di Arduino, mentre la versione I2C usa solo SDA e SCL per la comunicazione. In questo modo il cablaggio è più pulito e restano più pin disponibili per sensori o altri moduli.
La riga LiquidCrystal_I2C lcd_1(0x27, 16, 2); crea l’oggetto LCD. Il valore 0x27 è l’indirizzo I2C del display, mentre 16 e 2 indicano che il display ha 16 colonne e 2 righe.
La riga #include <math.h> viene aggiunta perché la conversione del termistore usa la funzione logaritmo log(). Questa funzione serve nell’equazione Beta usata per convertire la resistenza del termistore in temperatura.
La riga #define THERMISTOR_PIN A0 definisce il pin analogico usato per leggere il circuito del termistore. In questo progetto, il pin di segnale è collegato a un partitore di tensione formato da una resistenza di pull-up da 10k e dal termistore NTC 3950 10k.
La resistenza di pull-up è collegata tra il punto di segnale e VCC, mentre il termistore è collegato tra il punto di segnale e GND. Arduino legge quindi la tensione nel punto centrale del partitore. Quando la temperatura aumenta, la resistenza del NTC diminuisce e anche la tensione letta su A0 diminuisce.
Le costanti PULLUP_RESISTOR, NOMINAL_RESISTANCE, NOMINAL_TEMPERATURE_K e BETA_COEFFICIENT descrivono il circuito del sensore. Per questo NTC, la resistenza nominale è 10k a 25°C e il valore Beta è 3950.
L’array byte degree_symbol[8] crea un simbolo personalizzato dei gradi per l’LCD. Un display LCD 16x2 può memorizzare piccoli caratteri personalizzati formati da 8 righe di pixel, e questo simbolo viene poi stampato prima della lettera C.
Dentro setup(), il display viene inizializzato con lcd_1.init();, la retroilluminazione viene attivata con lcd_1.backlight(); e il simbolo personalizzato viene salvato con lcd_1.createChar(0, degree_symbol);. La prima schermata mostra il titolo del progetto per tre secondi, poi l’LCD viene cancellato e preparato alla lettura della temperatura.
La parte più importante del codice è la funzione readTemperatureC(). Essa parte da analogRead(THERMISTOR_PIN), che legge la tensione su A0 e la converte in un numero da 0 a 1023.
Le righe if (adcValue <= 0) adcValue = 1; e if (adcValue >= 1023) adcValue = 1022; proteggono il calcolo da divisioni impossibili. Questo è utile perché la formula della resistenza contiene 1023.0 - adcValue al denominatore.
La riga float thermistorResistance = PULLUP_RESISTOR * adcValue / (1023.0 - adcValue); calcola la resistenza del termistore. La formula deriva direttamente dal partitore di tensione: siccome il termistore è collegato a GND e la resistenza da 10k è il pull-up, la lettura analogica è proporzionale a Rntc / (Rpullup + Rntc).
Dopo aver trovato la resistenza, il codice usa l’equazione Beta nella riga float temperatureK = 1.0 / ((1.0 / NOMINAL_TEMPERATURE_K) + (1.0 / BETA_COEFFICIENT) * log(thermistorResistance / NOMINAL_RESISTANCE));. Questa formula converte il rapporto di resistenza in temperatura assoluta in Kelvin.
La riga return temperatureK - 273.15; converte i Kelvin in gradi Celsius. Questo è il valore finale stampato sul display LCD.
Dentro loop(), il codice cancella solo l’area numerica della seconda riga, riporta il cursore nella posizione della temperatura e stampa readTemperatureC() con una cifra decimale. Il simbolo dei gradi e la lettera C restano fissi sul display.
Nel complesso, il progetto funziona leggendo un partitore di tensione, calcolando la resistenza del termistore, convertendo quella resistenza in temperatura e mostrando il risultato sul display LCD I2C.
Per letture corrette, la formula presuppone che il circuito usi una resistenza di pull-up da 10k verso VCC e il termistore NTC verso GND. Se resistenza e termistore vengono invertiti, la formula della resistenza deve essere modificata. Su alcuni moduli LCD potrebbe anche essere necessario cambiare l’indirizzo I2C da 0x27 a 0x3F.
Troubleshooting: temperatura visualizzata errata
Se il display LCD mostra una temperatura chiaramente errata anche se i collegamenti sono corretti, una delle cause più probabili è che la resistenza nominale del termistore sia diversa da quella impostata nel codice. Questo progetto è configurato per un termistore NTC da 10k, quindi nel codice viene usato NOMINAL_RESISTANCE = 10000.0.
Per verificare il termistore, scollegalo dal circuito e misura la sua resistenza con un multimetro a temperatura ambiente, possibilmente il più vicino possibile a 25°C. Il valore misurato non deve essere necessariamente identico al valore nominale, perché i termistori hanno una tolleranza e la loro resistenza varia sensibilmente con la temperatura. Usa quindi la misura per individuare il valore nominale standard più probabile. Per esempio, se a temperatura ambiente misuri circa 80 kΩ, è molto più probabile che il termistore sia un NTC da 100k piuttosto che uno da 10k.
In questo caso, modifica nel codice la resistenza nominale del termistore da 10000.0 a 100000.0: const float NOMINAL_RESISTANCE = 100000.0;. Non modificare invece PULLUP_RESISTOR a meno che anche la resistenza fissa di pull-up realmente montata nel circuito abbia un valore diverso. Dopo aver caricato il codice modificato, confronta la temperatura visualizzata con un riferimento noto a temperatura ambiente.