La scelta del valore della tensione di riferimento deve essere considerato un fattore importante allorquando, nel realizzare un progetto, si necessita di alta precisione. Il 90% dei progetti riguardanti microcontrollori assumono la VDD (la tensione di alimentazione del picmicro) come valore di riferimento, talvolta, pero' tale valore è eccessivo quando i valori di tensione da analizzare sono troppo piccoli ovvero quando una maggior precisione sia determinante. Vediamo, a titolo di esempio, come rilevare la temperatura utilizzando un LM35 collegato ad un pic 16F877.
In sintesi vi sono solo alcune possibilita' per scegliere una tensione di riferimento:
- utilizzare il valore di tensione di alimentazione (normalmente 5V) ottenuta attraverso un regolatore di tensione positivo (7805, precisione 4%, in base al datasheet)
- utilizzare un componente dedicato che fornisca un valore di tensione noto e preciso, come l' LM385 ad esempio (diodo zener di precisione in due versioni: a 1.235V o 2.5V, 1% di precisione).
La prima soluzione potrebbe essere utilizzata quando, per i valori in gioco la criticità, non è determinante; la seconda soluzione riguarda componenti non semplici di reperire sul mercato oppure che costringono a calcoli un po' problematici di conversione (normalmente un microcontrollore ad 8 bit è dotato di un convertitore interno a 10 bit e quindi divide il valore in 1024 passi).
Una soluzione molto economica ed efficiente, invece, riguarda l'utilizzo di un trimmer multigiro collegato alla porta di ingresso VRef+.
Nel nostro esempio, infatti, posizioneremo un trimmer per ottenere un solido valore di tensione di riferimento per calcolare la temperatura ambiente per mezzo di un sensore LM35 (gradi centigradi; LM34 per gradi farheneit). Nell'osservare lo schema di sotto riportato, si tenga presente che, in base al datasheet, la tensione minima di riferimento applicabile ad un 16F877 è di circa 2.5V).
Come sappiamo dalla lettura del datasheet dell'LM35 questo riporta, con notevole precisione, una tensione di 10mV per ogni grado centigrado di temperatura. Questo significa che avremo solo 1V a 100 gradi centrigradi e quindi un valore VRef+ riferito alla VDD sarebbe eccessivo per le nostre necessita' e per ottenere valori affidabili di temperatura.
|
Ecco a lato un rapido schema per una conversione ADC. Abbiamo un sensore LM35 connesso a RA2 ed un timmer multigiro connesso ad RA3. Giriamo il trimmer sino a leggere con un buon tester il valore di 2.5V sul piedino interessato, RA3 sarà infatti il pin sul quale sarà applicata la VRef+. Se abbiamo letto altri articoli sappiamo già come configurare il registro interessato: Adcon, comunque rivediamo anche ora il suo settaggio. |
![]() |
ADCON0 sarà settato in questo modo:
ADCON0 = 0b01010000 =0x90 |
|
ADCON1sarà invece settato come:
ADCON1 = 0b10000001 = 0x81 A questo punto siamo pronti a scrivere il programma. Abbiamo usato il mikroc ma nulla toglie che con semplicissime modifiche si possano utilizzare altri linguaggi. |
Se la Vref+ è stata settata a 2.5V si calcola molto facilmente la risoluzione: ADC_read_value = 2500/1024 = 2,441 (mV/passo),
L'LM35 fornisce 10mv/grado e quindi la conversione sarà altrettanto semplice: ADC_read value * (2,441*1000 per evitare matematica in virgola mobile) /1000*10(mV/grado) = ADC_read *2441/100
Iniziamo il programma (all'inizio al fine di verificare l'esattenza della conversione, potremo sostituire LM35 con un normale trimmer da 10K) simulando il sensore.
//-------------------------------- Le connessioni all'LCD possono essere ovviamente diverse
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB3_bit;
sbit LCD_D5 at RB2_bit;
sbit LCD_D6 at RB1_bit;
sbit LCD_D7 at RB0_bit;
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_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 adc_value;
long temp;
char value [15];
char *degs = "00.00";
void main()
{
ADCON0 = 0b01010000; // Fosc/32, RA2 input
ADCON1 = 0b10000001; // Ra3 = Vref, tutto analogico = 2.5V
TRISB = 0x00; // PORTB tutti Outputs
TRISA = 0xFF; // PORTA tutti inputs
Lcd_Init();
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
do
{
adc_value = ADC_Read(2); // canale2 (RA2)
temp = ((long)adc_value*2441)/100; // 2.5V/1023 = (adc* 2,441 * 1000)/1000*10 (10mV °C)
LongToStr(temp,value); // valore su lcd non ottimizzato
lcd_out(1,1,"Temp.:");
lcd_out(2,5,value);
degs[0] = temp/1000 + 48; // valore su lcd formattato
degs[1] = (temp/100)%10 + 48;
degs[3] = (temp/10)%10 + 48;
degs[4] = (temp)%10 + 48;
Lcd_Out (3,12,degs);
delay_ms(300);
} while (1);
}