Monday 23 July 2018

Interfacing ADC in PIC Microcontroller (PIC18F4520)

Aim:

Digital inputs are great, but sometimes devices output an analog signal.  An analog signal is a signal of varying voltage levels.  Temperature sensors, light sensors, potentiometers and flex sensors are just some of the devices that output analog voltages that the PIC could read.  Analog sensors are generally a resistor that changes its value when a given condition is met (light level, temperature, flexibility, stretching … etc.).

Description:


Most important specification of ADCs is the resolution. This specifies how accurately the ADC measures the analog input signals. Common ADCs are 8 bit, 10 bit and 12 bit. For example if the reference voltage(explained latter) of ADC is 0 to 5v then a 8 bit ADC will break it in 256 divisions so it can measure it accurately up to 5/256 v= 19mV approx. While the 10 bit ADC will break the range in 5/1024 = 4.8mV approx. So you can see that the 8 bit ADC can’t tell the difference between 1mV and 18mV. The ADC in PIC18 are 10 bit.
Other specification include (but not limited to) the sampling rate, that means how fast the ADC can take readings. Microchip claims that pic18f4520’s ADC can go as high as 100K samples per second.

ADC Terminology

Reference Voltage: The reference voltage specifies the minimum and maximum voltage range of analog input. In PIC 18 there are two reference voltage, one is the Vref- and one is Vref+. The Vref- specifies the minimum input voltage of analog input while the Vref+ specifies the maximum. For example if the input signal Vref- is applied to analog input channel then the result of conversion will be 0 and if voltage equal to Vref+ is applied to the input channel the result will be 1023 (max value for 10bit ADC).
The Vref+ and Vref- pins are available in PIN5 and PIN4 of the PIC18F4520 chip. So you can connect the reference voltage here. For a simple design the Vref- is GND and Vref+ is Vcc. As this is such a common configuration that the ADC can be set up to use these reference internally. Therefore you do not need to connect these on the external Vref pins, so you can use them for other purpose.
ADC Channels: The ADC module is connected to several channels via a multiplexer. The multiplexer can connect the input of the ADC to any of the available channels. This allows you to connect many analog signals to the MCU (say 3 temperature sensors). In PIC18F4520 there are 13 analog input channels, they are named AN0, AN1 etc. You can have a look at the pin configuration in the pic18f4520’s datasheet to locate their position.
Acquisition Time: When an specific channel is selected the voltage from that input channel is stored in an internal holding capacitor. It takes some time for the capacitor to get fully charged and become equal to the applied voltage. This time is called acquisition time. The PIC18F4520’s ADC provides a programmable acquisition time, so you can setup the acquisition time. Once acquisition time is over the input channel is disconnected from the source and the conversion begin. The acquisition times depends on several factor like the source impedance, Vdd of the system and temperature. You can refer to the page 227 and 228 in the datasheet for details on its calculation. A safe value is 2.45uS, so acquisition time must be set to any value more than this.
ADC Clock: ADC Requires a clock source to do its conversion, this is called ADC Clock. The time period of the ADC Clock is called TAD. It is also the time required to generate 1 bit of conversion. The ADC requires 11 TADto do a 10 bit conversion. It can be derived from the CPU clock (called TOSC) by dividing it by a suitable division factor. There are Seven possible option.
  • 2 x TOSC
  • 4 x TOSC
  • 8 x TOSC
  • 16 x TOSC
  • 32 x TOSC
  • 64 x TOSC
  • Internal RC
For Correct A/D Conversion, the A/D conversion clock (TAD) must be as short as possible but greater than the minimum TAD . See table 26-25 in PIC18F4520 datasheet (or table 28-29 in PIC18F4550/PIC18F2550 datasheet). It is 0.7uS for PIC18FXXXX device and 1.4uS for PIC18LFXXXX device.
We are running at 20MHz in our PIC Development board so we set prescaler of 32 TOSC.
Our FOSC = 20MHz
Therefore our FOSC = 1/20MHz
                   = 50nS

32 TOSC = 32 x 50 nS
        = 1600nS
        = 1.6uS

1.6 uS is more than the minimum requirement.

You can calculate the value for division factor using the above example in case you are using crystal of other frequency. Also now we have the TAD we can calculate the division factor for acquisition time. Acquisition time can be specified in terms of TAD. It can be set to one of the following values.
  • 20 x TAD
  • 16 x TAD
  • 12 x TAD
  • 8 x TAD
  • 6 x TAD
  • 4 x TAD
  • 2 x TAD
  • 0 x TAD
As we saw in above paragraph that the safe acquisition time is 2.45uS, so we select 2 x TAD as acquisition time.
TACQ=2 x TAD
    =2 x 1.6uS (Replacing TAD= 1.6uS)
    =3.2uS


3.2uS is more than required 2.45uS so its ok.
ADC is connect to the PIC CPU by 3 control register and 2 data register. The control registers are used to setup and give commands to the ADC. They also provides the status of ADC. The two data registers holds the 10 bit of converted data. Since each resister in PIC18 is of 8 bits therefore 2 registers are required to hold the 10bit data.
We will develop two functions to support ADC in our projects. One will help initialize the module and other will help us select any of the 13 channels and start the conversion. After the conversion is done it will return us the results.
I am not giving here the description of the control and data registers as they are very clearly explained in PIC18F4520’s datasheet on page 223 to 225. I request you to download the datasheet and read the description so that you will have an Idea of what every bit in the registers do. As I told before, ADC is connected to the CPU via three control register and two data registers. The three control registers are :-
  • ADCON0 – Used to select analog input channel,start the conversion, check if the conversion is done and to switch on/off the module.(We use this in ADCRead() function.)
  • ADCON1 – Used to Select Voltage reference, and to configure ports as Analog of digital. (We leave these to defaults)
  • ADCON2 – Used to select ADC data format, Set acquisition time, ADC clock setup (We setup these in ADCInit() function)
You can see that we only set up the ADCON2 register.We setup the ADC as follows
  • ADC Result format as Right Justified(Explained latter).
  • Acquisition time = 2TAD(As Calculated Above)
  • Conversion Clock as 32 TOSC(As Calculated Above)
We also leave ADCON1 to defaults, which implies the following
  • +VREF is 5v (Our Vcc)
  • -VREF is GND
  • All ANx channels are Analog. If you need some of them to do digital I/O then setup them accordingly.
Now we have our ADC Module setup, when ever you want to do the ADC Conversion in any channel, simply call ADCRead(). For example to do ADC Conversion on channel 0 and store the result in variable val call the function in the following way.
The first line checks if the input channel provided by the user is valid or not. Then we select ADC channel. After that we switch on the module by setting ADON bit. Then conversion is started by setting the GODONEbit. As soon as the GODONE bit is set to 1 the module starts the conversion process. As long as the module is busy the GODONE bit is HIGH, and when the conversion is complete it is cleared by the module. So we wait in the while loop as long as GODONE is high. Remember that the while loop is empty (a semi colon just after it), so as long as GODONE is high the CPU will do nothing. As soon as GODONE is cleared the while loop breaks and we switch of the module by writing 0 to the ADON bit. Finally the result of conversion is returned, ADRES register holds the converted value.

Block Diagram

adc

Schematic


Code

// ****************************************************
// Poject: Interfacing ADC to PIC18F4520 microcontroller
// Author: Hack Projects India
// Module description: Operate POT
// ****************************************************
#include <p18f4520.h>
#include <delays.h>
#pragma config OSC=HS, FCMEN=ON, WDT=OFF, IESO=OFF, XINST=OFF, LVP=OFF
unsigned int d;

int adctest(void)
{
    ADCON0bits.GO=1;
    while(ADCON0bits.GO==1);
    return(ADRES);
}
void USART_Init()
{
    SPBRG =0x19;            // 9600 bps at XTA=4MHZ
    TXSTA=0X24;             // Transmission part enable
    RCSTA=0x90;             // Receiving part enable
}
void txd(unsigned char ch)

{
    TXREG=ch;               // Character send through transmission register
    while(!PIR1bits.TXIF);  // Upto transmitting character
}
void Convert_Transmit(int val,unsigned int field_length)
{
 char str[5]={0,0,0,0,0};
 int i=4,j=0;
 while(val)
 {
 str[i]=val%10;
 val=val/10;
 i--;
 }
 if(field_length==-1)
  while(str[j]==0) j++;
 else
  j=5-field_length;

 if(val<0) txd('-');
 for(i=j;i<5;i++)
 {
 txd(48+str[i]);
 }
}
void delay(unsigned short long x)
{
    while(x>0)
    {
        x--;
    }
    return;
}
void main()
{
      ADCON1=0b00001111;
      TRISA=0Xff;
 TRISD=0;  // Configure Port d as output port
 TRISB=0;  // Configure Port B as output port
      USART_Init();
 while(1)
 {
        ADCON0=0b00000001;    //FOR RA0
        ADCON1=0b00000000;//for analog
        ADCON0bits.ADON=1;
        txd('\r');
        txd('T');
        txd('-');
        d=adctest();
        Convert_Transmit(adctest()/128,3);
        ADCON1=0b00001111;//for DIGITAL
        delay(10000);
}
}


Downloads:

The code was compiled in Keil uvision4 and simulation was made in Proteus v7.7.
To download code and proteus simulation click here.

Further Reading suggestions:

No comments:

Post a Comment