xBoard v2.0
Easy to Use learning and development tool for Atmel AVR family of MCUs.
![]() |
Fig: ADC Theory |
Now you know the basics of ADC let us see how we can use the inbuilt ADC of AVR MCU. The ADC is multiplexed with PORTA (In ATmega32 and ATmega16) that means the ADC channels are shared with PORTA. The ADC can be operated in single conversion and free running more. In single conversion mode the ADC does the conversion and then stop. While in free running mode it is continuously converting. It does a conversion and then start next conversion immediately after that.
The ADC needs a clock pulse to do its conversion. This clock generated by system clock by dividing it(system clock) to get smaller frequency. The ADC requires a frequency between 50KHz to 200KHz. At higher frequency the conversion is fast while at lower frequency the conversion is more accurate. As the system frequency can be set to any value by the user (using internal or externals oscillators)( In xBoard a 16MHz crystal is used). So the Prescaler is provided to produces acceptable frequency for ADC from any system clock frequency. System clock can be divided by 2,4,16,32,64,128 by setting the Prescaler.
The ADC in ATmega32(or ATmega16) has 8 channels that means you can take samples from eight different terminal. You can connect up to 8 different sensors and get their values separately. In xBoard v2.0 only six out of 8 channels are available. This is to keep the size of the board small and place components at high density.
PORTA/ADC Port |
As you know the registers related to any particular peripheral module(like ADC, Timer, USART etc.) provides the communication link between the CPU and that peripheral. You configure the ADC according to need using these registers and you also get the conversion result using appropriate registers. The ADC has only four registers.
(Please Read the Tutorial "Internal Peripherals of AVR" before using ADC of AVRs.)
In this sample we will setup and use the ADC in single conversion mode. We will connect a LDR( light dependent resistor) (which is a light sensor) to input. The result will be shown in the LCD.
We have to configure the ADC by setting up ADMUX and ADCSRA registers. The ADMUX has following bits.
![]() |
REFS1 REFS0 selects the reference voltage. See table below
REFS1 | REFS0 | Voltage Reference Selection |
0 | 0 | ARef internal Vref Turned off |
0 | 1 | AVCC |
1 | 0 | Reserved |
1 | 1 | Internal 2.56 Voltage Reference |
ADMUX=(1<<REFS0);//Set REFS0 bit in ADMUX register.
The ADCSRA Register.
![]() |
//Wait for conversion to complete while(!(ADCSRA & (1<<ADIF)));The loop does nothing while ADIF is set to 0, it exits as soon as ADIF is set to one, i.e. conversion is complete.
![]() |
We need to select division factor so as to get a acceptable frequency from our 16Mhz clock. We select division factor as 128.So ADC clock frequency = 16000000/128 = 125000 = 125KHz (which is in range of 50KHz to 200KHz). So we set ADCSRA as
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(ADPS1)|(ADPS0); //Enable ADC with Prescalar=Fcpu/128
Now every thing is set up. We now write a routine that will ReadADC.
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
ADCSRA|=(1<<ADIF);
return(ADC);
}
We can call this function from any where in our code and simply need to pass
0-7 as for which channel we need to read. It will select the ADC channel first
and then it will request for ther ADC to sample and Convert the analog value
at that input channel. After that the function will wait till the ADC is busy
doing the conversion. As soon as the conversion is complete it will return
the converted value.
The following is complete code to Read ADC Channel 0(PA0) and display its value on LCD.
/*********************************************************************
xBoard(TM) v2.0 Sample Programs
------------------------------------
Description : Demonstrate the use of ADC interfacing functions.
Author : Avinash Gupta
Web : www.eXtremeElectronics.co.in
Copyright 2008-2010 eXtreme Electronics, India
**********************************************************************/
#include <avr/io.h>
#include <util/delay.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;
//Wait for LCD to Startup
_delay_loop_2(0);
//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();
}
}
![]() |
Fig: LDR Connected to ADC of AVR |
You have to connect a LDR (light dependant resistor) as shown above. Get Vcc and GND from connector labled 5v and GND on the PCB. For the location of extra 5v and GND supply refer to this document.
ADC Port and Extra 5v Supply
Output |
After burning the code on chip, use a light source to throw some light on LDR, the LCD 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.
If you do not have a LDR handy, you can also use a 10K POT as a potential divider. Connect the LEFT PIN to GND, RIGHT PIN to 5v and the CENTER PIN to INPUT of ADC with a 10K resistor in series. Now you can rotate the POT to vary the Input to ADC from 0v to 5v. So when the input is 0v the value displayed will be 0 and when it reaches close to 5v the output will advance towards 1023.
![]() |
Fig: POT Connected to ADC of AVR |
Note: