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;

 Skip Navigation Links.

Collapse Site Tutorial IndexSite Tutorial Index
Collapse 16F PIC Examples16F PIC Examples
LED's
Switches
Keypads
LCD's
7 Seg Displays
ADC
DAC
Expand MotorsMotors
Expand ThermometersThermometers
DS1307 RTC Chip
DS275
EEPROM's
RF Modules
RGB LED's
Code Snippets
Expand Code SnippetsCode Snippets
Expand 18F PIC Examples18F PIC Examples
Expand Handy TipsHandy Tips