Feb 06

Getting Started with PIC Microcontrollers – The ADC

This time, we shall take a look at the Analogue to Digital Converter (ADC) This peripheral is the link between the analogue world and the digital domain of the microcontroller.

It can be used for many things, e.g. (analogue) sensor/transducer readings such as microphones, thermistors, light sensors, pressure sensors, accelerometers, and much more. In this entry we will take a look at one of the simplest uses, reading the voltage from a potentiometer. We will look at how to set the ADC peripheral up, and how to take the reading and use it to display this information roughly on a line of LEDs.

If you are completely new to the ADCs and how they work, or want to learn a little more about the different types and theory behind them, then I suggest taking a look at these links:

Wiki ADC page

Decent Sparkfun page on ADC basics

Microchip app note on ADCs

ABCs of ADCs

At its most basic, the ADC takes a voltage level, compares it with a reference voltage, and turns it into a corresponding binary value. The PIC ADC is a 10-bit ADC, and we will be using the Vdd (+V power pin, it is possible to use a dedicated Vref pin if a different voltage to Vdd is required as reference) as the reference so the range will be from 0 – 5V (assuming you are running your PIC at 5V) The resolution, which at 10-bits equates to \( 2^{10} = 1024 \) steps means that each step equals \( \frac{5V }{1024} = 4.88mV \). For example an input of 0.5V would convert to \( \frac {0.5V}{0.00488V} = 102 \) decimal or  \( 0001100110 \) binary. An input of 2.5V would convert to  \( \frac {2.5V} {0.00488V} = 512 \) decimal or \( 1000000000 \) binary.

Okay, now to setup the PIC. We will use the PIC16F690 again with just a few additions to the original “Getting Started with Microcontrollers” schematic, namely a potentiometer and a few extra LEDs. The potentiometer can be pretty much anything you have to hand, preferably in the range of \( 1k \Omega\  –\  100k \Omega \). The LEDs used are standard 5mm red LEDs, but you can swap these if you need to (make sure you size the resistors correctly if the Vf / max current is different – see here if you need help) Also, don’t worry if you don’t have enough LEDs, you can use less if you alter the #define value accordingly in the code below and comment out the references to unused pins e.g. for 5 LEDs then the LED_INT value should be \( \frac{1024}{5} = 204 \).

Here is the schematic:


And the code:

/* * File: comet2.c * Author: Oli Glaser * * Created on 31 Jan 2015, 07:37 */ #include <xc.h> #define LED_INT 146 // Interval for ADC reading to light another LED (approx. 1024/7) #pragma config FOSC = INTRCIO // Internal RC Oscillator #pragma config WDTE = OFF // Turn watchdog off #pragma config BOREN = OFF // Brown out enable off // Set which pin controls which LED, change if you wish to use // different pin // Define which pin each LED is on #define LED1 PORTAbits.RA2 #define LED2 PORTCbits.RC0 #define LED3 PORTCbits.RC1 #define LED4 PORTCbits.RC2 #define LED5 PORTBbits.RB4 #define LED6 PORTBbits.RB5 #define LED7 PORTBbits.RB6 //#define LED8 PORTBbits.RB7 //#define LED9 PORTCbits.RC7 //#define LEDD PORTCbits.RC6 // Function definitions void init(void); void delay(unsigned int ms); // Global variables volatile unsigned int result = 0; int main(int argc, char** argv) { init(); while(1) { delay(10); unsigned int temph, templ; if(ADCON0bits.GO_DONE == 0) { temph = (ADRESH << 2); templ = (ADRESL >> 6); result = temph + templ; if(result > LED_INT) { LED1 = 1; } else { LED1 = 0; } if(result > LED_INT*2) { LED2 = 1; } else { LED2 = 0; } if(result > LED_INT*3) { LED3 = 1; } else { LED3 = 0; } if(result > LED_INT*4) { LED4 = 1; } else { LED4 = 0; } if(result > LED_INT*5) { LED5 = 1; } else { LED5 = 0; } if(result > LED_INT*6) { LED6 = 1; } else { LED6 = 0; } if(result > LED_INT*7) { LED7 = 1; } else { LED7 = 0; } ADCON0bits.GO_DONE = 1; // Start ADC conversion } } } // Basic delay routine void delay(unsigned int ms) { unsigned int i = 1000; while(ms) { i = 1000; while(i) i--; ms--; } } // Set up various things - I/Os, interrupts, etc void init(void) { // Set internal oscillator to 8MHz OSCCON = 0x70; // Turn analog inputs off ANSEL = 0; ANSELH = 0; // Set all pins to outputs TRISA = 0; TRISB = 0; TRISC = 0; // Setup ADC to read potentiometer voltage TRISCbits.TRISC6 = 1; // Set RC6/AN8 as input for ADC ANSELHbits.ANS8 = 1; // ADCON0bits.CHS = 0x08; // Set AN8 as the analog input pin ADCON1bits.ADCS = 0b010; // Set conversion clock as Fosc / 32 = 1(8MHz / 32) = 4us ADCON0bits.ADON = 1; // Turn ADC on }


Skip to comment form

  1. MIke

    Hi Olie,
    I wanted to thank you for the time you are taking to help me and others out there, it is very much appreciated. I started out with a couple of projects using the PicAxe basic which was quick and easy for a beginner to get into the pic world and provided some understanding of micro-controllers and peripheral interfacing. So, while I was able to get a functional result, I soon found that the interpreted environment became constraining in terms of code size, performance and advance features such as interrupts etc.

    Well, it turns out that the PicAxe 18M2 I used is actually a Pic16F1847 under the covers so the PCB I had fabbed for the projects would work for both. So I swapped the chips out, used mikroBasic compiler (a first step to ease the transition to compiled C environment) and rewrote my code. Unfortunately, the part of the code that uses I2C bus control of HMC5883L (among other things like real time clock) is not working out well (probably pilot error and/or some issues with libraries/initialization/configuration of the pic), so I have decided to bite the bullet and move to C (which at first glance seems very daunting with all the unfamiliar structure, configuration and setup) because the breadth of example code being available in C for the pic. Your tutorials are making that much easier to understand I thank you for that. Please continue the great work on your blog and look forward to learning more from you…

    All the best,

    1. Oli G

      Thanks Mike, you are quite welcome 🙂 I have had other commitments recently, but I intend to add more tutorials as soon as possible.

  2. Joseph

    Thanks for your work on these, Oli….Look forward to more!!

  3. black and white kitten names the letter W

    i found my errors thanks anyway br the for statement needs to end in a semicolon which is missing here Hi noob here, im getting errors at this point unable to resolve identifiers time amp; time1 br should these be defined somewhere else? thanks in advance

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>