Termometro digitale con PIC18F e Display LCD

Termometro digitale con PIC18F e Display LCDSchema e Codice per Realizzare un Termometro Digitale con Display LCD. Disponibile in Versione Semplice e in Versione più Accurata…

 
 
 
 




 

INTRO
Vi sono svariati modi di misurare la temperatura e svariati sensori, in questo articolo verrà spiegato il funzionamento del sensore LM35 e verrà illustrato il codice in C per convertire il valore analogico di temperatura acquisito e per visualizzarlo su un display LCD. Peculiarità di questo schema è che permette di visualizzare la temperatura con una cifra dopo la virgola con una precisione di 0.5°C. Inoltre sono illustrate due versioni, una semplice e una precisa.

 




 
LM35
È un sensore di temperatura con uscita analogica proporzionale alla temperatura in gradi centigradi, in particolare permette di avere 10mV per ogni grado, permette inoltre di misurare temperature in un range da -55°C a 150°C anche se non tutte le versioni. Ha un accuratezza di 0.5°C e può essere alimentato con tensioni da 4V ad un massimo di 30V.

Può essere connesso come indicato di seguito; Nel primo caso permette di misurare temperature da 2°C a 150°C, nel secondo caso permette di misurare anche tensioni negative.

lm35_1

È disponibile in molti package ma per questo progetto si userà il package TO-92.

Ad esempio se ho una temperatura di 30°C se ben connesso il sensore mi da in uscita 300mV, questo teoricamente, poi vi saranno una serie di errori del sensore e di rumori sulla linea che fan si che questo valore si discosti da quello ideale.

 
ADC del PIC18F252
Il PIC18F252 dispone di un ADC a 5 canali che permette di convertire i valori analogici in un range che va da 0V a VCC con una risoluzione di 10bit. Avere una risoluzione di 10bit significa che se il PIC18F252 è alimentato a 5V il passo di quantizzazione sarà:

EQ1Il primo passo di quantizzazione è compreso tra 0V e Q/2, quindi tensioni minori di 2,4428mV vengono convertite con una valore 0000000000, mentre per avere l’aumento di un bit del codice di uscita devo avere incrementi superiori ai 4,88mV. Il nostro sensore restituisce 10mV/°C quindi l’ADC non riuscirà a discriminare meno di 0.5°C.

Supponiamo di avere 23°C ovvero 230mV convertiti in uscita dal sensore, questo valore verrà convertito col codice 00101111 equivalente al numero decimale 47. Se moltiplico per 0.48828 ottengo un valore di 22.949 che poi convertito in intero diventa 22, quindi l’LCD mi indica 22°C. Se invece abbiamo 23.5°C ovvero 235mV teorici, l’ADC li converte con il codice 00110000 ovvero 48, se moltiplico per 0,48828 ovvero il valore per passare da byte a decimale ottengo 23.437 che verranno visti come 23°C. Purtroppo in queste condizioni vi sono degli errori di conversione e di approssimazione che non si riescono ad eliminare, in ogni caso l’errore massimo è di circa 1°C nella visualizzazione.

Per ovviare a questo errore vi sono molte soluzioni. Verrà illustrata la più semplice che consiste nell’amplificare il segnale in uscita dal LM35 di un fattore 2, vediamo cosa succede:

Supponiamo di avere 23°C e di moltiplicare X2, questa volta in ingresso all’ADC vi saranno 460mV che convertiti diventano 01011110 che in decimale è il numero 94, questa volta visto che abbiamo raddoppiato il segnale invece di moltiplicare per 0,48828 moltiplicheremo per metà di questa quantità ottenendo 94*0,24414=22,9 che questa volta non verrà convertito in intero ma verrà visualizzato così come è ottenendo un errore di 0.1°C.

Se invece ho 23.5°C avrò 470mV che in digitale diventa il codice 01100000 ovvero 96 che moltiplicato per il fattore 0.24414 diventa 23,4. Questo errore scompare per tensioni più grandi, dai 50°C in su non è presente, quindi si può pensare di lasciare un piccolo errore se si ha una scala di misura grande (anche perché già il sensore ha un errore di 0,5°) oppure si può fare una correzione software se si misurano tensioni basse sommando al valore 0.1 prima di visualizzarlo.

