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

Go To Last Post
326 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wanted to learn more about the ADC on my ATMega128, so I dug into the docs and taught myself a couple things. I thought since there wasn't a tutorial on this topic I'd write one. Hope this helps someone out. Comments, clarifications and constructive criticism welcomed!

Newbie's Guide to the AVR ADC
© Ken Worster

No part of this document is to be redistributed without the copyright holder's express permission.

What is an ADC?

An ADC, or Analog to Digital Converter, allows one to convert an analog voltage to a digital value that can be used by a microcontroller. There are many sources of analog signals that one might like to measure. There are analog sensors available that measure temperature, light intensity, distance, position, and force, just to name a few.

Introduction – The AVR ADC

The AVR ADC allows the AVR microcontroller to convert analog voltages to digital values with few to no external parts. The author wrote this tutorial with the ATMega128 in mind, though other AVRs use similar hardware. The ADC built into the ATMega128 is capable of 10 bit resolution. The ATMega128 microcontroller has 8 ADC channels, allowing up to 8 analog sources to be attached to the microcontroller. The 8 ADC channels are connected to the internal DAC through a device called a multiplexer. The multiplexer connects the 8 ADC channels (the 8 pins of Port F on the ATMega128) to the internal ADC. One channel at a time is passed through the multiplexer to the ADC. The ADC has its own power supply, labeled AVCC, on the ATMega128. This pin needs to be connected to a power source within .3 volts of the chip's VCC supply. Most of the time, you would wire this to VCC. With the 10 bit DAC, this allows measuring voltages from 0 to 5 volts with a resolution of 5/1024 volts, or 4.88 mV.

The ADC channels in the ATMega128 can be configured in several different ways. In this tutorial, the channels are being used in “single-ended” mode. In this mode, the analog voltages presented on the ADC channels are compared to ground. There are several selectable voltage references, which determine the range of the ADC conversion. In this tutorial, AVCC is used as the voltage reference. The ADC can also be set to run continuously (the free-running mode) or to do only one conversion. The first example in this tutorial uses the free-running mode to continuously update the ADC reading.

Part 1 – A Simple Free-Running ADC Example

This example uses the simplest variable voltage source I could think of – a potentiometer. I wired up a 10k potentiometer on a breadboard as in the example below.

The two outside terminals were attached to 5 volts and ground, with the center terminal attached to the first ADC channel. The two 330 ohm resistors protect the microcontroller pin from being shorted to ground or to 5 volts at the edges of the potentiometer's travel. With this setup, turning the potentiometer will give you a range of .15 volts to 4.85 volts between ground and ADC0. In order to read the voltage of this circuit, its ground and the ground of the microcontroller need to be connected.

To give an indication of the value the ADC is reading, two LEDs are hooked to the microcontroller. We can toggle these to give us a “high” or “low” indication. Here is the pseudocode for this example:

Set up output LEDs
Configure ADC Hardware
Enable ADC 
Start A2D Conversions 

WHILE Forever
	IF ADC Value High, Turn on LED1
	ELSE Turn on LED2
END WHILE

To simplify this example, we will set up the ADC to continuously measure the voltage on ADC0. We will then poll the value in an endless loop and change the LEDs' statuses as we need to. The skeleton code for our example would then be

#include  

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

	// TODO:  Configure ADC Hardware
	// TODO: Enable ADC
	// TODO: Start A2D Conversions

for(;;)  // Loop Forever 
	{ 
		// TODO: Test ADC Value and set LEDs
	}
}

Setting up the LEDs is outside the topic of this tutorial, so the code to set them up is shown above without explanation. You can use any unused i/o line for the LEDs. Check out the “Programming 101” tutorial on the AVRFreaks forum for more information on this if you need it.

The next step is to configure the ADC hardware. This is done through setting bits in the control registers for the ADC. First, let's set the prescalar for the ADC. According to the datasheet, this prescalar needs to be set so that the ADC input frequency is between 50 KHz and 200 KHz. The ADC clock is derived from the system clock. With a system frequency of 16 MHz, a prescaler of 128 will result in an ADC frequency of 125 Khz. The prescaling is set by the ADPS bits in the ADCSRA register. According to the datasheet, all three ADPS bits must be set to get the 128 prescaler.

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

Next, let's set the ADC reference voltage. This is controlled by the REFS bits in the ADMUX register. The following sets the reference voltage to AVCC.

ADMUX |= (1 << REFS0);

To set the channel passed through the multiplexer to the ADC, the MUX bits in the ADMUX register need to be set accordingly. Since we are using ADC0 here, which corresponds with all 5 MUX bits being zero, we don't need to set anything here.

In order to put the ADC into free-running mode, set the aptly-named ADFR bit in the ADCSRA register:

ADCSRA |= (1 << ADFR);

One last settings change will be made to make reading the ADC value simpler. Though the ADC has a resolution of 10 bits, this much information is often not necessary. This 10 bit value is split across two 8 bit registers, ADCH and ADCL. By default, the lowest 8 bits of the ADC value are found in ADCL, with the upper two being the lowest two bits of ADCH. By setting the ADLAR bit in the ADMUX register, we can left align the ADC value. This puts the highest 8 bits of the measurement in the ADCH register, with the rest in the ADCL register. If we then read the ADCH register, we get an 8 bit value that represents our 0 to 5 volt measurement as a number from 0 to 255. We're basically turning our 10 bit ADC measurement into an 8 bit one. Here's the code to set the ADLAR bit:

ADMUX |= (1 << ADLAR);

That completes the setup of the ADC hardware for this example. Two more bits need to be set before the ADC will start taking measurements. To enable the ADC, set the ADEN bit in ADCSRA:

ADCSRA |= (1 << ADEN);

To start the ADC measurements, the ADSC bit in ADCSRA needs to be set:

ADCSRA |= (1 << ADSC);

At this point, the ADC would begin continuously sampling the voltage presented on ADC0. The code to this point would look like this:

#include 

int main (void)
{
   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

   // 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
	{
		// TODO: Test ADC Value and set LEDs
	}
}

The only thing left to do is test the ADC value and set the LEDs to display a high / low indication. Since the ADC reading in ADCH has a maximum value of 255, a test value of 128 was chosen to determine whether the voltage was high or low. A simple IF/ELSE statement in the FOR loop will allow us to turn the correct LED on:

if(ADCH < 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
		}

Again, if the notation used above is unclear, the “Programming 101” tutorial at AVRFreaks forum gives a great explanation.

Here's the finished program with comments. When compiled and downloaded to an ATMega128, LED1 will be lit for roughly half the rotation of the potentiometer, indicating a “low” voltage reading. Near the halfway point of the potentiometer's rotation, LED1 will go out and LED2 will light. Indicating a “high” voltage reading. By changing the tests in the FOR loop, one could get different voltage indications with two or more LEDs.

#include 

int main (void)
{
   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

   // 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)
		{
			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
		}

	}

}

Part 2 – An Interrupt-Driven Example

Let's improve the first example so that we can run the LED IF loop “in the background”. It takes 13 cycles of the ADC clock to perform one A2D conversion in free-running mode according to the datasheet. With a prescaler of 128 as in the previous example, there are 13x128, or 1664, system clock cycles between each A2D conversions. If our short IF loop can be run only after an A2D conversion, this allows considerable processing time to be dedicated to other tasks.

Microcontrollers allow this kind of program execution using something called interrupts. Certain pieces of hardware within the microcontroller can signal that a certain task has been completed. Normal program execution can be “interrupted” when one of these signals (the interrupt) is asserted. Depending on the interrupt signal, different user-defined programs, called interrupt service routines or ISRs, can be run. After the ISR completes, normal program execution resumes.

The AVR ADC has an interrupt associated with it that is asserted when an A2D conversion completes. There are several changes that need to make to the first example to utilize this interrupt. First, let's write the ISR that will be run when the interrupt is asserted.

The first step in using interrupts in our application is to add the standard library header avr/interrupt.h. This file defines functions and macros needed to utilize interrupts on the AVR. The following line should be added below the io.h define in our original program.

#include 

Next, we'll define the ISR itself. To do this, we need the name of the interrupt we are connecting to the ISR. Referring to the datasheet, we find the name of the interrupt we want to use – ADC, which is asserted when an A2C conversion completes. Here is the proper format for an ISR using the ADC interrupt:

ISR(ADC_vect) 
{ 
	// Code to be executed when ISR fires 
}

Now, we place the IF statement originally in the infinite loop inside the ISR, so it will only be run when the ADC interrupt indicates a conversion has been completed:

ISR(ADC_vect) 
{ 
	if(ADCH < 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 
		} 	 
}

At this point, the program has an ISR defined. However, the ISR will never execute. Interrupts on the AVR need to be enabled before they will run. This is done in two steps. First, the interrupt capability of the microprocessor needs to be enabled. This is done with the sei() function call, defined in interrupt.h to simplify this process. Next, the ADC interrupt needs to be enabled. This is done by setting the ADIE bit in the ADCSRA register. The following two lines enable the ADC interrupt:

ADCSRA |= (1 << ADIE);
sei();

We can now combine the new interrupt code with our first example. We will insert the ISR after the main loop. The interrupt enable lines will be inserted before we start the A2D conversions. The FOR loop is now empty, as the code we had there originally has been moved to the ISR. Other code could be inserted here to run between ISR calls. The full code is shown below.

#include 
#include 

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

	ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescaler 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 << ADIE);  // Enable ADC Interrupt
	sei();	// Enable Global Interrupts

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

	for(;;)  // Loop Forever
	{
	}
}

