problema calcolo temperatura con lm35

Ciao a tutti,

ho un problema con la rilevazione della temperatura ambientale con lm35

questo è lo sketc

#include <LiquidCrystal.h> //Libreria per pilotare il display LCD

#define pin_temp A0 //Pin di collegamento del piedino Vout del sensore di temperatura

float temp; //Variabile in cui verrà memorizzata la temperatura rilevata

LiquidCrystal lcd(7, 6, 5, 4, 3, 2); //Inizializzazione della libreria con i pin del display LCD

void setup()
{
lcd.begin(16, 2); //Impostazione del numero di colonne e righe del display LCD
lcd.setCursor(2, 0); //Sposto il cursore sulla prima riga (riga 0) e sulla prima colonna
lcd.print(“Temperatura:”); //Stampo il messaggio ‘Temperatura:’ sulla prima riga

/*Imposto Vref dell’ADC a 1,1V
(per una maggiore precisione nel calcolo della temperatura)

IMPORTANTE: Se utilizzi Arduino Mega sostituisci INTERNAL con INTERNAL1V1 */
analogReference(INTERNAL);
}

void loop()
{
/Calcolo la temperatura
=============================================
/

temp = 0;
for (int i = 0; i < 5; i++) { //Esegue l’istruzione successiva 5 volte
temp += (analogRead(pin_temp) / 9.31); //Calcola la temperatura e la somma alla variabile ‘temp’
}
temp /= 5; //Calcola la media matematica dei valori di temperatura
/===========================================/

/Visualizzo la temperatura sul display LCD
=============================================
/
lcd.setCursor(5, 1); //Sposto il cursore sulla prima colonna e sulla seconda riga
lcd.print(temp, 1); //Stampo sul display LCD la temperatura con “,1” imposto il numero di decimali dopo la virgola
lcd.print(" C"); //Stampo uno spazio e il carattere ‘C’ sul display
/===========================================/

delay(10000); //Ritardo di un secondo (può essere modificato)
}

dalla temperatura reale misurata con un comune termometro d’ambiente l’lm35 misura circa 5° in più!!!
Cosa può essere???

Cos'è quel "/ 9.31"? Vado a memoria, ma lm35 ha una uscita direttamente proporzionale ai gradi celsius

Mi aspetto qualcosa tipo (codice scritto senza un test, guardalo solo a livello indicativo)

float temp = ( (float) analogRead(tempPin) / 1024.0 ) *5000.0;

ovvero una semplice proporzione tra fondo scale (1024 come valore letto, 5V come valore reale )

EDIT scusa non avevo visto che avevi cambiato il fondoscala dell'ADC. probabilmente l'errore che hai è solo dovuto a tolleranze nei calcoli o l'ADC non ha il fondoscala che ti stai aspettando. Prova a tornare con il fondoscala standard a 5V, fare il loop una volta sola, e vedere che lettura hai, poi se funziona, aumenti la precisione cambiando fondoscala e la proporzione di conseguenza, e poi ti metti a fare più campionamenti e la relativa media.

Tieni i fili corti, un offset potrebbe arrivare da fonti esterne. Nei test collega la sonda immediatamente a ridosso dell'arduino.

ok quindi tolgo il comando

analogReference(INTERNAL);

per ripristinare l’ADC a 5v

e al posto di

temp = 0;
for (int i = 0; i < 5; i++) { //Esegue l’istruzione successiva 5 volte
temp += (analogRead(pin_temp) / 9.31); //Calcola la temperatura e la somma alla variabile ‘temp’
}
temp /= 5; //Calcola la media matematica dei valori di temperatura

ci metto

float temp = ( (float) analogRead(tempPin) / 1024.0 ) *5000.0;

e vedo che valore mi restituisce.

i fili di collegamento sono di pochi cm per fare questa prova ma quando funzionerà tutto dovrò separare l’arduino dal sensore con almeno 1m di cavo.
Il progetto finale prevede di comandare un relè che aziona una resistenza di un vecchio fornetto del mulino bianco per tenere una temperatura compresa tra 25° e 30°.
Una volta risolto il problema della lettura della temperatura implemento il codice che comanda il relè.
Visto che ci sei hai idea di come posso implementare quest’ultima parte?
in pratica la resistenza deve accendersi quando la temperatura scende sotto i 25° e spegnersi quando raggiunge i 30°

Sì fai quella prova. La tolleranza che vedevi di 5 gradi e un loop di 5 volte, mi puzza di errore di lettura di 1°C ad ogni loop. Tale errore può essere dovuto a

  • il riferimento che non è 1.1V come ti aspetti
  • il valore 9.31 è troppo approssimato (quindi devi usare più decimali, es: 0.93090909)
  • offset fisso sulla tensione (ADC con tolleranze, perdita di tensione per qualche problema ai fili o alla pcb)

Quindi devi partire togliendo tutto e inserire un fattore alla volta per trovare quella che è la causa

Per quanto riguarda il relé, non è niente di complicato, quacosa tipo

if(temp>30){
digitalWrite(13, LOW);
}else if(temp<25){
digitalWrite(13, HIGH);
}

ammettendo che il relè sia sul pin 13 (dico quello solo perché tante board hanno già un led su quel pin che ti può essere comodo)

Ti accorgerai presto che in realtà le cose saranno un po’ diverse. Il relé stacca a 30 ma per inerzia la temperatura salirà ancora un po’, e idem in discesa, la temperatura reale scenderà un po’ sotto ai 25

E’ possibile che dovrai quindi mettere due numeri leggermente differenti (es. 29 e 26).

Se è proprio tassativo che non si superino i 30.0° altrimenti si rompe qualcosa, allora devi cercare un algoritmo PID, ci sono parecchie librerie già pronte. L’algoritmo in questione non misura solo la temperatura in un dato istante ma il suo andamento nel tempo e quindi riesce a capire l’inerzia termica e agire in anticipo.

Con un PID, la temperatura è enormamente più stabile, ma per tarare i parametri ci vuole una enorme pazienza. Te lo sconsiglio vivamente se non hai necessità di estrema precisione.

Per pilotare il relè ti serve un transitor qualsiasi, perché il microcontrollore non ce la fa a pilotare direttamente la bobina nel relè. Ci sono mille schemi in rete, niente di complicato.
Oppure prendi una scheda già fatta che con pochi euro trovi su ebay e hai già tutto pronto.

per la temperatura non ho bisogno di precisione perchè il forno serve a tenere i manufatti in fibra di carbonio che produco e la resina non catalizza sotto i 15°.

Ho comprato questo relè che dovrebbe essere compatibile con arduino

http://www.ebay.it/itm/111677145711?_trksid=p2057872.m2749.l2649&ssPageName=STRK%3AMEBIDX%3AIT

Ma torniamo ora alla temperatura...

Con la tua riga di comando misura sempre quei 5° in più (oltretutto ho dovuto moltiplicare per 500 e non 5000) L'orologio l'ho messo per vedere la differenza di temperatura segnata

|500x375

La lettura multipla dell'ADC di Arduino serve ad eliminare il rumore della misura.

Ma farlo usando direttamente la conversione intero-float non è mai conveniente per la relativa imprecisione del calcolo float.

Meglio usare nel for il calcolo intero e solo alla fine fare la conversione.

Per la verità, usare la riduzione del rumore su un segnale che non varia di molto come quello della temperatura, non solo non serve, ma addirittura può peggiorare la misura.

Ti consiglio di eliminare, almeno per il momento, la riduzione del rumore.

Il segnale in uscita al LM35 varia di 10mV per ogni °C (a 100°C ottieni 1V), quindi supponendo che la temperatura non superi i 100°C puoi usare la analogReference(INTERNAL) per settare a 1.1V il fondo scala, migliorando la precisione di lettura.

Se, invece, la temperatura supera i 100° (max 150°) devi usare il riferimento NORMAL (5V).

modificando la divisione come segue la temperatura sembra essere corretta

float temp = ( (float) analogRead(pin_temp) / 1200 ) *500;

500 è giusto, avevo dimenticato che sono 10mV a grado Celsius e non 1mV.

1200 però non ha senso, serve proprio solo per far tornare i conti.

Ma nel test in foto avevi il loop in funzione o era una lettura singola?

Se era nel loop, può ancora aver senso come lettura cumulavita di errori, se fuori dal loop allora c'è qualcosa di grosso che non va.

Se non l'hai già fatto:

  • togli il for e leggi la temperatura singola.

se il valore ha senso, porta il riferimento analogico a 1.1V con l'apposito comando e modifica l'istruzione in

float temp = ( (float) analogRead(pin_temp) / 1024 ) *110;

(1024 / 110 = 9,309090909090909 ovvero quel "9,31" che avevi nel codice originale)

così facendo aumenti la precisione della lettura

Una volta che hai un valore decente il lettura singola, potrai poi fare letture multiple e relative medie.

Altra cosa che mi viene in mente: prova le varie porte analogiche che hai a disposizione (A1, A2 ecc) : se la lettura cambia al variare della porta, allora hai qualche rientro che falsa la lettura

in foto il loop lo avevo già tolto ed era lettura singola! Anche le prove che sto facendo ora sono tutte senza loop.

cambiando l'ingresso analogico il valore cambia di pochissimo ma siamo sempre lì...

a giorni mi dovrebbe arrivare un DHT11 e vedo se ho problemi anche con quello!

Prima di tutto il generatore interno a 1.1V degli AVR è si stabile e abbastanza pulito dal rumore, però non è preciso, la tolleranza è del +/-10% rispetto al valore nominale, ovvero la reale tensione può essere un valore qualunque compreso tra 1.2 e 1.0 V. Va da se che per fare una conversione precisa occorre conoscere quanto vale Aref, nel caso del generatore interno, dopo averlo attivato, questo valore è misurabile sul pin Aref con un multimetro. l'ADC fornisce valori interi, non ha alcun senso sommarli su un float e poi farne la media, introduce un ulteriore fattore d'errore, la somma e media la fai su un unsigned int, poi dividi il valore ottenuto per 10 e lo assegni ad un float per la visualizzazione con una cifra decimale.

ho misurato la tensione sul pin aref ed è di 4,68v

Questo spiega la lettura sfalsata. Non conosco nei dettagli la scheda (arrivo da altri microcontrollori e son qui "di passaggio"), probabilmente l'IC è sottoalimentato (non gli arrivano esattamente 5V e di conseguenza anche il riferimento non è 5V)