Per ottenere precisioni migliori si può andare a fornire un riferimento preciso all’ADC del PIC18F252, come ad esempio una tensione di 2.56V. Però in questo caso il sensore è meno preciso del sistema se si utilizza lo schema più preciso presentato sotto, quindi non c’è bisogno di creare riferimenti di tensione.

 
LCD 16×2
Per visualizzare la temperatura si usa in questo caso un display 16×2 ovvero un display che dispone di due righe composte ognuna da 16 caratteri.

LCD16x2

Mikroc dispone di una libreria per pilotare l’LCD, i comandi sono:

sbit LCD_RS at RB4_bit;    // Lcd pinout settings

sbit LCD_EN at RB5_bit;

sbit LCD_D7 at RB3_bit;

sbit LCD_D6 at RB2_bit;

sbit LCD_D5 at RB1_bit;

sbit LCD_D4 at RB0_bit;

 

sbit LCD_RS_Direction at TRISB4_bit;   // Pin direction

sbit LCD_EN_Direction at TRISB5_bit;

sbit LCD_D7_Direction at TRISB3_bit;

sbit LCD_D6_Direction at TRISB2_bit;

sbit LCD_D5_Direction at TRISB1_bit;

sbit LCD_D4_Direction at TRISB0_bit;

Lcd_Init();

Queste istruzioni indicano alla libreria come sono connessi tra loro l’LCD e il microchip, il pin RS del LCD è connesso al pin RB4, il pin EN del LCD è connesso al pin RB5 e così via. Inoltre indicano che viene fatta una connessione utilizzando solo 4 bit, un pò più lenta come connessione ma che richiede meno linee di connessione. Infine Lcd_Init(); abilita l’LCD e inizializza le istruzioni base.

Lcd_Out(1, 3, “Hello!”);

Questa istruzione serve per scrivere la stringa “Hello!” sulla prima riga partendo dalla posizione 3.

Lcd_Out_Cp(“Here!”);

Serve a scrivere nella posizione corrente del cursore la stringa “Here!”. Il cursore si muove da sinistra a destra per ogni riga e arrivato alla fine ricomincia.

Lcd_Chr(2, 3, ‘i’); Lcd_Chr_Cp(‘i’);

Serve a scrivere un singolo carattere o in posizione 2,3 nel primo caso oppure nella posizione corrente del cursore nel secondo caso.

Lcd_Cmd(_LCD_CLEAR);

Con Lcd_Cmd si inviano i comandi all’LCD tra i qui vi sono i comandi _LCD_FIRST_ROW per spostare il cursore sulla prima riga, _LCD_CLEAR per pulire il display, _LCD_TURN_ON per accendere il display ed _LCD_SHIFT_LEFT per spostare a sinistra il cursore. Premendo su F1 in Mikroc si accede all’Help dove vi sono indicati molti più comandi.

 




 
TERMOMETRO SEMPLICE
Per realizzare un display semplice ma meno accurata del termometro si utilizza direttamente in ingresso all’ADC il segnale in uscita dal sensore senza amplificatore. In questo caso, come visto in precedenza nella discussione su l’ADC, si avrà un errore di massimo 1°C.

 
SCHEMA
Lo schema è molto semplice.

SCHEMA SEMPLICE

Il sensore LM35 è alimentato con una tensione di 5V e l’uscita del sensore è connesso al PIN2 che è il primo canale dell’ADC. Il PIN1 bisogna portare un livello logico alto per evitare che il PIC18F252 si resetti, questo viene fatto con una resistenza di pull-up da 10KΩ. Il circuito di oscillazione è composto dal risuonatore al quarzo X1 e dai condensatori C1 e C2.

La resistenza variabile RV1 serve per la regolazione del contrasto dell’LCD che viene alimentato anch’esso a 5V. Nello schema manca l’alimentazione della retroilluminazione dell’LCD che viene fatta collegano il catodo a massa e l’anodo a VCC interponendo però una resistenza da 470Ω.

