Friday, October 1, 2010

PIC16F887/877 programming in C Tutorial 10 (ADC)

Analog to Digital Converter (ADC):
In this tutorial i will show how to convert analog values into digital, by using 887 (little bit differ with 877), then display these digital value on LCD.

The Analog-to-Digital Converter (ADC) allows conversion of an analog input signal to a 10-bit binary representation of that signal. This device uses analog inputs, which are multiplexed into a single sample and hold circuit. The output of the sample and hold is connected to the input of the converter. The converter generates a 10-bit binary result via successive approximation and stores the conversion result into the ADC result registers (ADRESL and ADRESH).

The ADC voltage reference is software selectable to be either internally generated or externally supplied.

ADC Configuration:
When configuring and using the ADC the following functions must be considered:
• Port configuration
• Channel selection
• ADC voltage reference selection
• ADC conversion clock source
• Interrupt control
• Results formatting

Port configuration:
The ADC can be used to convert both analog and digital signals. When converting analog signals, the I/O pin should be configured for analog by setting the associated TRIS and ANSEL bits.

Channel selection:
The CHS bits of the ADCON0 register determine which channel is connected to the sample and hold circuit. When changing channels, a delay is required before starting the next conversion.
ADC voltage reference selection:
The VCFG bits of the ADCON0 register provide independent control of the positive and negative voltage references. The positive voltage reference can be either VDD or an external voltage source. Likewise, the negative voltage reference can be either VSS or an external voltage source. 

ADC conversion clock source: 
The source of the conversion clock is software selectable via the ADCS bits of the ADCON0 register. There are four possible clock options:
• FOSC/2
• FOSC/8
• FOSC/32
• FRC (dedicated internal oscillator)
The time to complete one bit conversion is defined as TAD. One full 10-bit conversion requires 11 TAD periods as shown in Figure.

Interrupt control:
The ADC module allows for the ability to generate an interrupt upon completion of an Analog-to-Digital conversion. The ADC interrupt flag is the ADIF bit in the PIR1 register. The ADC interrupt enable is the ADIE bit in the PIE1 register. The ADIF bit must be cleared in

Results formatting: 
The 10-bit A/D conversion result can be supplied in two formats, left justified or right justified. The ADFM bit of the ADCON0 register controls the output format. 

ADC Operation:
STARTING A CONVERSION:To enable the ADC module, the ADON bit of the ADCON0 register must be set to a ‘1’. Setting the GO/DONE bit of the ADCON0 register to a ‘1’ will start the Analog-to-Digital conversion. 

COMPLETION OF A CONVERSION:When the conversion is complete, the ADC module will:
• Clear the GO/DONE bit
• Set the ADIF flag bit
• Update the ADRESH:ADRESL registers with new conversion result

This is an example procedure for using the ADC to perform an Analog-to-Digital conversion:
1. Configure Port:
• Disable pin output driver (See TRIS register)
• Configure pin as analog
2. Configure the ADC module:
• Select ADC conversion clock
• Configure voltage reference
• Select ADC input channel
• Select result format
• Turn on ADC module
3. Configure ADC interrupt (optional):
• Clear ADC interrupt flag
• Enable ADC interrupt
• Enable peripheral interrupt
• Enable global interrupt(1)
4. Wait the required acquisition time(2).
5. Start conversion by setting the GO/DONE bit.
6. Wait for ADC conversion to complete by one of the following:
• Polling the GO/DONE bit
• Waiting for the ADC interrupt (interrupts enabled)
7. Read ADC Result
8. Clear the ADC interrupt flag (required if interrupt is enabled).

The following registers are used to control the operation of the ADC.

Lets make it easy by using adc library of mikroc. The following code will convert the analog input, at pin RA2, into digital and display it on lcd. As the conversion is of 10-bit, so the range is from 0-1023.

unsigned int temp_res;

// LCD module connections
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections

char txt1[] = "ADC Example";
char txt[7];
void main() {
/////////// comment for 877/////////////////////////////////////
  ansel=4;                     // Configure AN2 pin as analog
  TRISA  = 0xFF;              // PORTA is input
  Lcd_Cmd(_LCD_CLEAR);               // Clear display
  Lcd_Cmd(_LCD_CURSOR_OFF);          // Cursor off
  do {

    temp_res = ADC_read(2);   // Get 10-bit results of AD conversion
    IntToStr(temp_res, txt);    //int to string conversion
  } while(1);

adc_init(); This routine initializes PIC’s internal ADC module to work with RC clock. Clock determines the time period necessary for performing AD conversion.

ADC_read(2); 10 or 12-bit unsigned value read from the specified channel (MCU dependent).Parameter channel represents the channel from which the analog value is to be acquired.In this case it is 2.

IntToStr(temp_res, txt); Converts input signed integer number to a string. The output string has fixed width of 7 characters including null character at the end (string termination). The output string is right justified and the remaining positions on the left (if any) are filled with blanks.



  1. thanks for this tut.. very helpful

  2. Thanks!
    I'm having the problem when i using more than one adc channel.
    Please help me, how to solve this problem.

    Thank you everyone!

  3. Insert delay, then read the value of the other ADC channel.

  4. Ca you show us an example with 2 adc channels, please?

  5. just use ADC_read(x) to read the x channels;store it in other variable and rest of the code is same. like
    temp_res1 = ADC_read(1);//for channel 1
    IntToStr(temp_res1, txt);

    temp_res2 = ADC_read(2);//for channel 2
    IntToStr(temp_res2, txt);

  6. hi this is krishna

    In this project you write a program in C language to read the value from the ADC continuously on the easypic6 board and display the values on the LCD. For example:
    Voltage=2.843 V

  7. Hallo, I am looking to do the same but using ccs. How does the code lie out differ from pure c to ccs?
    Also using PIC kit 2 demo board and 16f887 controller.
    I am new to this type of code so any help will be greatly appreciated.

    1. Actually, i only know the c; may by the differences are of commands or syntax.
      if you are new then google the ccs tutorials.

  8. thank you sooooooo much:):):):):)Was very helpful!!!!!!!!!!!!100000000000000000000000000000000000000000000000000000000 thanks...

  9. ขอบคุณมากครับผม ข้อความนี้เป็นประโยชน์กับผมมากๆเลยครับ

  10. how can we configure pic16f877a to use all the analog channels and use adc_read(x), but also have one digital input (push button)?

  11. hello friends.
    I m new in PIC,very poor in programming.Can anyone of u plz write the code for me for the following requirements. i have written one but not working, i used MikroC.
    for PIC18F452; temperature sensor data to be displayed at hyperterminal. display should be like
    "Present Temp. is:-27.9";
    My Fosc is 4.0 MHz.
    Temperature sensor connected at An2.
    Please help me

  12. hello everyone, i hv an doubt ... is it necessary to reference voltage to adcon1..
    if it is so how i can give... plz help...

  13. hello,can anyone help us????????????
    we are getting errors while running the above code,
    we need to control two dc motors using joystick,so please help us in providing a code