Hai più di una strada

  • la più semplice: passare ad un sensore che dia in uscita un valore digitale e quindi, non essendo analogico, non risente delle stravaganze del ADC (non ricordo di preciso ma mi pare ch eil DHT11 sia così), ma anche un DS18S20 va bene ed è molto facile da reperire (tra l'altro cè un modo di farlo lavorare con solo due fili)

  • "starare" il sensore: fare artificialmente leggere il valore di un altro termometro manipolando le costanti (la precisione va a farsi benedire ma non è una richiesta fondamentale per il tuo progetto

  • usare un regolatore esterno per dare un riferimento fisso e sicuro in tensione su fui fare il confronto

visto che sono in attesa che mi arrivi il DHT11 farò delle prove con quello…

oltretutto ho notato che non è nemmeno stabile… ora ad esempio sta segnando 40° quando ce ne sono 25,4°

Con il DHT11 avrai problemi di precisione e range della temperatura (max 50°C):

Humidity Temperature Range Accuracy Range Accuracy Resolution 20-90%RH ±5%RH 0-50℃ ±2℃ 1

Si ho visto e i 2° di tolleranza mi stanno benissimo

Edit:
avere il vref non esattamente a 5v può dipendere dalla qualità della basetta o da qualche difetto sulla stessa? Magari con una originale posso risolvere questo problema?

Secondo me c'è qualcosa che non va, magari un cattivo contatto sulla breadboard: non può segnare 40°C quando la temperatura dovrebbe essere 25.4°C.

Hai seguito il mio consiglio di rimuovere il for nel loop ed inserito un ritardo tra le letture di 1 secondo (1000ms)?

Riposta lo sketch che stai usando.

Questo è lo sketch che sto utilizzando

oltretutto ho collegato il modulo relè per testare il tutto e sembra che ci ciano problemi di eccessivo assorbimento di corrente quando arduino cerca di azionare il relè… eppure il modulo è fatto apposta per arduino!!

#include <LiquidCrystal.h> //Libreria per pilotare il display LCD

#define pin_temp A5 //Pin di collegamento del piedino Vout del sensore di temperatura

float temp; //Variabile in cui verrà memorizzata la temperatura rilevata

LiquidCrystal lcd(7, 6, 5, 4, 3, 2); //Inizializzazione della libreria con i pin del display LCD

void setup()
{
  lcd.begin(16, 2); //Impostazione del numero di colonne e righe del display LCD
  lcd.setCursor(2, 0); //Sposto il cursore sulla prima riga (riga 0) e sulla prima colonna
  lcd.print("Temperatura:"); //Stampo il messaggio 'Temperatura:' sulla prima riga
pinMode(12, OUTPUT);
 
 //analogReference(INTERNAL);
}

void loop()
{
  
 /*===========================================*/
  /*Calcolo la Temperatura
  =============================================*/
 //temp = 0;
//for (int i = 0; i < 5; i++) { //Esegue l'istruzione successiva 5 volte
  //temp += (analogRead(pin_temp) / 9.31); //Calcola la temperatura e la somma alla variabile 'temp'
 //}
//temp /= 5; //Calcola la media matematica dei  valori di temperatura
  
  float temp = ( (float) analogRead(pin_temp) / 1024 ) *500; 
  
  /*===========================================*/
  /*Visualizzo la temperatura sul display LCD
  =============================================*/
  lcd.setCursor(5, 1); //Sposto il cursore sulla prima colonna e sulla seconda riga
   lcd.print(temp, 1); //Stampo sul display LCD la temperatura con ",1" imposto il numero di decimali dopo la virgola
  lcd.print(" C"); //Stampo uno spazio e il carattere 'C' sul display
  /*===========================================*/

  /*===========================================*/
  /*Comando la resistenza
  =============================================*/
  digitalWrite(13, LOW);
  if(temp>30){
 digitalWrite(12, HIGH);
}else if(temp<25){
 digitalWrite(12, LOW);
}


delay(1000); //Ritardo di un secondo (può essere modificato)
}

Prova a scrivere:

temp = analogRead(pin_temp) * 5.0 / 1023; // tensione in volt se Aref = 5V temp = analogRead(pin_temp) * 1.1 / 1023; // tensione in volt se Aref = 1.1V

temp *= 100; // 10mV/°C

Non capisco a cosa serva: digitalWrite(13, LOW);

si è vero ho dimenticato di cancellare digitalWrite(13, LOW); non serve a nulla

proverò prima con Aref a 5v

Intanto mi è arrivato un altro arduino uno originale e sul pin Aref misuro 4.78v, è normale? o magari è il mio multimetro che dopo svariati anni di utilizzo ha deciso di andare in pensione?

Se il multimetro è analogico o comunque a bassa impedenza (< 1MOhm), è possibile che legga male il valore di Aref (l’impedenza del multimetro diventa un carico per Aref, che ha una resistenza di 32k integrata nel microcontrollore)

Relé: hai 3 connessioni da fare: +5V, massa, accensione relé

La 5V a disposizione ha corrente più che sufficiente a pilotare un relè ed il display. Quindi o hai sbagliato a prelevare i 5V (prendi nel punto sbagliato) o hai una scheda (o collegamenti sulla breadboard) difettosi