Il PIC18F252 viene alimentato a 5V collegando i PIN8 e PIN19 a massa e il PIN20 a VCC.

Il PCB è il seguente ed è scaricabile:

PCB SEMPLICE

 




 
CODICE
Prima di tutto nel codice bisogna inizializzare l’LCD e le variabili necessarie per il programma. Poi si crea una sotto porzione di codice per pilotare l’LCD, questa sottofunzione riceve una stringa che contiene il dato di temperatura e vi aggiunge “°C”. Poi viene inizializzato L’adc e in un ciclo infinito si vanno a fare le seguenti istruzioni:

  1. Leggo il dato dall’ADC
  2. Moltiplico il dato acquisito per 0.48828 visto che Q=4.8828mV
  3. Converto il valore in intero e poi lo converto in stringa
  4. Richiamo il sottoprogramma per la scrittura della temperatura su l’LCD
  5. Faccio un delay di 500ms per avere due letture al secondo

Il codice è il seguente:

sbit LCD_RS at RB5_bit;                     // Configurazione Pin I/O
sbit LCD_EN at RB4_bit;                     //Indico alla libreria
sbit LCD_D4 at RB3_bit;                     //come è connesso l'LCD
sbit LCD_D5 at RB2_bit;
sbit LCD_D6 at RB1_bit;
sbit LCD_D7 at RB0_bit;


sbit LCD_RS_Direction at TRISB5_bit;        //Indico se ho ingressi o uscite
sbit LCD_EN_Direction at TRISB4_bit;
sbit LCD_D4_Direction at TRISB3_bit;
sbit LCD_D5_Direction at TRISB2_bit;
sbit LCD_D6_Direction at TRISB1_bit;
sbit LCD_D7_Direction at TRISB0_bit;

unsigned int short adcvalue;              //Variabile valore uscita da ADC
unsigned short int Tem1;                  //Variabile temperatura da
float Tem;                                //Valore convertito della temperatura
char Text[7];                             //Stringa contenente la temperatura


 void print_temp(char text){        //Sottoprogramma per la visualizzazione della temperatura
  Lcd_Cmd(_LCD_SECOND_ROW);         //invia cursore sulla seconda riga
  Lcd_Out_Cp(text);                 //scrivi la parte intera della temperatura
  Lcd_Chr_Cp(223);                  //codice per scrivere il simbolo di grado °
  Lcd_Chr_Cp('C');                  //scrivi C
}


void main(){                        //Programma principale

  Lcd_Init();                         // Initializza LCD
  Lcd_Cmd(_LCD_CLEAR);                // Pulisci LCD
  Lcd_Cmd(_LCD_CURSOR_OFF);           // Cursore non visibile

  Lcd_Out(1,2,"TEMPERATURA:");        //Scrivi la stringa TEMPERATURA sulla prima riga

  ADC_Init();                         // Initializza il modulo ADC con valori di default


  while(1){                 //Ciclo infinito

    adcvalue = ADC_Get_Sample(0);      //Lettura da ADC
    Tem = 0.48828 * adcvalue;          //Conversione da Byte a Decimale
    Tem1 = Tem;                        //conversione in intero

    IntToStr( Tem1, Text );            //conversione in stringa
    print_temp(text);                  //Invia i valori da visualizzare al sottoprogramma

    delay_ms(500);
  }
}

 
REALIZZAZIONE
Il progetto è stato realizzato su breadbord come si può vedere in foto:

Termometro semplice

 
TERMOMETRO PRECISO
Per realizzare una versione più precisa, con un errore massimo di circa 0.3°C è necessario amplificare il segnale in uscita. Per fare ciò si usa un op-amp, come ad esempio LM358, in configurazione non invertente, come visibile sullo schema. Ovviamente anche il codice subirà delle modifiche rispetto al precedente per tenere conto dell’amplificazione del segnale e per visualizzare la cifra dopo la virgola.

 

SCHEMA

SCHEMA PRECISO

 

PCB

PCB PRECISO

 
CODICE

