Wednesday 7 May 2014

Using the Analog To Digital Converter.




Most of the physical quantities around us are continuous. By continuous we mean that the quantity can take any value between two extreme. For example the atmospheric temperature can take any value (within certain range). If an electrical quantity is made to vary directly in proportion to this value (temperature etc) then what we have is Analogue signal. Now we have we have brought a physical quantity into electrical domain. The electrical quantity in most case is voltage.To bring this quantity into digital domain we have to convert this into digital form. For this a ADC or analog to digital converter is needed. Most modern MCU including AVRs has an ADC on chip. An ADC converts an input voltage into a number. An ADC has a resolution. A 10 Bit ADC has a range of 0-1023. (2^10=1024) The ADC also has a Reference voltage(ARef). When input voltage is GND the output is 0 and when input voltage is equal to ARef the output is 1023. So the input range is 0-ARef and digital output is 0-1023.

Fig: ADC Theory

ATmega16 has an inbuilt 10 bit, 8-channel ADC system. Some of the basic features of Armega16 ADC are:
·         8 Channels.
·         10-bit Resolution.
·         Input voltage range of 0 to Vcc.
·         Selectable 2.56V of internal Reference voltage source.
·      AREF pin for External Reference voltage.
·      ADC Conversion Complete Interrupt.
ADC channels in Atmega16 are multiplexed with PORTA and use the common pins (pin33 to pin40) with PORTA. ADC system  of Atmega16 microcontroller consists of following pins:
        i.            ADC0-ADC7: 8 Channels from Pin 40 to Pin 33 of Atmega16 ADC peripheral.
      ii.            AREF: Pin32 of Atmega16 microcontroller, the voltage on AREF pin acts as the reference voltage for ADC conversion, reference voltage is always less than or equal to the supply voltage, i.e., Vcc.
      iii.            AVCC: Pin30, this pin is the supply voltage pin for using PORTA and the ADC; AVCC pin must be connected to Vcc (microcontroller supply voltage) to use PORTA and ADC.
Note:  External reference voltage source can be used at AREF pin. However, Atmega16 also has internal reference voltage options of 2.56V and Vref = Vcc.
The figure below shows the pin configuration for ADC system of Atmega16 microcontroller.
 
ADC Registers 
To use the ADC peripheral of Atmega16, certain registers need to be configured.
        i.            ADMUX (ADC Multiplexer And Selection Register)
 
REFS[0:1] bits determine the source of reference voltage whether it is internal or the external voltage source connected to AREF pin. MUX[4:0] bits are used to select between the channels which will provide data to ADC for conversion. ADLAR bit when set to 1 gives the left adjusted result in data registers ADCH and ADCL.
      ii.            ADCSRA (ADC Control and Status Register)
 
ADEN: ADC Enable bit, this bit must be set to 1 for turning ADC on.
ADSC: ADC Start Conversion bit, this bit is set to 1 to start ADC conversion, as soon as conversion is completed this bit is set back to 0 by the hardware.
ADATE: ADC Auto Trigger Enable, this bit is set to 1 to enable auto triggering of ADC conversion.
ADIF: ADC Interrupt Flag, this bit is set to 1 when ADC conversion gets complete.
ADIE: ADC Interrupt Enable, this bit is set to 1 if we want to activate the ADC conversion complete interrupt.
ADPS[0:2]: ADC Prescaler bits, these bits are used to set the ADC clock frequency, the configuration of these bits determine the division factor by which the microcontroller clock frequency is divided to get the ADC clock frequency. The figure above shows the prescaler bit values for respective division factor.
 
The ADC clock frequency must lie somewhere between 50 KHz to 200 KHz.
    iii.            ADCH & ADCL (ADC Data Registers) 
When the ADC conversion is complete the data is stored in these two registers. The data configuration depends on the ADLAR bit value of ADMUX register. If ADLAR=0, data is right adjusted and if ADLAR=1, data is left adjusted.  Always read ADCL first and then ADCH. In cases where the 8-bit precision is enough set the ADLAR bit to 1 to left adjust the data and read only the ADCH data register.
When ADLAR = 0,
 
When ADLAR = 1,
 
Circuit description
Connect the circuit as shown in the circuit diagram. A ceramic capacitor 104 is connected in between AVcc (pin 30) and Aref (pin 32). AVcc (pin 30) is connected to external supply +5V.
Code explanation
To interface analog device with AVR microcontroller, follow the following steps for programming it.

Step1: To initialize ADC
        i.            Set the value in ADMUX register according to the ADC channel and the reference voltage.
       ii.            Set the Prescaler bits accordingly in ADCSRA register.
      iii.            Set the ADEN bit to enable the ADC.

void ADC_init(void) // Initialization of ADC
{
ADMUX=(1<<REFS0); // AVcc with external capacitor at AREF
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
// Enable ADC and set Prescaler division factor as 128
}
Step2: To read the analog value
        i.            Put the channel value in ADMUX
       ii.            Start the conversion by setting the ADSC bit.
      iii.            Monitor the ADIF bit for conversion complete.
      iv.            Clear the conversion bit ADIF. By writing it 1.
       v.            Digital converted result is now available in ADCH and ADCL registers.

unsigned int ADC_read(unsigned char ch)
{
ch= ch & 0b00000111; // channel must be b/w 0 to 7
ADMUX |= ch; // selecting channel
ADCSRA|=(1<<ADSC); // start conversion
while(!(ADCSRA & (1<<ADIF))); // waiting for ADIF, conversion complete
ADCSRA|=(1<<ADIF); // clearing of ADIF, it is done by writing 1 to it
return (ADC);
}

Sample Code.

The following is complete code to Read Channel 0 and display its value on LCD.

#include <avr/io.h>

#include "lcd.h"

void InitADC()
{
ADMUX=(1<<REFS0);                         // For Aref=AVcc;
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //Rrescalar div factor =128
}

uint16_t ReadADC(uint8_t ch)
{
   //Select ADC Channel ch must be 0-7
   ch=ch&0b00000111;
   ADMUX|=ch;

   //Start Single conversion
   ADCSRA|=(1<<ADSC);

   //Wait for conversion to complete
   while(!(ADCSRA & (1<<ADIF)));

   //Clear ADIF by writing one to it
   //Note you may be wondering why we have write one to clear it
   //This is standard way of clearing bits in io as said in datasheets.
   //The code writes '1' but it result in setting bit to '0' !!!

   ADCSRA|=(1<<ADIF);

   return(ADC);
}

void Wait()
{
   uint8_t i;
   for(i=0;i<20;i++)
      _delay_loop_2(0);
}

void main()
{
   uint16_t adc_result;

   //Initialize LCD
   LCDInit(LS_BLINK|LS_ULINE);
   LCDClear();

   //Initialize ADC
   InitADC();

   //Put some intro text into LCD
   LCDWriteString("ADC Test");
   LCDWriteStringXY(0,1,"ADC=");

   while(1)
   {
      adc_result=ReadADC(0);           // Read Analog value from channel-0
      LCDWriteIntXY(4,1,adc_result,4); //Print the value in 4th column second line
      Wait();
   }
}

Download the code here .


Hardware:

You have to connect a LDR (light dependant resistor) as shown above. After burning the code on chip use a light source to throw some light on LDR, the ADC will show a value between 0-1024 depending on light. For dark the value should be close to 0 while for bright condition the value will become close to 1000.

No comments:

Post a Comment