ISR(ADC_vect)
{
	if(ADCH < 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
	}
}
Last Edited: Tue. Jun 23, 2015 - 12:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Awesome! Mind if I add this to the starter guide?

Michael

Dragon Slayer... no not that one...This one!

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

Very well done - I do like your writing and example style. It reminds me heavily of my own tutorials, which many people like.

Looking forward to more tutorials from you in the future!

- Dean :twisted:

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

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

ttownfire wrote:
Awesome! Mind if I add this to the starter guide?

Please do. Thanks!

abcminiuser wrote:
Very well done - I do like your writing and example style. It reminds me heavily of my own tutorials, which many people like.

:D

I intentionally copied the structure of your tutorials. I really like how yours flow from one topic to the next. Having a common tutorial structure might also help some know where to find certain information in a new tutorial and make code examples easier to follow.

abcminiuser wrote:
Looking forward to more tutorials from you in the future!

Thanks, I appreciate that. I'm hoping to expand this one in the near future.

Ken

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

I've added a simple interrupt-driven example. Comments welcome!

Ken

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

I have only starting dabbling with AVR coding.. this tutorial was very useful. Thanks.

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

Thanks for your tutorial!

I can't see your images...
Maybe the image hosting service you used is down.

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

kioanakos wrote:
Thanks for your tutorial!

I can't see your images...
Maybe the image hosting service you used is down.

The image is hosted on my personal webspace, so I think it should be OK. I reloaded the page on my machine and everything seems to be OK.

Ken

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

No dice here. The progress bar in the browser takes a while, and then it fails to load the images, shown by with a small frame with a red X in IE, a dimmed image icon in Firefox. Trying the direct url to one of the images (http://www.intergate.com/~scienc...) results in a non-responsive server error.

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

The only image above is this isn't it?

Attachment(s): 

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

Well Cliff, either the problem is not global or you have just proved that your cache is working. Still can't see it in the OP.

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 can see it in OP post with FF and XP. No problems (And it's my first time here so no cache).

And nice tutorial indeed... At first I though it was Dean, who wrote it, but then I saw his name on the first comment and had to look again and surprise- surprise, it was penquissciguy. hehe ;)

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

great tutorial very helpful...

i'm actually using a similar functionality in a project. should i turn the ADC off somehow when i'm not using it? if so whats the best way...

i am curious because i am trying to save power. is this a problem?

basic idea of project: user control =
1) remotely turn leds on or off
2) use the adc (via rssi) to control the leds

if the user uses the adc then goes back to manual mode the adc will still be running correct? what about interrupting? is it constantly interrupting if it's turned on (the ADC that is)?

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

Well it's the ADEN bit that turns it on, so clearing that will turn it off.

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

Thanks, this tutorial is very usefull.

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

Hello

Easy to follow very instructive with well placed useable material.

Thank you
Stephen :wink:

Codevisionavr & Avrstudio 4.18
Easyavr5A-Jtagicemk1

Call me Pedantic, But not after 9.

if Milk_Brilliant
else Codevision_Avrs==Better

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

mega 16 adc chanels are multiplexed.it means at a given time there is only one conversion.
what in case we are using several sensors to guide a robot motion?

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

Does the rate really need to be faster than the "round robin" rate you can achieve using the multiplexer? If so then use a number of Tiny's/small Mega's in parallel and "network" them using I2C or SPI or similar.

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

Thanks for the tutorial. It only destroyed my atmega8 :)

I'm a Newbie! ... and it's not my fault!!

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

Thanks for the tutorial! Much appreciated!

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

very well written tutorial. Simple and Descriptive.

Thank You

Nagi

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

Hi
WhenI try to compile The last example in this tutorial (with AVR Studio) I get the message

Quote:
error; 'ADFR' undeclared (first use in this function)

How can i correct this..

Magnus

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

magnusrt wrote:
How can i correct this..

Maybe start by identifying which AVR you are using?

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

Sorry!
Mega88

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

Well if you go to the ADC chapter of the 48/88/168 datasheet and search for "free" you get SOME clues - though it may not be entirely obvious that they now also refer to it as "auto triggering" as well and the control bit for this is ADATE - bit 5 in ADCSRA

See the second paragraph in section 22.3 - Starting a Conversion

Also read about ADTS2/1/0 and note what 000 selects.

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

hi

Last Edited: Sun. Mar 2, 2008 - 03:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

gr8 tutorial

vicky3413 wrote:
mega 16 adc chanels are multiplexed.it means at a given time there is only one conversion.
what in case we are using several sensors to guide a robot motion?

Whichever sensor u want to read u have to select that channel through the ADMUX register.

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

I am little bit confuse :? about Interrupt Driven Example.

In mega32 data sheet it says
"Switching to Free Running
mode (ADTS[2:0]=0) will not cause a trigger event, even if the ADC Interrupt Flag is set(Page 218)"

So is it necessary to use other trigger source if we are using interrupt?

I mean logically in this mode it will be continuously converting Analog to Digital so it will continuously call the interrupt routing on the completion.
Still i m not sure.:(
Please help me here.

Thank You

Last Edited: Thu. Feb 28, 2008 - 03:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

vizard356 wrote:
gr8 tutorial

Whichever sensor u want to read u have to select that channel through the ADMUX register.

So, if you need say 3 ADC's and want to use interupt driven code, can you change the ADMUX inside the ISR and the next trigger will be the next channel, or will the next sampling already have started even though you haven't read the value yet?

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

mikaelo wrote:

So, if you need say 3 ADC's and want to use interupt driven code, can you change the ADMUX inside the ISR

Yes, u can change ADMUX inside the ISR.

Quote:

and the next trigger will be the next channel, or will the next sampling already have started even though you haven't read the value yet?

you have to careful because after changing ADMUX next conversation might be based of the previous value of ADMUX.
So you should put small delay after changing ADMUX and before reading the value.

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

Is it necessary that we use a 10 k potentiometer?What is the potentiometer with the smallest possible value that one can use for the ADC?

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

bootstrap wrote:
Is it necessary that we use a 10 k potentiometer?What is the potentiometer with the smallest possible value that one can use for the ADC?

Well, potentiometer is there because you can change voltage by changing resistance so that you can test sample program.
Actually there is no specific value of potentiometer should be used.
But 10K works great. At 0 ohm u can get min voltage and at 10k u can get max voltage.

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

Quote:

Actually there is no specific value of potentiometer should be used.

Maybe not, but a too low value on the pot will work bad. Heres why:

A potentiometer is essentially a resistor with the two ends connected to the supply voltage and ground respectively, and with a tap that you can move from one end of it to the other. Thus it forms a voltage divider and with the tap at one end you the voltage at it will be the supply voltage and at the other end it will be zero volts. Thats all fine, and a broad range of pot values will make this scheme work. But (and thats a BIG BUT) the pot is also a resistor between the supply rail and ground. So now, if you use say a 47 Ohm pot you will more or less short the supply rail to ground. Ohms law will tell you how much current will flow through the pot: V = R * I, and moved around a bit you have I = V / R, and assuming a 5 Volt supply you get 5 / 47 amps which is approximately 100 milliamps. Compare that to using a 10KOhm pot through which will flow only 5/10000 = 0.5 milliamps.

Quote:

What is the potentiometer with the smallest possible value that one can use for the ADC?

What is the maximum current that the pot can take? (look it up in the specs)
How much current can your power supply generate?
How much heat do you need? :wink:

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 have a 1k pot.The I/O pin of the atmega 8 can take in 40 milliamp.Power supply can give a max of 500 ma.And the current through the pot should be 5/1000 = 5 mA.This 5mA doesn't seem to damage anything

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

bootstrap wrote:
I have a 1k pot.The I/O pin of the atmega 8 can take in 40 milliamp.Power supply can give a max of 500 ma.And the current through the pot should be 5/1000 = 5 mA.This 5mA doesn't seem to damage anything

5mA doesn't do any damage.But it is current when resistance across pot is 1k, what if you turn the pot and make resistance 0 ohm. Its short circuit.
So you have to be careful and connect some fix resistance as shown in sample figure.

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

vizard356 wrote:

5mA doesn't do any damage.But it is current when resistance across pot is 1k, what if you turn the pot and make resistance 0 ohm. Its short circuit.
So you have to be careful and connect some fix resistance as shown in sample figure.

So if independent of the value of the pot if I have the 330 ohm resistors connected to the Vcc and Gnd legs of the pot the micro wont be damaged?
So if the we have the 330 ohm does it matter what value of POT we use (as in the sample figure?)

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

Quote:

Its short circuit.

Only if the impedance of the AVR input pin is 0 Ohms. I took a quick look in th ATmega88 data sheet to find the impedance of a pin in input mode, but couldnt find it. The only thing I found was this(p 299):

Input Leakage Current I/O Pin: 1 microampere (for pin both high and low, @ Vcc 5.5 volts). If I interpret this correctly there is no problem with a short through the AVR. (It actually suggests an input impedance of 5.5 MOhms. Take this with a grain of salt though, maybe I'm misreading the sheet.)

Anyhow, the problem with using a pot with a too low value is the shorting from supply rail to ground through the pot.

Now I'm curious: What made you pose the question, bootstrap? Why the need to use a low ohm pot? (Weekend and no supply of 10K resistors, maybe?)

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

JohanEkdahl wrote:
Quote:
Anyhow, the problem with using a pot with a too low value is the shorting from supply rail to ground through the pot.

If the OP is concerned about input impedance of the ADC channel, a buffer amp will provide high input, and quite low output impedance.

  VCC
  ---
   |
   |
   |
   /
   \  10K Ohm          |\
   /                   | \
   \<------------------|+ \
   /                   |   \
   \           LF355   |    +-------+-------> ADC Input
   /                   |   /        |
   |           --------|- /         |
   |           |       | /          |
   |           |       |/           |
  ---          |                    |
  GND          |                    |
               +--------------------+

I have used the above circuit in several designs. But there, the usage was for isolation and not necessarily impedance control.

But a 10K Ohm pot should not be of any concern to the ADC. I've used 10K, ten turn wire-wound pots for years with no ill effects.

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

Carl, the eye-opener! My brain must have gone bzzzzztt! yesterday.

Of course we are discussing the ADC input, and on page 306 of the ATmega88 data sheet it is in black and white:

Analog input resistance: Typically 100 MOhm.

Quote:

But a 10K Ohm pot should not be of any concern to the ADC.

No, but OP is asking "how low can we go".

Again, as I see it this has nothing to do with the value of the pot (as any pot will be able to be set to act as a 0 Ohm resistor between the supply rail and the ADC pin).

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

Quote:

Again, as I see it this has nothing to do with the value of the pot (as any pot will be able to be set to act as a 0 Ohm resistor between the supply rail and the ADC pin).

Yep, exactly. That's why some fix resistance must be used. Otherwise power supply might get damage if kept for long time :( due to heavy current (if fuse is not used).

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

Quote:

That's why some fix resistance must be used.

And if I read the data sheet correctly it is - internal in the AVR. And the value of it is 1 MOhm (nominally)! So you do not need to supply any fixed resistance external to the AVR.

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

As a newbie (we often struggle with nuances), I feel compelled to point out that while the NON-interrupt example works as it should, if one is taking baby steps at getting the ADC's to work, it should be observed that the first conversion will *not* be completed when

if(ADCH < 128)

is executed. Thus, if one simply captures ADCH at that point (as a baby stepping newbie might),say, with

Temp = ADCH;

it will not valid. To do so, the ADCSR bit, ADSC, must be polled for a transition to 0 to indicate that the conversion is complete.

John

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

I have a problem. The tutorial was great so I decide to make a thermometer with LM35 on attiny26.

When I measure voltage on PA0, there is 0,27V (so is't ok - 27 celsius). BUT!!! when I set for egzample PB4 (ADC7) (PORTB=(1<<4)), my voltmeter shows 0,67V !!! I thought, that if PA0 is an input, so i can make everything with other pins, but it seems I'm wrong! What is going on?

DDRB = 0xff; // portb as output
      
// ADC setup
   setb(ADCSR,ADPS0); setb(ADCSR,ADPS1);   // prescaler 8 for 1Mhz
   clrb(ADMUX, REFS0); clrb(ADMUX, REFS1); // voltage reference - AVCC
   setb(ADCSR, ADFR); // free running mode
   
   setb(ADCSR, ADEN); // adc enable
   setb(ADCSR, ADSC); // start conversion
   //setb(ADCSR, ADIE); // interrupt for ADC on

   sei();
   
   
   while(1)
   {      
      setb(PORTB, 4); // <--- problem!!!
   } 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you enabling the pull-up on this port, when you don't want to?

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

How do you select the ADC channel? in the atmega8535 datasheet they write that this is done by setting some bits in ADMUX, but i can't figure out which. Thanks

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

I can certainly see how that would be difficult to find (seriously, I am not being a smart ass :-) ). The Acrobat "Bookmark" takes you to page 213 in the datasheet for the "Changing Channel or Reference Selection" section. You have to skip all the way to page 220 to see Table 85. All is revealed there :-).

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

So, for changing chanels i need to add some instructions like these:
ADMUX |= (1 << REFS0);
ADMUX |= (1 <<ADLAR)|(0<<MUX4)|(0<<MUX3)|(0<<MUX2)|
(0<<MUX1)|(0<<MUX0)

?

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

For changing to channel n use:

ADMUX &= 0xF8; // clear bottom 3 bits
ADMUX |= n; // then set bottom 3 bits to channel n

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

@penquissciguy
Fantastic TuT loved the style and pacing, easy to follow even for a newb like me. SOOO much easier to understand when there is a working example to guide you and only one variable is changed at a time with each progression. Once again thanks for your effort!!! :mrgreen: (wish there was an emoticon with a hat tip because that would be more appropriate).

Lachlan

What we need to learn,
we learn by doing.

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

lmc222 wrote:
@penquissciguy
Fantastic TuT loved the style and pacing, easy to follow even for a newb like me. SOOO much easier to understand when there is a working example to guide you and only one variable is changed at a time with each progression. Once again thanks for your effort!!! :mrgreen: (wish there was an emoticon with a hat tip because that would be more appropriate).

Thanks! I appreciate the compliment. I basically copied abcminiuser's pattern for a tutorial. I like the whole step-by-step flow myself.

Ken

Last Edited: Tue. Mar 25, 2008 - 08:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

Excellent tutorial, thanks for posting it!

I am trying to run the same examples with a attiny45. It works but not quite. Looked at the data sheet and converted the registers:

#include 
#include 

int main(void) {
    // Set Port B pins for 3 and 4 as outputs
    DDRB = ( 1 << DDB3 ) | ( 1 << DDB4 );
    
    //set the reference voltage for the ATTINY45 ADC to be VCC
    ADMUX &= ~((1 << REFS0) | (1 << REFS1));
    
    //set pin #1 as ADC0
    ADMUX &= ~( ( 1 << MUX0 ) | ( 1 << MUX1 ) | ( 1 << MUX2 ) | ( 1 << MUX3 ) );
    
    //left allign the adc value 
    ADMUX |= (1 << ADLAR);
    
    //set the division factor to 128 (see the datasheet)
    ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
    
    //auto triger enable
    ADCSRA |= (1 << ADATE);

    //enable the ADC
    ADCSRA |= (1 << ADEN);
    
    //start the adc measurments
    ADCSRA |= (1 << ADSC);
    
    for ( ; 1==1 ; ) {
        
        if(ADCH < 128) {
            PORTB = 8;
        } else {
            PORTB = 16;
        }
        
        //optional
        PORTB = 0;
        
    }
    
    return 1;
}

What this does is untill around 2.1V both LEDs are off, at 2.1V LED1 turns on, at around 2.5V LED1 is off and LED2 is on and stays this way to the end (4.82V).

What beats me is that with the if/else in the endless loop above both LEDs can be dark. My guess is that there is some sort of interrupt/triggering happening but I can't quite get it. Without the

ADCSRA |= (1 << ADATE);

line it was behaving even more strangely (the behavior was dependent on the speed with which I move the potentiometer - if I move fast LED1 turns on, if I move slow LED2 turns on, both at around 2.5V).

Hope someone can explain what is happening and/or how to fix it. Appreciate your help...

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

Quote:

My guess is that there is some sort of interrupt/triggering happening but I can't quite get it.

Well microcontoller will be doing Analog to Digital conversion behind the scene. and will update converted digital data in ADCH and ADCL.

Quote:

Without the
ADCSRA |= (1 << ADATE);

line it was behaving even more strangely (the behavior was dependent on the speed with which I move the potentiometer - if I move fast LED1 turns on, if I move slow LED2 turns on, both at around 2.5V).

If u read data sheet u will come to know that ADATE bit in ADCSRA is for the auto triggering. so controller will do ADC conversation repeatedly based on the triggering source.

So if u dont set the ADATE bit controller will do Analog to Digital conversion only once and your led will be on based on voltage value of the pot. at that time.

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

I recently read through this tutorial and found a part that might lead to confusion.

In the tutorial it insists that two 330 ohm resistors must be used with the pot to avoid damage. I believe that this is incorrect (in most cases). the potentiometer will always be a fixed resistance between Vcc and Ground. therefore you do not need to worry about a low resistance path between Vcc and ground, for example in the tutorial it gives a 10k pot, if you only had the pot, you would always have 10k between Vcc and Ground regardless. Now one might be concerned about shorting the ADC input to Vcc or ground( this is what the Tutorial cites as the reason for the 330 ohm resistors), this is a possible condition. But, it is not a problem. Any standard ADC, like a voltmeter, will have a high input impedance, if this was not the case the ADC itself would sink appreciable current and change the voltage at the node you are measuring. In the ideal case the ADC would have infinite input impedance and would have no loading effect on the node of interest. It therefore is OK to directly connect the ADC to Vcc or Ground. The one problem that could arise is if the nominal value of the pot is low enough to allow too much current outside the specs of the power supply or the pot itself.

Josh

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

In the section "Voltage Reference Selection" of my atmega32's datasheet it is said that if AVCC is used as the voltage reference, an external capacitor should connected at AREF pin. How important is this? And what should the value of this capacitor be?

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

Can someone tell me what the minimum samping rate is for the built-in ADC in ATMega32?

Plus, My mega32 doesn't have a ADFR bit, how do I initiate a free running conversion? Right now, Only single conversions are working for me.

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

Quote:

My mega32 doesn't have a ADFR bit, how do I initiate a free running conversion?

Read the section Starting a conversion in the data sheet, especially the pieces on "Auto triggering". And you could always try to actually use the search function in Acrobat Reader to search for "free running"...

Quote:

Can someone tell me what the minimum samping rate is for the built-in ADC in ATMega32?

Mimimum? :shock: In my world "rate" is something per units of time (ie. a symonym to "frequency"), so the mimimum samples per time you can get is "none at all per eternity" (approximately :wink:). I suspect that you are asking about maximum sampling rate. This would depend on the clock rate of the ADC.

Questions seems kind of odd, and clues to answers are easily locatable. Is this part of a school assigment perhaps?

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 mean can I sample the data, at say anything from 1kHz to whatever the maximum samplng rate is?

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

Well, again you ought to turn to the data sheet
Page 202:

Quote:
By default, the successive approximation circuitry requires an input clock frequency
between 50 kHz and 200 kHz to get maximum resolution. If a lower resolution than 10
bits is needed, the input clock frequency to the ADC can be higher than 200 kHz to get a
higher sample rate.

From page 205 we can get that a conversion takes 13 cycles. Now we just need to apply some math to finish with a sampling frequency of (approximately) 3.85 KHz to 15.3 KHz. Gor lower sampling rates simply pause between samples. For higher rates you will have to sacrifice ADC accuracy.

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

hai all i'm doing a project which will control the temperature of Cooler. I'm using two adc channels

I have tried it by changing the channel and giving start conversion. i'm not using ADC interrupt.

now i want to use ADC interrupt two get datas of both channels. this is because for maintaining time interval.

Please help me by giving some guidelines how to proceed.

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

Does anyone know why this code does not work? I update the free running mode's code and I'm using an ATMega48.

int LEDS(int z)
{
	if(ADCH < 1)
	{
		(LED 1 on);
	}
	if(ADCH < 63)
	{
		(LED 2 on);
	}
	if(ADCH < 124)
	{
		(LED 3 on);
	}
	if(ADCH < 248)
	{
		(LED 4 on);
	}
}


int main (void)
{
	ADCSRA |= (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0);
		
	ADMUX |= (1 << REFS0); 
	ADMUX |= (1 << ADLAR);
		
	
		
	ADCSRB |= (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0);
	ADCSRA |= (1 << ADEN); 
	ADCSRA |= (1 << ADSC); 
		
	while(1) 
	{ 
		LEDS(0);
	} 
} 

Life Is Like A Bucket Of Chicken.

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

OMGHWGA...

Quote:

Does anyone know why this code does not work?

No-one wants to read your code, think hard, maybe even dig out a mega48 and try to run the code, using some input they guess and hope is similar to yours.

Take a break, sit down and have a cup of coffe, and think about what someone who should help you needs to know. I'm hoping that you at least come up with theese:

1) A description of the circuit.
2) A description of what kind of signal you are sending in to the ADC.
3) A description of what you see that makes you decide that it is not working.
4) A description of what you have done up to now in form of thinking and tests.