La prima parte del codice è uguale identica a quella del primo caso, solo che questa volta varia il sottoprogramma di scrittura su LCD.

Il sottoprogramma riceve un char contenente la parte intera della temperatura e riceve un intero che rappresenta la prima cifra dopo la virgola. Dopo di che il programma stampa la parte intera della temperatura, un punto, la cifra decimale e poi la stringa “°C”.

In questo caso, vista l’amplificazione del segnale in ingresso per 2, invece di moltiplicare per 0.48828 moltiplico per la metà di questo valore ovvero 0.24418.

Il codice è il seguente:

sbit LCD_RS at RB5_bit;                     // Configurazione Pin I/O
sbit LCD_EN at RB4_bit;                     //Indico alla libreria
sbit LCD_D4 at RB3_bit;                     //come è connesso l'LCD
sbit LCD_D5 at RB2_bit;
sbit LCD_D6 at RB1_bit;
sbit LCD_D7 at RB0_bit;


sbit LCD_RS_Direction at TRISB5_bit;        //Indico se ho ingressi o uscite
sbit LCD_EN_Direction at TRISB4_bit;
sbit LCD_D4_Direction at TRISB3_bit;
sbit LCD_D5_Direction at TRISB2_bit;
sbit LCD_D6_Direction at TRISB1_bit;
sbit LCD_D7_Direction at TRISB0_bit;

unsigned int adcvalue;                    //Variabile valore uscita da ADC
unsigned short int Tem1, Dec1;                  //Variabile temperatura
float Tem;                                //Valore convertito della temperatura
float Dec;
char Text[7];                             //Stringa contenente la temperatura


 void print_temp(char Text, unsigned short int Dec1){        //Sottoprogramma per la visualizzazione della temperatura
  Lcd_Cmd(_LCD_SECOND_ROW);         //invia cursore sulla seconda riga
  Lcd_Out_Cp(text);                 //scrivi la parte intera della temperatura
  Lcd_Chr_Cp('.');                 //scrivi la parte intera della temperatura
  Lcd_Chr_Cp(Dec1);                 //scrivi la parte inter
  Lcd_Chr_Cp(223);                  //codice per scrivere il simbolo di grado °
  Lcd_Chr_Cp('C');                  //scrivi C
}


void main(){                        //Programma principale

  Lcd_Init();                         // Initializza LCD
  Lcd_Cmd(_LCD_CLEAR);                // Pulisci LCD
  Lcd_Cmd(_LCD_CURSOR_OFF);           // Cursore non visibile

  Lcd_Out(1,2,"TEMPERATURA:");        //Scrivi la stringa TEMPERATURA sulla prima riga

  ADC_Init();                         // Initializza il modulo ADC con valori di default


  while(1){                 //Ciclo infinito

    adcvalue = ADC_Get_Sample(0);      //Lettura da ADC
    Tem = 0.24414 * adcvalue;          //Conversione da Byte a Decimale
    Tem1 = Tem;                        //conversione in intero
    Dec = (Tem - Tem1)*10;             //Estrazione decimale
    Dec1 = Dec +48;

    IntToStr(Tem1, Text);            //conversione temperatura in stringa
    print_temp(text, Dec1);                  //Invia i valori da visualizzare al sottoprogramma

    delay_ms(500);
  }
}

 
REALIZZAZIONE
termometro preciso

 
CONFIGURAZIONE PER LA PROGRAMMAZIONE E DOWNLOAD
Come detto nella guida sul programmatore K150, ma in generale all’apertura di un nuovo progetto in Mikroc, è necessario settare opportunamente i fuses per evitare mal funzionamenti. tutti e due i sistemi lavorano ad una frequenza di 4MHz e i fuses sono così configurati:

Fuses

Dal link sottostante è possibile scaricare i datasheet dei componenti utilizzati, i PCB realizzati con PCB wizard, le simulazioni con Proteus, i file .HEX  da caricare nel PIC18F252 e tutti i file generati con MikroC.

LINK!!!





 

[Voti Totali: 0 Media Voti: 0]
Segui la Nostra Pagina Facebook: Facebook

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *