16F Analogue To Digital Conversion Example
Many PIC's have the ability to perform analogue to digital
conversions, and in this example the 16F877 is used. It doesn't take
any extra components, although a pull down
resistor is always good
to keep the conversions as accurate as possible, though not needed
in some cases. Here's an example,

Note the PIC's power supply/oscillator are not shown
Click here too watch this circuit in action!
This example has 2 inputs that are going to be used
for ADC's, and an
LCD to relay information to the user. ADC needs
some settings defined before its use, the compiler will assign
default settings if you don't specify them in your program, but its
a handy thing to know.
DECLARE ADIN_RES 10 ' 10-bit result required
DECLARE ADIN_TAD FRC ' RC OSC chosen
DECLARE ADIN_STIME 50 ' Allow 50us sample time
ADIN_RES
specifies the resolution of the ADC result, 8 bit
allows for values from 0-255 and 10 bit allows 0-1023. 10 bit is
usally a good option, as it provides much better accuracy and each
increment would be the equivalent of 0.0048V, compared to 8 bit
reolution whose increments would be the equivalent of 0.009V.
ADIN_TAD
defines the clock source that the ADC uses. FRC
indicates that the internal RC Osc is used for the operation, and is
guaranteed to work every time. Other options are available, but can
degrade the ADC performance . So if accuracy is not important you
could use the external Osc and achieve much faster results. See the
programmer help file for more detail.
ADIN_STIME
Allows the internal capacitors to fully charge
before a sample is taken. This may be a value from 0 to 65535
microseconds (us). A value too small may result in a reduction of
resolution. While too large a value will result in poor conversion
speeds without any extra resolution being attained.
ADCON1
is the register used to set up which pins are used as anologue /
digital, and what pin to compare the voltage with (Vref). Check the
datasheet for a more detailed explanation on the ADCON1 register for
the PIC your using.
There are
many different options, but to keep it easy, the following setting
is used in this example;
ADCON1 = %10000000
This
makes all of PORTA analogue and the voltage reference is Vdd. Bit 7
(set as a 1 in the example) is to tell the MCU how to save the data,
i.e. left / right justify. We have chosen 1 - right justify, so now
the data will always be 0000 00xx xxxx xxxx in 10 bit mode - much
easier to work with.
Now for
the program itself. The following example performs an ADC on PORTA.0
and then PORTA.1 and displays the value in volts on the
LCD. Note
the small delay between samples, this is allowing the internal
capacitors to charge between samples.
Device 16F877
Declare XTAL 4
DECLARE ADIN_RES 10 ' 10-bit result required
DECLARE ADIN_TAD FRC ' RC OSC chosen
DECLARE ADIN_STIME 50 ' Allow 50us sample time
Declare LCD_TYPE 0 ' Type of LCD Used is Alpha
Declare LCD_DTPIN PORTB.4 ' The control bits B4,B5,B6,B7
Declare LCD_RSPIN PORTB.2 ' RS pin on B2
Declare LCD_ENPIN PORTB.3 ' E pin on B3
Declare LCD_INTERFACE 4 ' Interface method is 4 bit
PORTB_PULLUPS True
Dim Result1 As Float
Dim Result2 As Float
Dim Last_Result1 As Float
Dim Last_Result2 As Float
Symbol Input1 = PORTA.0
Symbol Input2 = PORTA.1
TRISA = %00000011 ' Configure AN0 (PORTA.0+1) as an input
ADCON1 = %10000000 ' Set analogue input, Vref is Vdd
Main:
Result1 = ADIN 0 ' Grab A0's digital value
Delayus 1 ' Allow internal capacitors to charge
Result2 = ADIN 1 ' Grab A1's digital value
Result1 = Result1 * 5 / 1023 ' Scale it to volts
Result2 = Result2 * 5 / 1023 '
If Last_Result1 <> Result1 Then ' Check if value has changed
Print At 1, 1, Dec2 Result1, "V " ' If it has, display new data
Last_Result1 = Result1 ' and update last value
EndIf
If Last_Result2 <> Result2 Then ' Check if value has changed
Print At 2, 1, Dec2 Result2, "V " ' If it has, display new data
Last_Result2 = Result2 ' and update last value
EndIf
Goto Main ' Loop for ever
The output on the
LCD
looks something like this,

I have used floats in this example, and it's not the most efficient
way of programming, but once the float algorithm has been loaded
into the program, it doesn't consume to much more code whenever you
use floats, but this example compiled to 824 lines of code. You can
however use words (16bit registers) to reduce the program size and
increase its efficiency, but I always find myself choosing accuracy
over speed..
Voltages over 5V
For voltages that exceed 5V that you wish to
sample, simply use a voltage divider network like the following;

For best ADC performance of the
PIC micro, the input impedance
should not exceed 2.5K as the PIC's internal capacitors will take
too long too charge/discharge. This isn't really an issue for most
projects though, as you can just change the sample time with a
couple of settings - see the help file of your compiler for more
information. I generally use 10K resistors without any issues.
Where you can get
the components;

 | Site Tutorial Index |
|  | 16F PIC Examples |
| |  | Motors |
| |  | Thermometers |
| |  | Code Snippets |
|  | 18F PIC Examples |
|  | Handy Tips |