[TUT] [C] Newbie's Guide to the AVR ADC

Go To Last Post
324 posts / 0 new

Pages

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thaks..
could i have the asembly code too??

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thnks very much penquissciguy.. your tutorial is very helpful.. i'm very very very new to avr..

I have 2 simple questions..

1. In your tutorial, you mention that

"There are several selectable voltage references, which determine the range of the ADC conversion."

Can you please explain this in detail? How does the voltage reference determine the range of ADC conversion?

2. If I wanted to test your code using ATmega8, can I simply connect AVCC with VCC? I actually dont understand what's the purpose of having the AVCC pin..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ATmega 128

When I run this code, As soon as it gets to the for(;;) "Forever loop". The interrupt causes it to reset to the beginning of MAIN. It is acting like a reset vector to the beginning of the application, instead of going to ISR(ADC_vect).

Is this because I have a fuse setting wrong...?

I'm thinking that because sei is enabled, that something is triggering a "power up reset".

I am a noob so...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Could it be because, I have the SPIEN fuse enabled, but no ISP connected and it is causing reset somehow?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I made sure the reset pin was held high, no difference.

Something is causing a reset vector to the beginning.

I am using an STK300, I also made sure the supply voltage is > Aref.

The Studio 4 tutorial mentions an "Info View" window with an interrupt vector section...but I can't seem to find such a window...that could help me debug this

Keep in mind it only resets after the sei(); occurs.
(Actually one statement after that,as the datasheet says the instruction folowing the SEI will be excecuted before any pending interrupts.)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

problem solved my Winavr had an old library in it the interrupt.h had sei ,but not ISR functionality.

I reloaded with the updated library

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello! A little help please.

I test adc with a battery. As I use 8bit mode, I get normal value near 130.

Somewhy, I'm unable to convert it to volts (Internal 2.56v as reference). With this code I get strangely jumping values from -10000 to 10000(nearly).

(I tried reading ADCH directly, without using tempv)
(Code below uses prescale of 128, runs on atmega32 at 8Mhz, free running conversion)

#include 
#include "lcd.c"
#include 
#define F_CPU 8000000UL
#include 
#include 

int tempv=0;
char disp[32];

void adc_setup(void){
	ADMUX |= _BV(REFS0) |  _BV(REFS1) | _BV(ADLAR);
	ADCSRA |= _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS1) | _BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIE);
	sei();
}

ISR(ADC_vect){
	tempv = ADCH;
	sprintf(disp, "val: %d\n %d v.", tempv, (2.56/255) * tempv);
	lcd_clrscr();
	lcd_puts(disp);
	_delay_ms(150);
}

int main(void){
	lcd_init(LCD_DISP_ON);
	adc_setup();
	while(1)
	;;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
sprintf(disp, "val: %d\n %d v.", tempv, (2.56/255) * tempv);

You're formatting float values as regular integers. Try replacing the "%d"s in the format string with "%f"s. Alternatively, cast the float value back to an int:

sprintf(disp, "val: %d\n %d v.", tempv, (int)((2.56/255) * tempv));

Which would remove the decimals.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also, a better (non-floating point) way would be:

unsigned int convertedtempv = (unsigned int)((256L * tempv) / 25500);

sprintf(disp, "val: %d\n %d v.", tempv, convertedtempv))

As the calculation is performed in fixed point. That will give the same results (to a few decimal places) but take a MUCH smaller amount of FLASH memory and time to execute.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your help, Dean :)

Unfortunately, nor

sprintf(disp, "val: %d\n %d v.", tempv, (int)((2.56/255) * tempv)); 

neither

unsigned int convertedtempv = (unsigned int)((256L * tempv) / 25500);
sprintf(disp, "val: %d\n %d v.", tempv, convertedtempv)) 

did not work as expected, they were cutting everything to decimal point(for example I get 1 volt instead of ~1.3).

I've found what was the problem though. When changing "%d" to "%f", special linker options are needed, as there are three versions of printf functions and only one includes floating point conversions. After compiling my code the right way, I'm totally happy with proper conversion to volts :D

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