One thing that might, or might not, have to do with your problem is that you read the ADC four times to determine which LEDs to turn on. If you want the four leds to be controlled by the same ADC reading you need to read the ADC once to a temporary variable and then use that for your four tests.

Or could it be that when the ADC value is low you see all LEDs on when you just want LED 1 on? If so then you need to arrange your if's in a cascading way (if- else if - else if ... ).

If I sit another half-hour thinking and guessing I might come up with ten more tips. One of those might be the one you needed, but then you have wasted my time coming up with the other nine because you didn't take your time to think about your audience. Go make coffe...

EDIT: Another tip on the side is to start a new thread for a new question (instead of bloating a thread that is about Deans tutorial). For a new question use the "New Topic" button rather than the "New Reply". If you think out a subject for your new thread that is both accurate and tempting more people will probably be interested.

EDIT: And I need to go to bed, as I am obviously too tired. This tutorial is written by Ken, none other. Sorry Ken, but as Dean more or less owns this corner of 'freaks it was an easy mistake to make. Assumption is the mother of many Foul-ups...

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

Quote:

(instead of bloating a thread that is about Deans tutorial)

Credit where credit is due, this actually isn't one of mine. A fellow member went to the trouble of writing it, and only copied my writing style to remain consistent. Did a damn good job of it too - confused the hell out of me for a few minutes when I saw it, as I couldn't remember writing it...

- Dean :twisted:

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

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

The input circuit is the same setup as the tutorial. And for the output, I turn the variable resistor, and one LED turns on, then another turns on, then another turns on, then another turns on. That is what I'm trying to do.

Life Is Like A Bucket Of Chicken.

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

Taco_Bell wrote:
The input circuit is the same setup as the tutorial. And for the output, I turn the variable resistor, and one LED turns on, then another turns on, then another turns on, then another turns on. That is what I'm trying to do.

So, what are you using as the trip points to turn on the LEDs at different ADC values? Are you using specific bits being turned on, or are you using byte or 10 bit integer values?

That is, for bit specific trip points, dose say, B1 turns one one LED, B3 turns on another LED, B5 another, B7 turns on yet another LED, etc.?

Or, are you using value based comparisons such as, the integer value 100 (0x64) turns on an LED, 155 (0x9B) turns on a different LED, and 200 (0xC8) yet another LED?

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

63, 126, 189, 252 are my trigger points and I'm running it 8 bit style.

Life Is Like A Bucket Of Chicken.

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

Hi, I doubt please. It is my first time dealing with ADC so... be pacient...

Question one: I have the ATMega128 on a stk300 board and that board comes with a blue pot. Does this pot is for testing ADC? I cant understand its aim from the STK300 manual :-(

Question 2: I have a 10k pot. Please confirm me this:
I plug the wiper in the port F pin 0 (adc0). The vcc pin of the pot is plugged in the avcc pin or in the vcc pin of the port F? and the same about the ground. Do I have to make grounds in common (port f gnd and Agnd)?
Sorry I am not a expert in english language and I didnt undertood this on the tutorial...

Thank you very much
Alex

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

Quote:

The vcc pin of the pot is plugged in the avcc pin or in the vcc pin of the port F?

I understand that english is not your first language, but there is a real problem understanding your sentence above.

Anyway, here is a description of how to connect a potentiometer so you can read it's position with the AR ADC:

A potentiometer has three connections. One on each end of the resitive track, and one on the "wiper" that can move along this resistive track. You connect one of the endpoints to VCC and the other endpoint to GND. Thw wiper goes to the AVR ADC pin.

Connecting a potentiometer this way effectively makes it into a voltage divider. The voltage on the slider will be proportional to its position between the two endpoints.

http://en.wikipedia.org/wiki/Pot...
http://en.wikipedia.org/wiki/Vol...

If the pot on the STK300 you are talking about is the one close to the four headers forming a square, then this is used to adjust the analogue reference voltage (I believe it is marked AREF, but the piccture of the STK300 I found is not of good quality).

From a 1999 version of the STK300 User Manual:

Quote:
To use the [...] (on-board) Voltage Reference, the pot marked AREF is used to set the voltage
level.

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

"Does the vcc pin of the pot is plugged in the avcc pin od of borad or it is to be plugged into the vcc pin of the port F (the ADC port)?"

I already simulated it in a test board with 2 330 resitors and a led on the wiper and it works and I know the pins of the pot. My doubt is:

How do I feed the pot? 1. Should I use the Vcc and GNd of the ADC port or 2. pot must be feed using the AVCC and AGnd?
Case 2: do I have to connect both gnds (port f gnd and Agnd) in order to make gorund common?

And what about a photoresistor that just has 2 ends? How it is connected to the portF?

Thanks, please be patient... :-)

Alex

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

<--- Im a newbie take it easy on me!

What about when you want to get a reading from your vcc ? for example I would like the avr to detect when its own voltage source is getting low. Great tutorial though!!

Support my site for funding my AVR projects!! heh

Credit Card Information

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

Hi. Been reading the tutorials for a couple months learning WinAVR. Just signed up so this is my first post here.

Clawson pointed out to me that both the ADCH & ADCL registers must be read for ATTiny261's ADC to be refreshed as he illustrated in the post below mine here. So as frustrating it was to me to get all this to work and find code that can migrate from MCU to MCU, if it helps, here is working ISR driven ADC code for this MCU. No sense in letting this post go to waste:

#include "avr\io.h"
#include "avr\interrupt.h"

int main(void)
{

	// PORTB set for output
	DDRB = 0b11111111;
	
	// PORTA set high nibble as output
	DDRA |= 0b11110000;

	// No need to set A/D channel; reading ADC0 by default


	// Set prescaler to clk/8 to get 125kHz ADC clk
	// (Running 8MHZ w/ divide by 8 bit enabled = 1 MHZ)
	// 1MHZ / div by 8 ADC prescaler = 125kHz ADC clk
	ADCSRA |= (1 << ADPS1) | (1 << ADPS0);
	
	// Set ADC Vref to 2.56V
	// (with ext decoupling cap)
	ADMUX |= (1 << REFS1) | (1 << REFS0);
	ADCSRB |= (1 << REFS2);
	
	// Set ADC to free run mode
	ADCSRB &= ~(1 << ADTS2) | ~(1 << ADTS1) | ~(1 << ADTS0);
	
	// Enables ADC for use
	ADCSRA |= (1 << ADEN);
	
	// Enable ADC Interrupt
	ADCSRA |= (1 << ADIE);

	// Enable Global Interrupts
	sei();
	
	// Starts ADC conversion
	ADCSRA |= (1 << ADSC);

	// ADC Auto Trigger Enable
	ADCSRA |= (1 << ADATE);

	// Loop forever. ISR will interrupt when called.
	while (1)
	{
	}
}


ISR(ADC_vect) 
{ 
	// output ADC's value to PORTB,
	PORTB = ADCL;
// don't care about first 2 MSBs but they still must be loaded into some variable (ie read from the ADCH register) for the ADC to be updated.
temp = ADCH;
} 
Last Edited: Mon. Jun 2, 2008 - 07:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can't help wondering if this from the 261 datasheet is relevant here:

Quote:
When ADCL is read, the ADC Data Register is not updated until ADCH is read. Consequently, if
the result is left adjusted and no more than 8-bit precision is required, it is sufficient to read
ADCH. Otherwise, ADCL must be read first, then ADCH.

Maybe try dummy reading ADCH and see what happens. Or simply:

PORTB = ADCW & 0xFF

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

@ +rokof+ below:

Single Conversion mode can offer a quieter signal aquisition conversion due to the fact that the programmer can disable unused MCU services prior to a conversion cycle.

Free run mode may be simpler to program for those learning the MCU. I can understand the possibility that after one masters the ADC module, single conversion mode may be one of choice.

Last Edited: Wed. Jul 2, 2008 - 03:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

how do you set up ADC for single mode?

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

Quote:
how do you set up ADC for single mode?

Follow the first post but don't set ADFR (free run mode). Now a conversion is triggered each time you set the ADSC bit and is complete when you see that ADSC bit trasition from 1 to 0. (don't be tempted to use ADIF as the signal for completion or, if you do, make sure to clear the bit each time - but using ADSC as the flag is much easier as it's self-clearing)

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

what are the advantages of free running ADC over single mode?
I want to check the temperature of a tank in intervals of say 2 sec.What would be best? Set the ADC in free run mode and check ADCH every 2 seconds or set it in single mode and every 2 sec make a conversion then check ADCH?

Is free running more cpu consuming or the other way around? Maybe I'll implement a floating point controller algorithm in the future so i want to know

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

Hello,

I have some questions about voltage divider. How can pot output 0.15 to 4.85 volts? On one side pot will output

((330+10)/(330+330+10))*5V
340*5/670 = 1700/670 = 2.537 V

On the other side:

((330)/(330+10+330))*5V
330*5/670 = 1650/670 = 2.462 V

http://en.wikipedia.org/wiki/Vol...

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

Wonderful tutorial, very helpful. I learned enough to build a simple voltage / battery monitor for another circuit!

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

Hello, Thanks for the great tutorial. I'm completely new to all this. A month ago I had no idea what an AVR even was, and now I'm barely beginning to understand. Ports and registers and bits are still all kinda like mysterious black boxes to me, but hopefully I'll figure it out.

Anyway, my question, and I know it's probably really stupid, is what if you want to use the ADC to control the frequency of a flashing LED rather than just whether the LED is on or off based on a threshhold voltage? Can you write a line of code like

LEDfrequency = (ADCH/10);

and then use LEDfrequency as a variable in a flashing subroutine?

If there's a tutorial already written on this, I'm sorry. You could just point me in that direction if you don't want to re-explain it.

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

Quote:
Can you write a line of code like

LEDfrequency = (ADCH/10);

and then use LEDfrequency as a variable in a flashing subroutine?


Sure, why not? You can use the information you got from the ADC in any way that you want.

Regards,
Steve A.

The Board helps those that help themselves.

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

Hi all,

I am a newbie in AVR programming. Currently I am building a project with ATMEGA8 ADC. In this project, I am using 2 ADC inputs (ADC0 and ADC1), XTAL 3.6864 MHz (prescaller : 101). The problem is:

When I activate only 1 channel (ADC0), it works nicely. However, when I tried to switch to the other channel (ADC1), my program just read the same value like the first one. I change the channel by setting and clearing MUX0 bit to select ADC0 and ADC1.

Could anyone help me with this? Here is the simple program based on program list Dean's Tutorial (1st page), with modification to read 2 ADC Channels:

#include
#include
#include "lcd.h"

int adc0 = 0;
int adc1 = 0;
int adcport = 0;

int main (void)
{
int num;
char buffer[7];

lcd_init(LCD_DISP_ON);
lcd_command(LCD_DISP_ON);
lcd_clrscr();

ADCSRA |= (1 << ADPS2) | (1 << ADPS0);
ADMUX |= (1 << REFS0);
ADMUX |= (1 << ADLAR);

ADMUX |= (1 << MUX0);

ADCSRA |= (1 << ADFR);
ADCSRA |= (1 << ADEN);
ADCSRA |= (1 << ADIE);
sei();
ADCSRA |= (1 << ADSC);

for(;;)
{
lcd_gotoxy(0,0); // Display ADC0
lcd_puts("ADC0: ");
num = adc0;
itoa(num , buffer, 10);
lcd_puts(buffer);
lcd_puts(" ");

lcd_gotoxy(0,1); // Display ADC1
lcd_puts("ADC1: ");
num = adc1;
itoa(num , buffer, 10);
lcd_puts(buffer);
lcd_puts(" ");
}
}

ISR(ADC_vect)
{
if (adcport==0)
{
if (ADCH==0)
adc0 = ADCL;
else adc0 = ADCH * 256;
adcport = 1;
ADMUX |= (1<<MUX0); // Switch to ADC1
}
if (adcport==1)
{
if (ADCH==0)
adc1 = ADCL;
else adc1 = ADCH * 256;
adcport = 0;
ADMUX &= ~(1<<MUX0); // Switch to ADC0
}
}

Thanks a lot !!!

Best,
wibi

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

FAQ#1 - trying making your main/ISR shared variables volatile.

Also for reasons of atomic access it is unwise to make them 16 bit (two register) wide 'int' if 'char' would be OK

If they must be 16 bit then protect access to them in main with "sregcopy=SREG; cli(); access the variable; SREG=sregcopy"

Also your code doesn't look right:

if (ADCH==0) 
adc0 = ADCL; 
else adc0 = ADCH * 256;

Appears to violate the datasheet requirement:

Quote:
When ADCL is read, the ADC Data Register is not updated until ADCH is read. Consequently, if the result is left adjusted and no more than 8-bit precision is required, it is sufficient to read ADCH. Otherwise, ADCL must be read first, then ADCH.

Also this code only ever appears to set ADSC once and it does not appear to be configuring for free-running mode.

Cliff

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

What are you intending this

if (ADCH==0)
   adc0 = ADCL;
else 
   adc0 = ADCH * 256; 

to do? No, no nitpicking, an honest question.

There is a strict procedure to follow if you read both ADCH and ADCL. Those registers are "double buffered" wich means that in order to always being able to read a value pair ot of them that belongs to the same register then you need to read them in this specific order: First ADCL and then ADCH. The mechanism involved works like this: When you read ADCL then the low byte of the current conversion value is read out of ADCL immediately, and the high byte of the same conversion value is moved to a temporary register. When you read ADCH that temporary registers value is returned. And as long as you dont read ADCH no new conversion values will be moved into the registers. This also implies that you should not read the same register twice. If you read ADCL two times, then the same value will be returned for the two reads. If you read ADCH twice (as you do with first the test if ADCH==0 and then adcn = ADCH * 256 you risk getting values from two different concersions if a conversion finishes between the test and the assignment. (Data sheet page 195.)

If you for some reason just want to combine ADCH and ADCL to a (a 16 bit) integer value then this simple scheme will work in avr-gcc (WinAVR):

adcn = ADC;   // Read the full 16 vit ADC value

Tip: Learn how to use the code tags when posting as this will preserve the indentation, and prevent semicolon-right parenthesis from being displayed as a wink-smiley.

EDIT: Ooops! Didn't notice the (new) fifth page of the thread with Cliffs response.

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

hey everyone, i have a serious problem or at least that's what i think it is..
i have just bought a new laptop and it does not have an RS232 female with it, it only has the VGA female... how can i connect the butterfly to bray's terminal?? please help:( thanks a lot

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

You need a USB-to-RS232 converter. Prepare to spend $20 to £30.

There are lots of them around. Here is one example: https://www.crystalfontz.com/car...

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

What does this thread have to do with either RS-232 or the Butterfly?

Regards,
Steve A.

The Board helps those that help themselves.

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

Plus, it is cross posted. I informed the poster in another thread that his post was considered uncool.

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

Very well done. It cleared up a few issues I was having. If your not running free run mode or using interrupts this code is handy.

while (ADIF ==0);
This flag is set when the conversion is ready.
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
while (ADIF ==0);

that statement says something like:

while (4 ==0);

which will never be true. I bet you meant something like:

while ((ADCSRA & (1<<ADIF)) ==0);

(but it's better to block on ADSC being one than ADIF being zero anyway)

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

When setting the prescaler in ADCSRA, we usually hard code the prescaler values like this:

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

Unfortunately, when we change our chip's clock speed, we have to remember to change the ADC prescaler as well. If we set the prescaler bits using an algorithm that takes into account the CPU clock speed, we can avoid this problem:

uint8_t prescale = 0;
for( uint8_t div = (F_CPU / 200000L) - 1;
        div > 0;
        div >>= 1, prescale++);
ADCSRA |= prescale;

In the compiled program, this will not result in any more code than the previous example. Since the value in prescale is a constant at compile time and the prescale variable is not used anywhere else, these get optimized out leaving the same code as the first example.

If you look at the AVR datasheets, you'll see that the ADPSx bits are just the Log2 value of the division factor which is all the above calculates. It will pick the smallest division factor that will set ADC clock as close to 200KHz without going over.

Cheers,

Tom

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

Thank you for this splendid tutorial. After only reading the datasheet of my avr i had a whole load of questions all of which were answered by the text above.
Thanks for taking the time to write.

There is one little thing. The datasheet i raed concerned exactly my Atmega8. At one point it says:

"The ADC is enabled by setting the ADC Enable bit, ADEN in ADCSRA. Voltage
reference and input channel selections will not go into effect until ADEN is set."

Does that mean i will have to enable ADC only as a last step of setting the ADMUX and ADCSRA registers?

Meanwhile i can see that for your microcontorler there was no such demand. (in the code you'r enabling ADC only as the last step in the whole ADC registers setup.

Are there already such huge differences between different AVR's?

Kind regards

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

It's always good programming practice to leave the actual enabling of a device until the very last step after all other initialisation. Consider a timer for example. As soon as the CS bits are set it starts running. You'd probaby want to ensure that it had already been set into the right mode and configured to produce the right external pin behaviour BEFORE it starts counting.

As for the ADC nothing really happens (even after ADEN) until you set ADSC so you really just need to ensure that THIS is the last step of initialisation in fact and you could ADEN earlier in the sequence.

Cliff

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

I see. Thanks for answering.

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

I used the code from "Part 1 – A Simple Free-Running ADC Example" - it works great. But how to change it from 8-bit precission into 10-bit precission ?

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

Quote:

But how to change it from 8-bit precission into 10-bit precission ?

The ADC is running with 10-bit precision in the first part, but it is left justified so that you get the eight most significant parts in ADCH. To get all 10 bits you
i) Want the result right justified in ADCH+ADCL, and
ii) want to read the 16-bit value in ADCH+ADCL

Item i) is accomplished by not setting the ADLR bit.

Accomplishing item ii) depends on your compiler. For avr-gcc (WinAVR) you can simply do:

int theValue = ADC;

If your compiler does not offer you this nifty access to 16-bit "L+H-registers" then this should work in any standards-compliant compiler:

int theValue = ADCH<<8 + ADCL;

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 have the same configuration as in the first example, and I've verified that the voltage over the resistors vary between 0.16V and 4.85V.

The problem is that I'm only seeing 0-64 on ADCL and always 0 on ADCH. If I use the left alignment option, I only see 0-16 on ADCH. What happened to the 10-bit range?

I'm using an ATMEGA8, my reference voltage is set to Vcc and I'm sending the values through RS232 to my computer (which works fine).

please help!

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

Hi all,
i have a problem which i cannot overcome alone, so if somebody can help me i'll be thankful.

I'm using Mega128 with 1MHz clock source and debugger JTAGICE,but after conversion ADCL and ADCH are empty(and they shoudnt).
If someone can give some clue what is wrong.
Here is my code:

#include 

#define ADCCon	 (ADCSRA|=0x40)//Start ADC Conversion

void AdcInit(void)
{
	ADMUX |= (1 << REFS0);//AVCC with external capacitor at AREF pin
	ADCSRA|=0x80;//Enable ADC
	ADCSRA |=(1 << ADPS1) | (1 << ADPS0);//Select Division Factor =8
}
int main (void)
{	int buf;
	
	AdcInit(); 

	for(;;)
	{
		ADCCon;
		while(ADCSRA &(1<<ADSC)) {};
		buf = (ADCH<<8) + ADCL; 
	}

}

10x.
O ,and i add to watch variable "buf", but the value is "Location not valid".
It stays that way even when i set it to 0 (int buf=0; )

Beware the barrenness of a busy life.
Socrates .

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

cahofmeyr wrote:
I have the same configuration as in the first example, and I've verified that the voltage over the resistors vary between 0.16V and 4.85V.

The problem is that I'm only seeing 0-64 on ADCL and always 0 on ADCH. If I use the left alignment option, I only see 0-16 on ADCH. What happened to the 10-bit range?

I'm using an ATMEGA8, my reference voltage is set to Vcc and I'm sending the values through RS232 to my computer (which works fine).

please help!

Can someone please help me?

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

Thank you so much for this tutorial. I'm a newbie and this tutorial was GREAT!

It's so nice that people like you and abcminiuser doing these tutorials!

So thanks again! :)

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

thanks for the tutorial! I got the ADC up and running in no time!!

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

as for 10-bit conversions, the code in this thread to add them is wrong (for my GCC).

value = ADCL + (ADCH<<8);

I fixed it with the above code, by swapping them : which the pre-processor will probably correctly read the L then the high byte (at least in my tiny brain it makes sense). I now get 10 bits, yay!

I read the datasheet at least 5 times, but the tutorial made it all come together. Thanks.

Conrad Braam - www.softcircuitry.blogspot.com - www.plcsimulator.org
Always start off poorly, that way when you finally figure it out, you can get a few surprise hits in.

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

Any reasonably new avr-gcc/avr-libc will happily accept the simple

value = ADC;

and generate the correct code sequence for reading ADCH and ADCL and combine them into one 16-bit value.

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

In other C compilers that don't provide a 16 bit register access like avr-libc's ADC/ADCW I'm guessing that:

unsigned char temp;
temp = ADCL;
value = (ADCH<<8) + temp;

will absolutely guarantee the access order and 'temp' will never really exist as a stack/RAM variable as the optimiser will just make temporary use of an AVR register.

Cliff

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

Total Newbie here,

The if else-loop works as expected and the LED output on my STK300, when I turn the pot high or low, however I see no change/activity/values on the ADCH byte monitor (debug), although it must be reading the value into it otherwise the if-else would not be functioning......i'm overlooking something simple i bet?

In a nusthell the ADCH value is there, but no ADCH bits are being shown (all blank/white)...

STK300
Atmega128
Studio4
JTAG AVRISP

Thanks for the great tutorial

  • 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!

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

Actually, this code

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

Did not do what I wanted... instead I had to use:

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

Now it works like it's supposed to, and not by luck! Thanks again for bringing it my attention.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ADCSRB &= ~(1<<ADTS2) | ~(1<<ADTS1) | ~(1<<ADTS0); 

This can't possibly do what you want. This translates into:

ADCSRB &= 0b11111011 | 0b11111101 | 0b11111110;

which gives you:

ADCSRB &= 0b11111111;

which means that ADCSRB remains unchanged.

Quote:

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

That line does nothing.


Actually, it does do something: it sets the entire register to 0.
Quote:

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

Did not do what I wanted...


So what exactly do you want the code to do? If you want to clear the ADTSx bits and only those bits, then that is exactly the code that you need.

Regards,
Steve A.

The Board helps those that help themselves.

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

Steve,

I want to clear just those three bits. However, the code which did something actually caused my code to quit working. My code which did nothing worked. The reason seems to be that I was attempting to set the free running mode before triggering of the first conversion. Moving the code that you and clawson suggested as being correct to after the trigggering of the first conversion made it start working.

Thanks for all, very educational for me!

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

TeonHarasymiv wrote:
Thanks for the tutorial! Much appreciated!

hi! for firs excuse me for my bad english and thank you for very good tutorial!

i have a problem, i have in my system an analog in very bad signal because i work with a plasma cutter system and i have more disturb problem, so..

what do i do for filter this analog in by software too?? i set the prescaler at 1024 but this is insufficient...

thank you for your time!

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

Quote:
what do i do for filter this analog in by software too?? i set the prescaler at 1024 but this is insufficient...

This sounds more like a hardware problem. I don't think that there is much you can do in software except take multiple readings and average them.

Regards,
Steve A.

The Board helps those that help themselves.

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

Koshchi wrote:
Quote:
what do i do for filter this analog in by software too?? i set the prescaler at 1024 but this is insufficient...

This sounds more like a hardware problem. I don't think that there is much you can do in software except take multiple readings and average them.

hi, thanks for answer.. i have an analog signal in from a plasma cutter system, this is the problem for the noise.. i resolve this problem with this code

code:

ISR(ADC_vect)
{

adc_data = ADCW;

ANALOGIN1= adc_data;
ANALOGIN = (ANALOGIN+ANALOGIN1);
ANALOGIN_IND ++;

if (ANALOGIN_IND==50)
{
ANALOGIN_F=(ANALOGIN/ANALOGIN_IND);
ANALOGIN_IND=0;
ANALOGIN=0;
}

//ANALOGIN = adc_data;
ADCSRA = ADCSRA|0x40; //start the next conversion

}

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

Hi, just a question about the prescaler and ADc frequency:
In the datasheet of my atmega644, there is written "If a lower resolution than 10 bits is needed, the
input clock frequency to the ADC can be higher than 200 kHz to get a higher sample rate".
But there is nowwhere written how high it can go. Where is the maximum and what happens if I go higher than the maximum clock rate for ADC?

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

But I faced great difficulty in showing the actual digital value in LCD. That means if I measure 4.2volt by multimeter, then I who can help me to show that value in LCD?
I only could show the binary value ie 806 for 4.2..but failed to convert it into fractional format...

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

Convert the 0..1023 reading of the ADC into the value in centi-volts or millivolts then output it to the LCD placing a decimal point 2 or 3 digits from the right.

Say your Vref is 5.00V then 1023 represents 5.00V so use (ADC * 500) / 1023 to get the value in centi-volts. Say the ADC read 619 then the result would be (619 * 500) / 1023 = 303. So that is a reading of 3.03Volts

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

im trying to do this example on a attiny13.

ive understood everything so far, and ive changed what i need to for it to work on what im using...

but i cant find how to set which pin i want to do adc from, the original writer left that part out, since using ADC0 is default.

i need to use ADC0, unless i can use that pin as an input without disabling the reset fuse.

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

First you pick the channel you want to use as you are designing your schematic. Within the AVR code you then set the bottom 3 bits of the ADMUX register to the channel you have picked and readings will be made from the selected pin.

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

right now this is what my admux looks like.

ADMUX |= (1 << REFS0);

im not sure what bits i have to set :?

im trying to change ADC from ADC0, to ADC1.

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

i think i figured it out.

this is what i got.

ADMUX |= (0 << MUX1) | (1 << MUX0); // select ADC channel 1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That probably wants to be:

ADMUX &= 0xF8; // clear existing bits
ADMUX |= (0 << MUX1) | (1 << MUX0); // select ADC channel 1

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

but wouldnt &= just make anything that was high, go low, and anything that was low, go high?

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

Get a good book on Boolean Logic.

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

lol.

i said that wrong.

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

Also be aware that the (0<<MUX1) in your code does nothing.

Regards,
Steve A.

The Board helps those that help themselves.

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

Koshchi wrote:
Also be aware that the (0<<MUX1) in your code does nothing.

its just there for me :P

i realize that would only do something if it was already high, and i was changing the channel i was on.

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

so...who wants to tell me whats wrong with my code. :oops:

#include 
#include 

int main (void)
{
	DDRB = 0b00010011;

   ADCSRA |= (0 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // set prescaler to 8. 1Mhz/8=125Khz
   ADMUX |= (1 << REFS0); // external analog voltage reference


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


   ADMUX &= 0xF8; // clear existing bits
   ADMUX |= (0 << MUX1) | (1 << MUX0); // select ADC channel 1

   ADCSRA |= (1 << ADEN);  // Enable ADC

   ADCSRA |= (1 << ADIE);  // Enable ADC Interrupt
   sei();   // Enable Global Interrupts

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

   for(;;)  // Loop Forever
   {
   }
}

ISR(ADC_vect)
{
   if(ADCH < 85)
   {
      PORTB = 0b00000001;
   }
      
   else if(ADCH >= 85)
   {
      PORTB = 0b00000010;
   }

   else if(ADCH >= 171)
   {
   	  PORTB = 0b00010000;
   }
} 

i got a lab tomorrow morning, so im going to bed now and dont have time to check my code.

ill be doing so tomorrow, unless someone would be so kind as to tell me what i did wrong... =\

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

Quote:

whats wrong with my code.

But you haven't told us what you thought it should do and what it actually does. My reading is that you set up and make one reading. It's not clear if that's what you intended or not. If you want it to make repeated readings then add a last line to the ISR:

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

Cliff

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

ill add that and try it.

i have a green led(PB0), a yellow led(PB1), and a red(PB4) led, hooked up.

anything under 1.6V lights up green, under 3.2V yellow, under 5V red.

i tried putting "X <=ADCH <= X" but that didnt work.

right now only the yellow led lights up.

it turns on as soon as the avr is powered, and never changes.

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

i believe my problem is here.

if(ADCH < 85)
   {
      PORTB = 0b00000001;
   }
     
   else if(ADCH >= 85)
   {
      PORTB = 0b00000010;
   }

   else if(ADCH >= 171)
   {
        PORTB = 0b00010000;
   } 

i changed it to make repeated adc'.

the yellow is always on, i got it to turn green with a very low voltage, but i cant get it to turn red.

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

how do i properly do?

( 25 < ADCH < 100)

the message im getting is "comparisons like x > y > z do not have there mathematical meaning."

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

Quote:

how do i properly do?

( 25 < ADCH < 100)

((25 < ADCH) && (ADCH < 100))

But now you are actually reading the ADCH register twice, and that could be different conversions, so read the value into a temporary variable and compare that:

unsigned char adcvalue = ADCH;
if ((25 < adcvalue) && (adcvalue < 100)) ...

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

thanks :)
ill try that out in a minute.

im still having a major issue somewhere or im doing something really stupid...

i went backwards and simplified my code to see if it would work then, still isn't working how i thought it would.

ADCH starts at 0, and ends at 255, to represent a voltage between 0-5V.

so.. if i divide up 255... 255/5 -- 51 should be 1V, right?

so i set it to light up my green led only anything larger than 51, but when i flashed it and hooked it all up, the led stays on.

#include 

int main (void)
{
	DDRB = 0b00000001;

   ADCSRA |= (0 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // set prescaler to 8. 1Mhz/8=125Khz
   ADMUX |= (1 << REFS0); // external analog voltage reference


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


   ADMUX &= 0xF8; // clear existing bits
   ADMUX |= (0 << MUX1) | (1 << MUX0); // select ADC channel 1

   ADCSRA |= (1 << ADEN);  // Enable ADC

   for(;;)  // Loop Forever
   {

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


	if(ADCH > 150)
	{
	PORTB = 0b00000001;
	}	

	else
	{
	PORTB = 0b00000000;
	}


   }


}

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

So what have you got connected to Aref? (Vcc I presume?)

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

clawson wrote:
So what have you got connected to Aref? (Vcc I presume?)

the micro is connected to 5V via a usb cable i cut up.(pin 8 )

then for the adc tests im using batterys connected to the ground, then the positives on pin 7, which is what i have adc set to.

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

Quote:

the micro is connected to 5V via a usb cable i cut up.(pin 8 )

You have to connect 5 Volts to both VCC and AVCC. I am too lazy to look up what pin number they have on your AVR model and specific package, but it is a fact that you have to hook up two power supply pins on the AVR if you want to use the ADC pins. For every AVR I have played around with this has been clearly stated in the data sheet. Read it.

Also: If you refer to pins by their number in a specific physical package you must also tell us what package that is. There is no guarantee that eg pin 2 has the same function in a DIL package as in a TQFP package.

You can avoid this nuisance if you refer not to the physical package pin number but to the "logical/functional" pin designations, eg PB4, VCC, GND, AREF etc... Then we can discuss your problems without you having to translate from function to physical pin, and then us translating back from physical to function to see what pin you are talking about. Most of us probably don't keep the physical pin numbers in our heads, but are used to talk about the logical/functional pin names.

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

there is no avcc on the pinout, and search the data sheet finds nothing.

would i be correct in assuming that AIN0 is what im looking for?

"analog comparator positive input"

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

Quote:

there is no avcc on the pinout

You are on a attiny13 and you are correct. There is no AVCC pin, and there is no external reference voltage input. My mistake. Apologies are due.

The ATtiny13 ADC takes it's reference voltage from either VCC or an internally generated 1.1 Volt reference. The selection between these is done through the REFS0 bit in the ADMUX register.

In a previous post you have

   ADMUX |= (1 << REFS0); // external analog voltage reference

The data sheet clearly states that this will select the Internal Voltage Reference (1.1V).

The AIN0 pin has nothing to do with the ADC. It is an input for the Analogue Comparator.

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

so, since the attiny has no avcc and is using the internally generated voltage, does my vcc still have to be withing .3V?

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

No reaction to my last post. I'll rephrase:

I've tried to browse over your posts in this thread and see no statement of how high voltages you are trying to measure. I might have missed it though.

Anyhow, the ADC value is presented as fractions of the reference value. With the current selection of reference voltage you can not measure anything higher than 1.1 Volts. Anything over 1.1 Volts will return 1023 decimal (0x3FF) if you are running the ADC with 10 bit resolution, 255 (0xFF) at 8-bit resolution.

In the data sheet

Atmel wrote:
The ADC converts an analog input voltage to a 10-bit digital value through successive approximation. The minimum value represents GND and the maximum value represents the voltage on VCC or an internal 1.1V reference voltage.

HTH!

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

so with the attiny13 there is no avcc, only an internal refrence, which is 1.1V, which means i can only measure between 0-1.1V

i was trying to measure up to 5V.

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

Go back and read the data sheet on REFS0. Instead of selecting the internal 1.1V reference, reference your measurements to Vcc. You will then be able to read voltages up to your Vcc voltage which is 5V.

Cheers,

Tom

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

tblough wrote:
Go back and read the data sheet on REFS0. Instead of selecting the internal 1.1V reference, reference your measurements to Vcc. You will then be able to read voltages up to your Vcc voltage which is 5V.

:evil: BLARG!?!

when i initially set it up, i did have vcc as reference, but then i copy pasted the original example and modified it, and forgot to change that back.

ill try it out now.

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

yay! seems to work now.

although... i have it set to light up if ADCH > 150, and it lights up just from me touching it with my finger.

if i have 5V as my reference an 255 is the highest.
each increment of 51 should be equal to another volt.

which would mean at 150, it getting more than 3V from my just touching it.

add:

i put a 1k Ohm resistor between adc1 and ground, and it seems to work perfectly now. :lol:

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

Excellent Tutorial, very useful esp for newbie like me!
One question:-

1) Can the ADC detect only mV change without a transistor? My ultrasonic receiver only send a few mV when a signal is detected. Can I directly connect the Ultrasonic receiver to the ADC? Or is it a MUST to use a transistor?

2) Why a PIC can directly measure a ultrasonic receiver without a transistor? Does that mean the PIC ADC is more sensitive compared to AVR microcontroller?
http://www.micro-examples.com/public/microex-navig/doc/090-ultrasonic-ranger.html This is the website where they directly connect the ultrasonic receiver to the PIC ADC pin.

Thanks in advance...

cs

I'm happy ytd, today, and tmr :)

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

With an AREF=5.0V then if you manage to achieve 10 bit accuracy each step will be 5.000V/1024 ~= 5mV

So what is the exact spec of your ultrasonic receiver?

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

my ultrasonic receiver has no name! no spec! It only labelled as T and another one as R (the two look exactly the same), so I guess the one labelled as T is transmitter and R is a receiver.

By the look of my ultrasonic transmitter and receiver, it looks like this one:-

So I dont know how many mV it will generate, as a matter of fact, there is no datasheet for this pair of ultrasonic transmitter/receiver.

cs

I'm happy ytd, today, and tmr :)

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

Silly question then - how do you propose to use a piece of electronics that you don't understand the operation of?

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

How would i add a second ir sensor so if i have one in front of a robot and one in back (i got 1 working so far)?

Hobbles and Company â„¢

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

clawson wrote:
Silly question then - how do you propose to use a piece of electronics that you don't understand the operation of?

Well, I am really out of desperation, I can't find any ultrasonic Tx/Rx, so when I see one, even without any documentation and label, I just bought it! I hope I can play around with it and understand it by experimentation!

BTW,

clawson wrote:
With an AREF=5.0V then if you manage to achieve 10 bit accuracy each step will be 5.000V/1024 ~= 5mV

Can we use AREF as 3.0V? then 3.000V/1024 ~= 2.92 mV more sensitive? Is there any limit? Can I use 0.3V as AREF? then the AVR is so sensitive 0.292 mV? My commonsense told me no...So, what is the lowest AREF I can use?

I read the documentation of my AVR 169, it says "The ADC has a separate analog supply voltage pin, AVCC. AVCC must not differ more than ± 0.3V from VCC" Pg 193.

So, if my VCC is 3.3V, then my AVCC can be 3.0V. Is this the lowest?

cs

I'm happy ytd, today, and tmr :)

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

hobbles wrote:
How would i add a second ir sensor so if i have one in front of a robot and one in back (i got 1 working so far)?

Well, if you can make the first ir work, then it should not a problem to make a 2nd ir work. You should tell us more about your problem, what is not working? Do you use modulation for your ir? Perhaps a TSOP17xx series chip for detection?

Can you post your schematics and code here? Just coincidence, I am developing a robot with ir sensors and now the ultrasonic sensors too.

cs

I'm happy ytd, today, and tmr :)

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

Oh a ultrasonic sensor would be awesome radio shack sells them for too much $32 for the parallax one. Well the tut kinda skipped the part on how to use like adc0 and adc1 and the others at the same time im using a 168 with this ir circuit http://www.reconnsworld.com/ir_ultrasonic_basicirdetectemit.html and the output is connected to adc0. So im not sure how to read whats coming off the second sensor from adc1.

Hobbles and Company â„¢

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

can anyone write this program in assembly for at90pwm3b uC?
thank you very much

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

Hello,

I've been trying to use the sample Battery Charger provided by Atmel. It runs on the BC100 board with a ATTINY861 processor. The app note is AVR458.

The I'm having trouble with the unipolar differential conversion across two pins (pin 11 and 12). Using a multimeter, I see that the voltage difference between the two pins is .6 millivolts. However, when I try to read the ADC result from a Unipolar Differential Conversion, the result is 0.

Below is a snippet of my code. Can anyone tell me why I'm running into this error? I'm pretty sure the problem lies with my code.

			ADMUX = (1<<REFS0)| 0x17;							// Use External Voltage Reference of 2.5 volts			
			ADCSRA = (1<<ADEN) | (1<<ADSC) | ADC_PRESCALER;		// Start conversion, no interrupt (disable ADC-ISR).

			do
			{ // Wait for conversion to finish.
			} while (!(ADCSRA & (1<<ADIF)));

			ADCSRA |= (1<<ADIF);  								// Clear ADC interrupt flag manually.


			sensorArray[11] = ADC;								// Save the sampled offset.

ADD~ Sorry, just realized that I'm not supposed to post questions to this forum! I re-posted this question in the correct forum.

Attachment(s): 

Last Edited: Mon. Jul 20, 2009 - 05:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

Thanks for the tutorial Ken; it was just what I was looking for.

I am trying to get this working with an attiny45. I read through the entire post hoping someone else was running into the same problem I am. I found a post where the user was having my exact issue, but unfortunately a resolution was never posted.

https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=425057&highlight=#425057

My code is basically the same as pepper_bg’s. Here is how my hardware is connected:

Pin 1 to output of the 10k pot voltage divider.
Pins 2 and 3 have the LED’s.
Pin 4 to ground.
Pin 8 to VCC

I also have my AVRISP mkII connected as well.

MKII to attiny45
Pin 1 to Pin 6
Pin 2 to VCC
Pin 3 to Pin 7
Pin 4 to Pin 5
Pin 5 to Pin 1
Pin 6 to Ground

With the MKII connected, it works as described in pepper_bg’s post. LED1 turns on at about 2.1V, LED2 at about 2.5 at which point LED1 turns off. LED2 then stays on up to max. With the MKII disconnected LED1 turns on at max only, about 4.85 volts.

Any help would be greatly appreciated.

I am totally new to this stuff and have tried some other easier tutorials with success. But was wondering why when the MKII is disconnected the programs run differently or sometimes not at all. Once a chip is programmed shouldn't it function as intended with the MKII disconnected?

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

I used the tutorial in a Mega16A, off course i had to do a little modification, and i have the ADC working, but... I don´t understand why!

here is the code:


#define F_CPU 1000000UL  //1MHz

#include 

//Ports

#define LED1 PA0
#define LED2 PA1
#define POT ADC2

int main(void){
   
   DDRA|=_BV(LED1)|_BV(LED2);  //LEds input,

//ADC CONF

   
   //1MHz/8=125kHz   limit Prescaler [50 200] kHz

   ADCSRA|=_BV(ADPS1)|_BV(ADPS0);   //Define prescaler  8=(0b011)
   ADMUX|=_BV(MUX1);                //input ADC2
   ADMUX|=_BV(REFS0);               //Ref AVCC

   
   //Free-running mode 000
   ADCSRA|=_BV(ADATE); //set Auto Triguer

   ADMUX|=_BV(ADLAR); //use only ADCH

   ADCSRA|=_BV(ADEN); //ADC on

   ADCSRA|=_BV(ADSC);  //start ADC

//end ACD CONF
   
   
   while(1){
      if(ADCH<128){  // Led1 on
         PORTA|=_BV(LED2);
         PORTA&=~_BV(LED1);
      }
      else{           //led2 on
         PORTA|=_BV(LED1);
         PORTA&=~_BV(LED2);
      }

      ADCSRA|=_BV(ADIF); // if i remove this line it stops working
   }
   return (0);
}

in the datasheet they say that the Interrupt flag is set when the conversion ends, so why do i have to set it manually?

the code is correct?

Thanks for your help

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

Awesome tutorial thanks.

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

A friend of mine tells me that my range of adc can be a multiple of the reference voltage...so that if im using Vcc as my reference voltage, which is going to be 2V, i should be able to measure more than 4V.

i checked the documentation on my attiny13, but i didnt see anything about that, although im probably not looking for the right thing.

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

Quote:

A friend of mine

I'd put more faith in the datasheets than a "friend". Generally the 0..255/0..1023 range of readings will be split between Gnd and the reference voltage.

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

thats what i thought, the reference voltage is the MAX voltage you can measure.

the problem is that i wanted to use an attiny to measure battery voltages, while running off of the batterys. but if its running off the batters, the attiny has to be able to run when the batterys are at there discharge point, which is 2.7V so its possible, but then if Vcc is my reference i wouldnt be able to measure more than that...

edit:
i could probably just use a couple of resistors so that the attiny gest 1.8V while the batterys are at 2.7V, then have it calculate for full etc...

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

The method to measure battery voltage using the ADC has been widely documented here a number of times. A search should find a suitable thread (I'm guessing the words "ADC" and "battery" are going to be involved! ;-))

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

Placing a resistor divider from Vbat to ground to measure battery voltage is ok, but you will waste current in the divider. If the device is supposed to run for a long time, this is a problem

You can solve that by adding a mosfet on the bottom of the divider, using an I/O pin to turn the mosfet on before you make your measurement. This way, the divider is disconnected when not in use. The mosfet draws no current in the on or off state, and its on resistance is so low that it won't be noticable.

How long you need to delay between turning on the mosfet and making the reading depends on the resistor values and whatever filter capacitance you're using.

If the battery voltage is much higher than VCC, then you'll want to switch it on the high side, using a Pfet and an open collector or open drain inverter.

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

dbvanhorn wrote:
Placing a resistor divider from .... *trimmed*

since im using an attiny13, my adc' reference voltage is the attiny13's source voltage, which means i have to be able to power the attiny13 at the same time the batterys are virtually dead.

right now the resistor divider is the only way i can think it would work right now, although a bit wasteful.

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

You use the internal bandgap 1.1V not Vref when measuring the battery. I DID suggest you search for this above. When I tried it "internal bandgap adc battery" hit a load of very useful looking threads. Just a few of those:

https://www.avrfreaks.net/index.p...
https://www.avrfreaks.net/index.p...
https://www.avrfreaks.net/index.p...
https://www.avrfreaks.net/index.p...

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

clawson wrote:
You use the internal bandgap 1.1V not Vref when measuring the battery. I DID suggest you search for this above. When I tried it "internal bandgap adc battery" hit a load of very useful looking threads. Just a few of those

i did do several searches, and didnt find any results anywhere close to that good :oops:

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