This web site uses cookies. By continuing to browse the site you are agreeing to our use of cookies. Find out more.

16F877 and Vref (an example using LM35)

Last update: 31/07/2015

A good setting of a reference voltage can be considered a must where precision is an important matter. 90% of projects are based assuming the VDD (microcontroller 5V power supply) as voltage reference but when the voltages to be compared are very small or the precision is a critical factor, very probably, it is better to reduce the value of this reference.

Synthesizing, we can reduce the different possibilities to obtain a reference supply voltage to the following: 

  • using the 5V regulated power supply voltage, normally obtained by the use of a positive voltage regulator (7805 precision 4%, according to datasheets) 
  • using dedicated components as micropower voltage reference diodes, as the LM385 for instance (a 1.235V or 2.5V zener diode,  1% precision).

The first solution is quite common where absolute precision is not a critical factor, the second regards components not easy to find and sometimes a little difficult to manage because of the calculation of the conversion procedure (normally an 8 bit microcontroller divides the reference voltage in 1024 steps because of the 10bit adc).

A really economical and easy solution can be found using a normal multiturns trimmer. In this example we'll show the value in degrees of the temperature using an LM35, a precision centigrade temperature sensor (LM34 for farheneit temperatures) according to the following schematic using a 16F877 (reading the datasheet of the microcontroller, we'll discover that the minimum level of Vref+ is around 2.5V). 

As we know, according to the datasheet of the component, the LM35 provides a voltage of 10mV every centigrade of temperature; this means only 1V at 100°c therefore the value of the vdd voltage, as reference, can be considered too high for our needs.

lm35 vref

Here, on the left, a quick schematic regarding a traditional configuration for an ADC conversion. We have a LM35 sensor connected to RA2 and a multiturns trimmer connected to RA3.

We have to turn the trimmer until to read, using a good tester, the value of 2,5V on the pin RA3, the pin we are going to use as voltage reference pin.

According to previous articles we should already know how to set correctly the registers but we'll pay again a look to theyr settings.

lm35 vref

ADCON0 will be set as:

  • 10 (fosc/32)
  • 010 (RA2/AN2 as analog input)
  • xxx

ADCON0 = 0b01010000 =0x90

adcon1 vref

ADCON1 will be set as:

  • 1 right justified
  • xxx
  • 0001 Vref+ = RA3 all analogical

ADCON1 = 0b10000001 = 0x81

At this point we can start to write our program (we are using C but the code, with small modifications, can be used with any other language)

Ff the Vref+ has been set to 2.5V mV the conversion is: ADC_read_value = 2500/1024 = 2,441 (mV/step).

The LM35 provides 10mv/degree therefore the conversion will be very simply: ADC_read value * (2,441*1000 to avoid float point math) /1000*10(mV/degree).

Let's start. To check the validity of the results it is suggested to replace, initially, the LM35 temperature sensor with a trimmer connected to the 5V power supply simulating a temperature value.

/-------------------------------- LCD connections, could be different

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, all analog = 2.5V 
TRISB = 0x00;                                             // PORTB All Outputs 
TRISA = 0xFF;                                             // PORTA All Inputs
     adc_value = ADC_Read(2);                       // channel2 (RA2)      
     temp = ((long)adc_value*2441)/100;           // 2.5V/1023 =  (adc* 2,443 * 1000)/100 (10mV *°C)      
     LongToStr(temp,value);                            // display value 'brutely'
     degs[0] = temp/1000 + 48;                        // display formatted value in degrees 
     degs[1] = (temp/100)%10 + 48;      
     degs[3] = (temp/10)%10 + 48;      
     degs[4] = (temp)%10 + 48;      
     Lcd_Out (3,12,degs);
     } while (1);


Diritti riservati 2008-2015. Tutti i marchi riportati sono detenuti dai legittimi proprietari. Tutto il materiale e` liberamente utilizzabile ma non per scopi commerciali. Non si assume alcuna responsabilita` sul materiale pubblicato per eventuali danni diretti o indiretti che possano derivare dall`utilizzo di schemi, progetti o altro materiale presente nel sito. Inviare una mail a: (contenuti) (webserver) per domande e/o suggerimenti.