how to read the adc channel value??i mean i've put the sensors output to adc pins...now i want to get the sensor readings for further processing...pls help.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

how to read the adc channel value??i mean i've put the sensors output to adc pins...now i want to get the sensor readings for further processing...pls help.

That's a joke, right? You're asking how to use the ADC, in the thread whose original post is a complete guide to using it. Read the tutorial on page one.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just wanted to add the following...

...before you spend days trying to get your ADC going and resort to RTFM, remember that if the result is right adjusted you must first read the ADCL and then ADCH, not the other way around.

Correct:

in R16,ADCL
in R17,ADCH

Incorrect:

in R16,ADCH
in R17,ADCL

The manual (ATtiny26) is right about it. I've checked. :oops:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can anyone help me to handle 48 volt DC to the port of AVR? I will be really grateful, if anybody helps me in this regard..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi

Firstly thanks for the ADC tutorial, I have used it to write a looped ADC function of my own, however the reading I get never seems to change, was wondering if anyone could shed some light on where I am going wrong (running on the mega1281)?

int main (void) {

   DDRE |= (1 << 2); // Set LED1 as output
   DDRG |= (1 << 0); // Set LED2 as output    

   ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS0);

   ADMUX = (0 << REFS0) | (0 << REFS1); // Set ADC reference to AREF

   ADCSRB |= (0 << ADTS0);
   ADCSRB |= (0 << ADTS1);
   ADCSRB |= (0 << ADTS2); // free run mode

   ADMUX |= (1 << MUX0); // ADC Chan1

   ADCSRA |= (1 << ADEN);  // Enable ADC
   ADCSRA |= (1 << ADSC);  // Start A2D Conversions

   while (1) {
      
	  uint16_t data = 0;

     // Read ADC conversion result
	  data = (uint16_t) ADCL;
	  data |= (uint16_t) ADCH << 8;
	  
	  if(data < 128)
      {
         PORTE |= (1 << 2); // Turn on LED1
         PORTG &= ~(1 << 0); // Turn off LED2
      }

      else
      {
         PORTE &= ~(1 << 2); // Turn off LED1
         PORTG |= (1 << 0); // Turn on LED2
      } 

   } // while


} // main

Many thnaks for any help you can offer :)

FR

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wow!!! Thanks for the in depth & detailed tutorial! It's just the perspective I've been looking for. Thanks everyone for all the additional posts & added information as well! Anyone have any specific insight on tiny's?? I'm playing with tiny13 for a remote sensing application- thoughts?
lefthand112 :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Compiler: AVR-GCC
IDE: AVR Studio, Version 15.4
Problem: Code compiles with errors

Great tutorial! I'm trying to run this code on my ATmega32. What conversions do I need to do (besides changing the ports)?

CODE:

#include 

int main (void)
{
   //PORTE WAS REPLACED WITH PORTD
   //PORTG WAS REPLACED WITH PORTB 
   DDRD |= (1 << 2); // Set LED1 as output
   DDRB |= (1 << 0); // Set LED2 as output

   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescalar to 128 - 125KHz sample rate @ 16MHz

   ADMUX |= (1 << REFS0); // Set ADC reference to AVCC
   ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading

   // No MUX values needed to be changed to use ADC0

   ADCSRA |= (1 << ADFR);  // Set ADC to Free-Running Mode
   ADCSRA |= (1 << ADEN);  // Enable ADC
   ADCSRA |= (1 << ADSC);  // Start A2D Conversions

   for(;;)  // Loop Forever
   {
      if(ADCH < 128)
      {
         PORTD |= (1 << 2); // Turn on LED1
         PORTB &= ~(1 << 0); // Turn off LED2
      }

      else
      {
         PORTD &= ~(1 << 2); // Turn off LED1
         PORTB |= (1 << 0); // Turn on LED2
      }

   }

}

ERRORS:

    ../adcexample.c:18: error: 'ADFR' undeclared (first use in this function)

    ../adcexample.c:18: error: (Each undeclared identifier is reported only once

    ../adcexample.c:18: error: for each function it appears in.)

    make: *** [adcexample.o] Error 1
    Build failed with 3 errors and 0 warnings...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The ADFR equivalent is ADATE on m32 isn't it? (just going from memory here)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, or at least the default behavior of setting ADATE is the same as ADFR.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I stumbled past this tutorial and I was just wondering what is required to change both the analog reference and the input address. I am using an Attiny85, so the default presented will not work for me. Also, where can I find more complete documentation on programming the ADC?

Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

what is required to change [...] the input address

The names of the ADC control registers are in the data sheet for your AVR. The addresses of those registers should be in the part specific include file, but a specific answer depends on what compiler/assembler you are using.

Quote:

Also, where can I find more complete documentation on programming the ADC?

In the data sheet for the AVR model you are using.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I found the registers on the datasheet, I just don't know where to insert them into the code. Same situation with using AREF over AVCC. I'm using Winavr (avr-gcc), if that helps.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I found the registers on the datasheet, I just don't know where to insert them into the code.

What registers are you talking about? The sample code uses ADMUX, the tiny85 has an ADMUX. The sample code has an ADCSRA, the tiny85 has an ADCSRA. The tiny85 does have an ADCSRA, but the bits of that register are explained in the datasheet.

Quote:
Same situation with using AREF over AVCC.

If you want AREF as the voltage reference, then set the REFSx bits to the proper value.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just to clarify,

I've figured out that I need to set REFS0 and REFS1 to 0. Thats no problem, because they are 0 by default, but for REFS2 it says to set it to 'X'. How do I go about doing that? I'd also like to change the A/D channel to ADC2, but again, I don't know where I can find out how to do that (I think it has to do with ADCH). Any advice is appreciated.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

but for REFS2 it says to set it to 'X'

A single bit can not be set to 'X'. The 'X' means "don't care". When you have REFS0 and REFS1 both set to zero REFS2 has no meaning.

Quote:

I'd also like to change the A/D channel to ADC2, but again, I don't know where I can find out how to do that (I think it has to do with ADCH).

No, ADCH contains the high bits of the conversion result. You select the channel with the MUX3:0 bits in the ADMUX register.

There is a section in the data sheet called "Changing Channel or Reference Selection". Your PDF reader has a search function. I know the ADC section in the data sheet is 18 dense pages, but you really need to read through all those pages from start to end. Not everything might be clear after that, but you will stand a much better chance of seeing your endeavour with the ADC through to a successful end.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is what I came up with after adapting the tutorial. It's not working, so I'm posting it up to see if there is anything wrong with the code, or if it's the hardware config.

#include      
#include 

int main(void)
{
  
  DDRB = 0b00001000;
  
  ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescalar to 128 - 125KHz sample rate @ 16MHz
  
  ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading
  ADMUX |= (1 << MUX1);  // Sets input to 0010, or ADC2
  
  ADCSRA |= (1 << ADATE); // Set ADC to Free-Running Mode
  ADCSRA |= (1 << ADEN);  // Enable ADC
  ADCSRA |= (1 << ADSC);  // Start A2D Conversions 
    
  while(1)
  {
    if(ADCH > 128)
    {
	  PORTB = 0b00001000;
    }
	else PORTB = 0b00000000;
  }

  return 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Never mind my above post - I got it figured out

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

FiniteRed wrote:
Hi

Firstly thanks for the ADC tutorial, I have used it to write a looped ADC function of my own, however the reading I get never seems to change, was wondering if anyone could shed some light on where I am going wrong (running on the mega1281)?

int main (void) {

   DDRE |= (1 << 2); // Set LED1 as output
   DDRG |= (1 << 0); // Set LED2 as output    

   ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS0);

   ADMUX = (0 << REFS0) | (0 << REFS1); // Set ADC reference to AREF

   ADCSRB |= (0 << ADTS0);
   ADCSRB |= (0 << ADTS1);
   ADCSRB |= (0 << ADTS2); // free run mode

   ADMUX |= (1 << MUX0); // ADC Chan1

   ADCSRA |= (1 << ADEN);  // Enable ADC
   ADCSRA |= (1 << ADSC);  // Start A2D Conversions

   while (1) {
      
	  uint16_t data = 0;

     // Read ADC conversion result
	  data = (uint16_t) ADCL;
	  data |= (uint16_t) ADCH << 8;
	  
	  if(data < 128)
      {
         PORTE |= (1 << 2); // Turn on LED1
         PORTG &= ~(1 << 0); // Turn off LED2
      }

      else
      {
         PORTE &= ~(1 << 2); // Turn off LED1
         PORTG |= (1 << 0); // Turn on LED2
      } 

   } // while


} // main

Many thanks for any help you can offer :)

FR

I'm still having trouble with this sadly, has anyone got any ideas?

Thanks

FR

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ADCSRB |= (0 << ADTS0);
ADCSRB |= (0 << ADTS1);
ADCSRB |= (0 << ADTS2); // free run mode

This sets the trigger source for auto-trigger mode. But if you don't actually put the ADC into auto-trigger mode, it does nothing. You need to set the ADATE bit.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Am I too tired, or is

(0 << ADTS0); 

always zero, and thus

ADCSRB |= (0 << ADTS0); 

meaningless? It is equivalent to

ADCSRB = ADCSRB | (0 << ADTS0);

which becomes

ADCSRB = ADCSRB | 0;

which is equivalent to

ADCSRB = ADCSRB;

So, am I too tired?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No, I think that it is me who is too tired since I completely missed that.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

:D Ah wonderful! Thank you very much – iv been stuck on that for ages :D :D

FR

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Microcontroller: ATmega32
Goal: Want to multiplex through each ADC pin (ADC0-ADC7)
Issue: Not sure how to modify the code.
Programmer: AVRisp MkII
Compiler: GCC/Win-AVR
IDE: AVR Studio 4, Version 4.15

Great tutorial. How could I revise the code to multiplex through ADC0-ADC7? I want to pull a value from each channel one-by-one, and then use those values to update my output bits. I want this cycle to run in an endless loop.

Should I just set my first ADC pin to free-running -> get the value -> then set the second pin to free-running and continue this process? It seems like there would be a more efficient way.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Stay clear of free running if you are multiplexing. If you are happy with polling (and slotting in the actual "work" after each reading) then something like:

#include  

int main (void) 
{ 
   uint8_t channel = 0;
   DDRE |= (1 << 2); // Set LED1 as output 
   DDRG |= (1 << 0); // Set LED2 as output 

   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescalar to 128 - 125KHz sample rate @ 16MHz 

   ADMUX |= (1 << REFS0); // Set ADC reference to AVCC 
   ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading 

   ADCSRA |= (1 << ADEN);  // Enable ADC 
   ADCSRA |= (1 << ADSC);  // Start A2D Conversions 

   for(;;)  // Loop Forever 
   { 
      // TODO: Test ADC Value and set LEDs
      ADMUX &= 0xF8; // clear existing bottom 3 bits 
      ADMUX |= channel; // add in 0..7
      ADCSRA |= (1<<ADSC); // start conversion
      while(ADCSRA & (1<<ADSC)); // wait for completion
      
      // use ADCH value (or drop ADLAR and 
      //  use ADCH/L or ADCW)
      // possibly delay() for results to be seen

      channel++;
      if (channel > 7) {
        channel = 0;
      }
   } 
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Or use the ADC interrupt. When the interrupt happens, grab the value, set the next channel, then start the next conversion.

Quote:
then set the second pin to free-running

You don't set each pin to free-running, you set the ADC to free-running. But I agree with Cliff, no need for free-running here. In free-running, when you set the channel, a conversion is already in progress, so the channel change won't take effect until the next conversion.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey thanks a bunch clawson and koshchi! I got the code to work perfectly.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank You! Good tutorial!
I need for NIMH charger measure 4 Nimh element voltage about 1,25V and place all numbers same time on the one LCD.Using AtMega88.
Whats AVR ADC measure method I need use for tolerance 1,xx volt to 1,55V?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I commented out the line that shifts the conversion to 8-bit:

ADMUX |= (1 << ADLAR);

So I assume it should be the default 10-bit, or out of 1024. The problem is that it is now returning very low values. Does this have to do with the prescaler, or am I missing something in reading it properly?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You realise that if you set ADLAR then it's enough to just read ADCH but if you don't have it set then to get a 10 bit reading you must read ADCL and ADCH and it MUST be in that order? (your C compiler may offer a composite 16 bit access register called "ADC" or "ADCW" which guarantees the order they are read)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I do not totally understand how to read both... How would I put both values into one?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, can I use this tutorial for understanding the atmel mega 16 processor's ADC?

If not, is there any similar guide for the atmel mega 16 ADC?

Kind regards

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Hi, can I use this tutorial for understanding the atmel mega 16 processor's ADC?

Yes.

(The quality of the answers you get is highly correlated with the quality of the question you ask.)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, I also want to made an ADC conversion. I wrote a programme in C for my meg32, and I want to check it in AVR Studio by simulation. In this case I can represent the analog signal only be apply 1 (reference voltage) or 0 (zero voltage) to ADC0 (PINA). Theoretically the output of the ADC has to be 255 (using 8bit) if PINA=1 and 0 if PINA=0, isn't it? But the values of the ADC bits remains zeros for both case.
Is the mistake in my code, or the AVR Studio is not capable to simulate the ADC?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can't simulate analog in the simulator but what you can do is put a breakpoint at the process where ADCH/L has just been read then edit the register contents there to try differing values between 0..1023 or 0..255 (ADLAR). Or replace you "ADC_read()" routine with a dummy routine that just returns the next value of some test data each time it is called.

(or you could just work with real hardware and connect up a variable resistor to the pin and "twiddle" it)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very useful tutorial, thanks :D

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Clawson for your reply. It works fine.

I have another question, probably somebody can give me advice.
I want to measure three values and calculate an output from them. I use a ATMmega32 controller. I have a routine which reads and converts the analog values (from ADC0, ADC1 and ADC2) to digital than it calculates the output. I want to use a numerical integral, so I want a fix sampling time (eg 2ms). So every 2ms the routine is called (I assume that the routine is faster than 2ms). How can I solve such a synchronization?
thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I want to make an ADC conversion and with the JTAG ICE mkII i made the debugging. I download the avrlib files and from them I include into my project the timer.h/.c files to measuring the ADC time. I select the CPU frequency 8MHz and I select the divison factor 8 for TCNT0. So it ticks every 0.001ms. For the ADC conversion I select factor 64, so 125kHz. According to my Atmel32 datasheet the conversion time takes 13 cycles, so 0.104ms. So theoretically the command lines

ADCSRA |= (1<<ADSC);
while(ADCSRA & (1<<ADSC));

takes 0.104ms which means the TCNT0 timer have to ticks 104. Instead of that it ticks only 1. (The conversion produce a good result, I convert DC voltage to digital and the value what I get is good)
Probably I made mistake somewhere, but I check it million times and I don't know what is the problem. Anybody has a suggestion? thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To the original poster:

Thank you for the nice tutorial! I adapted it pretty easily to accommodate the different setup for free-running mode in the ATTiny861 in only a short time:

ADCSRA |= (1<<ADATE);
ADCSRB &= (0<<ADTS2) | (0<<ADTS1) |(0<<ADTS0);

ADCSRA |= (1<<ADEN);
// ... continue ...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ADCSRB &= (0<<ADTS2) | (0<<ADTS1) |(0<<ADTS0);

That line does nothing. Did you mean to clear those bits? If so I think you meant:

ADCSRB &= ~((1<<ADTS2) | (1<<ADTS1) |(1<<ADTS0));

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Clawson,

The code works, but only by luck, so right you are. I'll fix that straightaway, thanks!

Pages

Topic locked