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:

Schema del circuito: termometro Arduino con termistore NTC 3950 10k e LCD I2C

Codice:

temp_lcd.ino
// 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.

Video dimostrazione: