ADC Module: Voltage
ADC Module: Voltage
ADC is stands for Analog to Digital Converter. It is used to convert any analog signal to digital data so
that it can be stored and manipulated digitally. Digital voltmeter is a good example it simply takes analog
reading (Voltage) and converts it to digital using ADC then by making simple calculations on this digitized
value we will have a digital reading corresponds to the original analog, now we can store it, display it on
a 7-segment or LCD, send it to PC as we will see later and the most important we can modify and process
this digital data. And same as digital voltmeter procedure we can handle any analog input such as
temperature, pressure and so on…
PIC16F877A has 8×10bit multiplexed ADC channels (AN0-AN7) mapped to port E and port A except
RA4. Next figure shows an abstraction view for ADC module.
AN0/RA0
Analog input pins:
8x1 MUX
……….....
AN7/RE2
Result
(10bit)
As you note from previous figure the result of conversion is 10 bit width and this means that the result of
conversion is a value between 0 and 210 -1 or [0,1023]. For example if we use 5 volt as reference voltage
then analog input should be in TTL level (ranges from 0 and 5 volt) and in this case 0 volt analog corresponds
to 0 digital in result and 5 volt analog corresponds to 1023 digital in result. In real application analog
input is unknown and at the same time it is our target. The procedure for calculating this value is
straightforward. Firstly, make a conversion to get a digital value that corresponds to analog input.
Secondly, make a reverse calculation for the unknown analog voltage as follows (note that the default
value for Vref is VDD voltage at pin 11 or 32, in general it is 5v):
𝑉𝑟𝑒𝑓 → 1023
𝐴𝑛𝑎𝑙𝑜𝑔𝑢𝑛𝑘𝑛𝑜𝑤𝑛 → 𝐷𝑖𝑔𝑖𝑡𝑎𝑙 𝐾𝑛𝑜𝑤𝑛
1
Two examples will be taken: first, building a digital voltmeter. Second, measuring temperature and displaying it on
LCD.
As shown above a variable resistor is used to choose a voltage from 0 to 5v. Code is shown below.
#include <16F877A.h>
#DEVICE ADC=10 // return 10 bit(FULL RESOLUTION) from ADC, Will be explained later.
#FUSES XT // Crystal osc <= 4mhz.
#FUSES NOWDT // No Watch Dog Timer.
#FUSES NOPROTECT // Code not protected from reading.
#USE DELAY(CLOCK = 4000000)
#include <lcd.c>
void main()
{
int16 digitalValue; //16 bit integer, to store the ADC result (10bit).
float voltage;
setup_adc_ports( ALL_ANALOG ); //All 8 pins are analog input. Vref is 5v.
setup_adc( ADC_CLOCK_INTERNAL );//Use internal clock (TAD between 2u-6u Second)
set_adc_channel( 0 ); //AN0 is the used here pin.
lcd_init();
lcd_gotoxy(1,1);
printf(lcd_putc, "Digital voltmeter");
delay_ms(1500);;
while(TRUE)
{
digitalValue = read_adc();
voltage = (float)digitalValue/204; //ADC equation: digitalValue*5/1023
Because ADC ports are configured to ALL_ANALOG we can use any pin from <AN0:AN7> as analog input,
for other parameters show 16F877A.h header file. In above example we use AN0 and according to that
we must read from channel 0 this is done using set_adc_channel( 0 ) line. Suppose that AN5 is used
then instead of passing 0 we must pass 5 i.e.) set_adc_channel( 5 ). TAD is the time required from
ADC to digitize one bit (at minimum, it must be 1.6uS). By choosing ADC_CLOCK_INTERNAL TAD automatically
set between 2uS and 6uS.
2
Example 2: Temperature control system.
Main goals: More about ADC module, dealing with LM35 temperature sensor.
DESCRIPTION: Reads a temperature from 0 ْC and above. If it is less than 22 ْC send a high signal
from RE0 to operate a heater. If the temperature is more than 27 ْC send a high
signal from RE1 to operate an air conditioner. Use ADC=8 and Vref = 1v.
We will use LM35DZ temperature sensor, it is a 3 terminal sensor (VCC, GND and O/P) and it can measure a
wide temperature range (from 0 ْC up to 100 ْC). The most important feature (for more features refer to datasheet)
that its output is linear with 10mV / ْC. This means that if temperature is 1 ْC then LM35's output is 10mV,
so and simply:
1℃ 𝑇𝑒𝑚𝑝𝑒𝑟𝑎𝑡𝑢𝑟𝑒
=
10𝑚𝑉 𝑠𝑒𝑛𝑠𝑜𝑟 𝑜𝑢𝑡𝑝𝑢𝑡 𝑣𝑜𝑙𝑡𝑎𝑔𝑒
Honestly, there are many types to LM35 like LM35A, LM35C and our sensor LM35DZ, each one differ
from other in temperature range (e.g. LM25C can measure from -40 ْC to 110 ْC) and accuracy.
As you note from description RE0 and RE1 must set to digital output, LM35 is connected to AN0 and the
reference voltage (pin A3) is set to 1v. Schematic is shown below.
LM35D RA0/AN0
1 volt RA3/AN3/Vref+
LCD
To heater Interface RE0/AN5
PIC16F877A
Tip 1: Control system like that is called a regulator system. It is automatically maintains a
parameter at (or near) a specified value; in our example we maintain temperature.
The interface between PIC (low voltage devices) and heater or air conditioner (high voltage devices) can be
done using any device that makes isolation between them like relays (certainly with other elements).
3
#include <16F877A.h>
#DEVICE ADC=8 //return 8-bit width. Don't forget to divide digitalValue over 255.
#FUSES XT, NOWDT, NOPROTECT
#USE DELAY(CLOCK = 4000000)
#include <LCD.c>
void main()
{
int8 digitlValue; //Store the result of A/D conversion. 8bit is enough.
float temperature;
set_tris_d(0);
output_d(0);
lcd_init();
lcd_gotoxy(1,1);
lcd_putc("Temperature\nControl System");
delay_ms(1500);
while(1)
{
digitlValue = read_adc();
temperature = (float)digitlValue / 255; //Apply ADC equ.: digitalValue*Vref/255
Temperature = temperature * 100; //Apply LM35 equation.
printf(lcd_putc, "\fT = %2.2f", temperature);
In (#DEVICE) directive we use ADC=8 instead of ADC=10 this means that read_adc() function will return
8-bit only from the converted result and a variable with int8 type is enough to store this value also instead
of dividing by 1023(210-1) in ADC equation ( (𝑉𝑟𝑒𝑓 × 𝑑𝑖𝑔𝑖𝑡𝑎𝑙𝑉𝑎𝑙𝑢𝑒) 1023 ) we must divide by 255 (28-1), the
overall result is a light calculation but less accuracy.
Pin RA3/AN3 can be used as analog input or reference voltage input. This can be determine according to
the argument that passed to setup_adc_ports() function. In the above code it is used as Vref . By
setting Vref to 1v the final result will be somewhat more accurate (in examples like this only). To show the
difference you can convert Vref to default VDD (in general 5v) as example 1 and change the ADC equation
to ( (𝑑𝑖𝑔𝑖𝑡𝑎𝑙𝑉𝑎𝑙𝑢𝑒 × 5) 255 ). Next table shows some setup_adc_ports() parameters.
4
Some setup_adc_ports() parameters.
Parameter Description
NO_ANALOG All pins are digital.
ALL_ANALOG All pins are analog. Vref = VDD.
AN0 AN0 is the only analog pin. Vref = VDD.
AN0_AN1_AN3 All of these pins are analog input. Vref = VDD.
AN0_AN1_AN2_AN4_VSS_VREF All of these pins are analog. Vref is set at AN3.
NOTE: VDD or VCC means the voltage that fed to PIC at pin 11 or 32; it is normally 5v but you can choose from 2v – 5.5v
(according to PIC specification). So if you use VDD as Vref for example ALL_ANALOG or AN0_AN1_AN3 then you must measure
the voltage that supplied to PIC at pin 11 or 32 and change ADC equation according to it.
PIC16F877A hasn't a float point circuitry so all float calculations handled by PIC C using software and
this implies to long execution time and more memory usage. In project section we introduced a method
called integer coding scheme it can handle any float calculations using simple integer calculations.