| Author |
Message |
|
|
Posted: Jun 20, 2011 - 02:00 PM |
|

Joined: Oct 23, 2010
Posts: 66
Location: VIT University, Vellore, India
|
|
Hello everyone. This is my second post in the AVR Tutorials section. I have decided to post a tutorial on using the ADC of the AVR.
So basically, there's already a tutorial existing on this topic here. But I am posting my tutorial as it has a different approach. I have followed the kind of approach used in the datasheet.
Most people face difficulty in comprehending the bits of the registers. So, I have discussed all the registers here in brief. This not only gives a clear understanding about the programming, but also exposes the readers to all the possible things they could do with the ADC.
Please note that the registers discussed are according to ATmega16/32. But the concepts hold good for any AVR device.
The overview of the tutorial goes like this:
- Signal Acquisition Process
- Features of the AVR ADC
- ADC Prescaler
- ADC Registers - ADMUX, ADCSRA, ADCL, ADCH, SFIOR
- A real world example with code
- Sensor Calibration
Here is the link to the tutorial.
http://maxembedded.wordpress.com/2011/06/20/the-adc-of-the-avr/
If I have committed any mistakes, please notify me of them so that I could edit them.
I hope this is helpful to someone out there. I would love to hear any kind of response, suggestions, clarifications, etc from your side. The comments box is available here as well as in the site link.
I have also attached a PDF version of the tutorial. You can download it in case the above link doesn't show up. But prefer the link as it is more illustrated.
Thank You
Mayank
PS. The previous fault in the tutorial has been cleared and the post (along with the PDF) has been modified. |
_________________ AVR Guide and Tutorials
http://maxembedded.wordpress.com
Last edited by maxmiaggi on Nov 08, 2011 - 06:21 PM; edited 5 times in total
|
| |
|
|
|
|
|
Posted: Jun 20, 2011 - 06:47 PM |
|


Joined: Jul 18, 2005
Posts: 62354
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Thanks for posting the PDF.
Code:
// wait for convertion to complete
// ADIF becomes '1' when conversion is complete
// till then, run loop continuously
while(!(ADCSRA & (1<<ADIF)));
// clear ADIF bit for the next iteration
ADCSRA |= (0<<ADIF);
Two things here:
1) if you block on ADSC rather than ADIF (wait while it's high rather than low) then it self clears (goes back to 0) so you don't need to manually clear it.
2) If you are going to block on ADIF the way to clear it is:
// clear ADIF bit for the next iteration
Code:
ADCSRA |= (1<<ADIF);
(OR with 0 otherwise doesn't achieve very much ) |
_________________
|
| |
|
|
|
|
|
Posted: Jun 20, 2011 - 07:33 PM |
|

Joined: Oct 23, 2010
Posts: 66
Location: VIT University, Vellore, India
|
|
|
clawson wrote:
Thanks for posting the PDF.
Code:
// wait for convertion to complete
// ADIF becomes '1' when conversion is complete
// till then, run loop continuously
while(!(ADCSRA & (1<<ADIF)));
// clear ADIF bit for the next iteration
ADCSRA |= (0<<ADIF);
Two things here:
1) if you block on ADSC rather than ADIF (wait while it's high rather than low) then it self clears (goes back to 0) so you don't need to manually clear it.
2) If you are going to block on ADIF the way to clear it is:
// clear ADIF bit for the next iteration
Code:
ADCSRA |= (1<<ADIF);
(OR with 0 otherwise doesn't achieve very much  )
means that I should replace the statements with
Code:
while (ADCSRA & (1<<ADSC));
that's enough? i.e. no need to monitor ADIF anymore?
also, i tried out both of the following statements:
Code:
ADCSRA |= (1<<ADIF);
ADCSRA |= (0<<ADIF);
but there wasnt any significant change in the output.. |
_________________ AVR Guide and Tutorials
http://maxembedded.wordpress.com
|
| |
|
|
|
|
|
Posted: Jun 20, 2011 - 07:48 PM |
|

Joined: Oct 23, 2010
Posts: 66
Location: VIT University, Vellore, India
|
|
|
Code:
while (ADCSRA & (1<<ADSC));
i checked it.. it works absolutely fine! Thanks for the info.. I will update my post.. |
_________________ AVR Guide and Tutorials
http://maxembedded.wordpress.com
|
| |
|
|
|
|
|
Posted: Jun 20, 2011 - 08:08 PM |
|


Joined: Jul 18, 2005
Posts: 62354
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Yup just to confirm:
Code:
while (ADCSRA & (1<<ADSC));
which says "wait here while the ADSC bit remains set" - unless free running mode is being used it returns back to 0 after a single conversion.
Code:
ADCSRA |= (1<<ADIF);
ADCSRA |= (0<<ADIF);
Code:
0<<anything = 0
Code:
(anything | 0) = anything
So
Code:
ADCSRA |= (0<<ADIF);
is the ultimate "nop".
As the datasheet says, IF flags bits are cleared by writing 1 to them. So
Code:
ADCSRA |= (1<<ADIF);
is most definitely the way to do it (if you insist on using ADIF).
Although you say "but there wasnt any significant change in the output" there most definitiely would be if the input voltage was varying because you were blocking on ADIF!=1 and on the second and all subsequent readings the ADIF bit would still be 1 from last time. So there would be no delay waiting for the conversion to occur. |
_________________
|
| |
|
|
|
|
|
Posted: Jun 20, 2011 - 10:05 PM |
|

Joined: Oct 23, 2010
Posts: 66
Location: VIT University, Vellore, India
|
|
|
|
|
|
|
Posted: Jul 13, 2011 - 04:24 PM |
|

Joined: Jul 12, 2011
Posts: 34
|
|
Hi!
I'm trying to sample a signal at 10kHz. I made timer0 to generate an Output compare interrupt at this rate. I've set the ADC to be triggered by the timer interrupt. I was expecting that the ADC Conversion Complete interrupt to be triggered at 10kHz (the ADC clock is 250kHz), but this happens at 1.666KHz.
Can somebody tell me what I'm missing here? Or, how could i do this exact 10KHz sampling without using the timer.
Many thanks,
Monica |
|
|
| |
|
|
|
|
|
Posted: Jul 13, 2011 - 06:28 PM |
|


Joined: Jul 18, 2005
Posts: 62354
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Surely the timer interrupt occurs. You set ADSC to start a new conversion and then about 60us later (at 250kHz) the ADIF vector should fire where you collect the result?
BTW tutorial threads are not the right place to diagnose this kind of problem - you should start a thread in AVR forum. |
_________________
|
| |
|
|
|
|
|
Posted: Sep 24, 2011 - 05:52 PM |
|

Joined: Sep 24, 2011
Posts: 3
|
|
hii
i m using avr dragon to program at90usb1287 .
i m trying to read 0-5 volt from Port A Pin 1. due to some season my program doesn't work..
need help.
my code...
Code:
#define F_CPU 1000000UL
/* Clock Frequency = 1Mhz */
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <stdio.h>
#include <avr/sfr_defs.h>
#include <avr/interrupt.h>
#include <stdbool.h>
void init_ports(); //PORTC for output initialization
void init_adc();
void init_delay();
//void lowload();
//void highload();
unsigned char read_adc();/// read value
//unsigned char a;
void main()
{
// main function
init_ports();
init_adc();
while(1) //READ THE VALUE CONTINIOUSLY
{
PORTC = read_adc();
lowload();
// highload();
}
}
// initilizating the PORTS
void init_ports()
{
DDRC = 0xFF; // SET DDRC AS OUTPUT
PORTC = 0x00; //
DDRB = 0xFF;
PORTB = 0x00;
DDRE = 0xFF;
PORTE = 0x00;
}
void init_adc()
{
ADMUX = 0x01; // SETTING UP ADMUX CHANNEL
ADMUX = ADMUX | 0x40; // SETTING EXTERNAL VREF
ADMUX = ADMUX | 0x20; // JUSTIFICATION ADLAR
//ADCSRA = 0x00;
ADCSRA = 0x07;//DIVISION FACTOR
ADCSRA = ADCSRA | 0x80; //ENABLE THE ADC
DIDR0 = 0xFF;
//ADCSRA = 0x80; // START CONVERTING SIGNAL
}
unsigned char read_adc()
{
unsigned char a;
ADCSRA = ADCSRA | 0x40; // START CONVERTING SIGNAL
while( (ADCSRA & 0x10) == 0 );
a = ADCH;
ADCSRA = ADCSRA | 0x10;
return a;
}
void lowload()
{
if(PORTC == 0x06)
{
PORTE = 0x01;
}
}
|
|
|
| |
|
|
|
|
|
Posted: Sep 24, 2011 - 08:47 PM |
|


Joined: Jul 18, 2005
Posts: 62354
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
If you block on ADIF you must clear it - far better to block on ADSC anyway (the other way up).
BTW why are you using hex constants - all the SFR bits are defined in the .h ? |
_________________
|
| |
|
|
|
|
|
Posted: Oct 07, 2011 - 01:54 AM |
|

Joined: Sep 24, 2011
Posts: 3
|
|
THX A LOT FOR THE REPLY....
I AM TRYING MY BEST TO MAKE IT WORK. IF U CAN HELP ME WITH THE CODE THAN IT WOULD BE HIGHLY APPRECIATED. MY CODE IS..
Code:
#include <avr/io.h>
void init_ports();
void init_adc();
unsigned char read_adc();
void main()
{
init_ports();
init_adc();
while (1)
{
PORTC = read_adc();
}
}
void init_ports()
{
DDRC = 0xFF;
PORTC = 0X00;
// DDRB = 0xFF;
// PORTB = 0X00;
}
void init_adc()
{
ADMUX = 0x00;
//ADMUX = ADMUX | 0x00;
//ADMUX = ADMUX | 0x40;
//ADMUX = ADMUX | 0xC0;
ADMUX = ADMUX | 0x40;
ADMUX = ADMUX | 0x20;
ADCSRA = 0x07;
ADCSRA = ADCSRA | 0x80;
}
unsigned char read_adc()
{
unsigned char a;
//unsigned char b;
ADCSRA = ADCSRA | 0x40;
while( (ADCSRA & 0x10) == 0);
a = ADCH;
ADCSRA = ADCSRA | 0x10;
// PORTB = ADCL;
return a;
}
IF I MAKE ANY MISTAKE COULD U PLZ HELP ME WITH IT....
i am too much stressed cuz couldn't make it work for 1 month. tried all different possible ways to make it work.
my lecturer advised me to read 16 bit rather than 10 bit.
i tried that but did't work.
need some professional touch now....
thx a lot for yr reply
MY EMAIL ID: nembizpark@gmail.com
[As this is the wrong place to ask this kind of question and because you have already cross-posted this here: http://www.avrfreaks.net/index.php?name ... highlight= I will lock this thread - if anyone wants it reopened to make a post that is on-topic send a PM to clawson, js or plons] |
|
|
| |
|
|
|
|
|