Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   This topic is locked: you cannot edit posts or make replies.
View previous topic Printable version Log in to check your private messages View next topic
Author Message
maxmiaggi
PostPosted: Jun 20, 2011 - 02:00 PM
Wannabe


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
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Jun 20, 2011 - 06:47 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62299
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 Wink)

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
maxmiaggi
PostPosted: Jun 20, 2011 - 07:33 PM
Wannabe


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 Wink)


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
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
maxmiaggi
PostPosted: Jun 20, 2011 - 07:48 PM
Wannabe


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
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Jun 20, 2011 - 08:08 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62299
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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
maxmiaggi
PostPosted: Jun 20, 2011 - 10:05 PM
Wannabe


Joined: Oct 23, 2010
Posts: 66
Location: VIT University, Vellore, India

hmm.. i guess i get it now.. thanks a lot! Smile

_________________
AVR Guide and Tutorials
http://maxembedded.wordpress.com
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
monicazo
PostPosted: Jul 13, 2011 - 04:24 PM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jul 13, 2011 - 06:28 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62299
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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
nembizpark
PostPosted: Sep 24, 2011 - 05:52 PM
Newbie


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;
            
            }
            
      
      }
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 24, 2011 - 08:47 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62299
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 ?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
nembizpark
PostPosted: Oct 07, 2011 - 01:54 AM
Newbie


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]
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   This topic is locked: you cannot edit posts or make replies.
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits