How to get a working ADC? ATMEGA328P

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

The 328p datasheet does not explain what it means by "voltage reference selection". I want to connect a potentiometer to the Arduino Uno R3, how do I do it? The three pins to GND, 5V and (for instance) ADC0? Or GND, AREF and ADC0? Or 5V, AREF and ADC0? Impossible to know.

 

 

Secondly, how do I read the value of the ADC? The ADCL and ADCH (low, high?) have some disclaimer to them, is it a good idea to set ADLRA in ADMUX? (see below)

 

 

Basically, how does the correct code to get the ADC working look? Preferably interrupt driven. I saw the tutorial on this site but they lied and it didn't work (EDIT of course not, turns out the ADRF bit is replaced by ADATE, then it works!). All examples on the internet are bogus aswell, even Atmel themselves can't provide correct code. I've sat here for a while now, I wouldn't ask you if I hadn't given up.

 

Thanks so much and for enduring my grumpiness!

sol i sinne - brun inne

Last Edited: Sat. Feb 14, 2015 - 01:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tickstart wrote:

I saw the tutorial on this site but they lied and it didn't work. All examples on the internet are bogus aswell, even Atmel themselves can't provide correct code. I've sat here for a while now, I wouldn't ask you if I hadn't given up.

 

Thanks so much and for enduring my grumpiness!

 

Only if you are willing to endure our retort.

Ross McKenzie ValuSoft Melbourne Australia

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

The arduino library is always a good start. Scout around in the arduino install directory and find it.

Here's some code from off the top of my head (actually from reading the data sheet):

void adc_init(void)
{
    ADMUX = (1<<REFS0);     //select AVCC as reference
    ADSRA = (1<<ADEN) | 7;  //enable and prescale = 128 (16MHz/128 = 125kHz)
}

int readAdc(char chan)
{
    ADMUX = (1<<REFS0) | (chan & 0x0f);  //select input and ref
    ADSRA |= (1<<ADSC);                 //start the conversion
    while (ADSRA & (1<<ADSC));          //wait for end of conversion
    return ADCW;
}

If this doesn't work, then post your test code and tell us the result.

 

 

If you want to get down and dirty with coding, you'll need to learn how to read the data sheet. Arduino was invented for those who don't want to get their hands dirty with the nitty-gritty of datasheets and how the processor works and hides the evil in libraries and standard hardware configurations.

Last Edited: Sat. Feb 14, 2015 - 07:34 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

valusoft wrote:

 

Only if you are willing to endure our retort.

laugh yeah I agree, oh how I love blaming tools.. But now I've had at least a couple hours of sleep, feeling like new (sort of..)!

 

Kartman wrote:

The arduino library is always a good start. Scout around in the arduino install directory and find it.

Here's some code from off the top of my head (actually from reading the data sheet):

void adc_init(void)
{
    ADMUX = (1<<REFS0);     //select AVCC as reference
    ADSRA = (1<<ADEN) | 7;  //enable and prescale = 128 (16MHz/128 = 125kHz)
}

int readAdc(char chan)
{
    ADMUX = (1<<REFS0) | (chan & 0x0f);  //select input and ref
    ADSRA |= (1<<ADSC);                 //start the conversion
    while (ADSRA & (1<<ADSC));          //wait for end of conversion
    return ADCW;
}

If this doesn't work, then post your test code and tell us the result.

 

 

If you want to get down and dirty with coding, you'll need to learn how to read the data sheet. Arduino was invented for those who don't want to get their hands dirty with the nitty-gritty of datasheets and how the processor works and hides the evil in libraries and standard hardware configurations.

 

Appreciate it man, thanks. I will test and see what happens. The arduino library, you mean the files inside their IDE? I never bothered with the arduino software, I don't like "simplified", but I do like their hardware. And their examples are pretty much useless since they obfuscate their code with macros you can't examine. I'm just going off the datasheets, and maybe if I can discern the Atmel application notes I'll scan through those (I'm usually very impatient though, don't know why).

sol i sinne - brun inne

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

Okay, I tried some version of the code you gave me. Some registers you used are imaginary, at least according to the datasheet. It might have been a typo so I tried my best to "correct" it. Still nothing. Please read the comments in the code.

 

#define LEDPORT PORTB		// Arduino pin 13 is bit 5 of port B
#define LEDPORT_DIR DDRB
#define LEDBIT	5
	
unsigned int comp = 128;    // I'm not sure which value to set here..
                            // I guess the formula "ADC = Vin * 1024 / Vref".
                            // But at the moment it does not make any difference anyway

int readAdc(char chan)
{
	ADMUX = (1 << REFS0) | (chan & 0x0f);
	ADCSRA |= (1 << ADSC);                 // this said "ADSRA", changed to ADCSRA
	while (ADCSRA & (1 << ADSC));          // this too.. besides, what about ADIF?
	                                     // isn't that set when the conversion is done?
	return ADCW;                         // ADCW does not exist in the datasheet, but
	                                     // Atmel Studio does not complain..
}

int main (void)
{
	LEDPORT_DIR = _BV(LEDBIT) ;

	for (;;) {
		if (readAdc(0) < comp) {
			LEDPORT |= _BV(LEDBIT);         // on
		} else {
			LEDPORT &= ~_BV(LEDBIT);       // off
		}
	}
}

 

sol i sinne - brun inne

Last Edited: Sat. Feb 14, 2015 - 09:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is what I have now. Not working of course, but it should (:P).

int readAdc(char chan)
{
	PRR &= ~(1 << PRADC);
	ADMUX = (1<<REFS0) | (chan & 0x0f);  //select input and ref
	ADCSRA |= (1<<ADSC);                 //start the conversion
	while (!ADIF);          //wait for end of conversion
	return ADCH;
}

sol i sinne - brun inne

Last Edited: Sat. Feb 14, 2015 - 10:11 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ADCSRA & (1 << ADSC) should work equally well or better I suppose, I'm just guessing at this point. Searching through the git repository after code but it's almost impossible. 

sol i sinne - brun inne

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

Kartman wrote:
If this doesn't work, then post your test code and tell us the result.

 

Okay you have posted your code and said it doesn't work ad nauseum.  The part that is missing is the result!

 

What is it that doesn't work?  What values are you getting?  What is the circuit you are using, a schematic perhaps?  Read the tutorial again, see if you missed something.  The tutorial already passed a peer review here.  Sorry, but sometimes our patience runs out too.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

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

alright alright.. Unless I've coupled the potentiometer wrong (not an impossibility), given that the ADC actually returns a value, it seems to be zero no matter what. The potentiometer is connected to 5V, GND and ADC0. "Connect VCC to an outer pin, GND to the other, and the center pin will have a voltage that varies from 0 to VCC depending on the rotation of the pot."

 

Hm, I used the first example in the tutorial, and depending on how the pot is positioned when I reset the program, actually changes the LED. Always something (:

sol i sinne - brun inne

Last Edited: Sat. Feb 14, 2015 - 11:05 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ADCSRA |= (1 << ADSC);
_delay_ms(10);
while  (ADCSRA & (1 << ADSC));
adc_tmp = (ADCL | (ADCH << 8));       

AvrStudio 7
AVR ISP MkII Clone
Core I3-4330
Kingston HyperX Savage SSD

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

Aha! It was the ADATE bit that was missing! Instead of ADRF or whatever the mysterious bit was named. Just a regular case of misreading the datasheet then, not surprising. Kartman your code might well be working after all.

sol i sinne - brun inne

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

The register names could have been dyslexia on my part, nevertheless you've resolved that. As for ADSC vs ADIF they are similar but different. If you use ADIF and not interrupts, you must specifically clear this bit. By 'clearing' this means writing a '1' bit to it. Says so in the datasheet.
ADCW is a avr-gcc thing. It reads the adc registers in the correct order (as per the datasheet).
How do you know if your pot is connected to the correct port pin? How do you know your pot works? How do you know it always outputs 0?
Don't ever underestimate the complexity of this kind of stuff. You need to get a lot of small things correct in order for it to work. One mistake can stop it and two or more mistakes can really upset you.
You can prove your hardware by writing an Arduino sketch.
I'd suggest you get the uart going in your code so you can output more meaningful results as compared with one led.
I looked at the Arduino library code and it is near identical to what i wrote. As for Arduino being simple, yes, it does already what you end up doing. There's no magic.

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

Disregard, too tired to reply.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Sat. Feb 14, 2015 - 11:53 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just noticed, your code does not enable the ADC - i wrote adc_init for a reason. ADATE is for auto triggering - should be 0.
Mixer188, why the delay and the last line of your code is suspect. How do you guarantee the compiler reads the regs in the correct order? ADCW does what is required.
The arduino source is located somewhere like:
\program files\arduino\hardware\cores\
The adc file is something like wiring_analog.c
I may have got these wrong - i'm pulling these off the top of my head and my ipad is not much help.
So the hidden 'macros' can be found.

Last Edited: Sat. Feb 14, 2015 - 12:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use the 328 a/d. In the init I use ADMUX = 0x40 to use vcc as the ref, and I use DIDR0 = 0x3f; to disable digital inputs on the a/d pins.

Imagecraft compiler user

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

Is the mega328 AVcc powered and bypassed with capacitor?  ADC will be broke without that, even with all the SW corrections.

It all starts with a mental vision.

Last Edited: Sun. Feb 15, 2015 - 12:59 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a very elementary and useless free-running mode ADC example that I had done a couple of years ago and rewrote today.  Wrote it for an ATmega1280 on an original Arduino Mega.  Used some funky retro macros that I found in the tutorials and in forum posts for setting up the LED pins .  I think Danni gets the credit for them.

/*
 * ADCwithapot.c
 *
 * Created: 2/14/2015 04:45:37 PM
 * Author: Larry
 *
 * Potentiometer is wired across +5V VCC and GND
 * with the wiper connected to ADC0.
 * LED1 and LED2 are used as status indicators
 * and are connected to PORTB pins 0 and 1
 * respectively.
 *
 * Code was written for ATmega1280 and comments reflect that
 *
 */

#include <avr/io.h>

struct bits
{
    uint8_t b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
} __attribute__((__packed__));

#define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
#define SBIT(port, pin) SBIT_(port, pin)

enum {LOW, HIGH};

#define PORT PORTB
#define DDR DDRB

#define LED1            SBIT(PORT, PB0)
#define LED1_bm         (1 << PB0)
#define LED1_ACTIVE     HIGH
#define LED1_INACTIVE   !LED1_ACTIVE

#define LED2            SBIT(PORT, PB1)
#define LED2_bm         (1 << PB1)
#define LED2_ACTIVE     HIGH
#define LED2_INACTIVE   !LED2_ACTIVE


int main (void)
{
    // Variable to hold ADC result
    unsigned int adc_data;

    // Initialize LED pins as outputs
    DDR = LED1_bm | LED2_bm;

    // Set up ADMUX - ADC multiplexer selection register
    // Set ADC channel 0 - ADMUX bits 4..0 cleared - default after reset
    // Clear ADLAR bit in AMUX to have right adjusted result -default after reset
    // Voltage Reference Selection - AVCC with external capacitor at AREF pin - ADMUX REFS0 bit 6 set REFS1 bit 7 clear
    ADMUX = (1 << REFS0);

    // Set up ADCSRB - ADC Control and Status Register B
    // Set ADC Auto Trigger Source to Free-Running Mode - ADTS2 ADTS1 ADTS0 bits 2..0 clear - default after reset
    // Set ADC channel 0 - ADMUX bit 5 cleared - default after reset

    // Set up ADCSRA - ADC control and status register A
    // Set ADC prescaler to 128 - 125KHz sample rate @ 16MHz - ADCSRA ADPS2 ADPS1 ADPS0 bits 2..0 set
    // Set ADC ADC Auto Trigger Enable - ADCSRA ADATE bit 5 set
    // Enable ADC - ADCSRA ADEN bit 7 set
    // Start taking continuous samples by writing logical one to ADCSRA ADSC bit 6
    ADCSRA = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADATE) | (1 << ADEN) | (1 << ADSC);

    // Wait for the first conversion to complete.
    // When the conversion completes the ADC Data Registers are updated
    // and the ADCSRA ADIF bit is set and will remain set until we clear it
    // or a reset occurs.
    while ((ADCSRA & (1 << ADIF)) == 0);
        
    // Since we are in Free-Running Mode new conversions will start immediately after the completion
    // of the current one and will repeat as long as we leave ADSC high.

    while (1)
    {

        // Delay seems to be required - Reason unknown at this time
        asm("NOP");
                
        // Read all 10 bits
        adc_data = ADCW;

        // The compare values are arbitrary and only used to demonstrate that the code works

        if (adc_data == 0)
        {
            LED1 = LED1_INACTIVE;
            LED2 = LED2_INACTIVE;
        }
        else if (adc_data <= 512)
        {
            LED1 = LED1_ACTIVE;
            LED2 = LED2_INACTIVE;
        }
        else if (adc_data == 1023)
        {
            LED1 = LED1_ACTIVE;
            LED2 = LED2_ACTIVE;
        }
        else     // ((adc_data > 512) & (adc_data < 1023))
        {
            LED1 = LED1_INACTIVE;
            LED2 = LED2_ACTIVE;
        }
    }
}

 

EDIT: Changed code per discussions below.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Mon. Feb 16, 2015 - 12:36 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a very elementary free-running mode ADC example that I had done a couple of years ago and rewrote today. 

Indeed.  

 

        // Wait for this conversion to complete
        // When the ADC conversion completes the ADC Data Registers are updated and the ADCSRA ADIF bit is set.
        // Since we are in Free-Running Mode new conversions will start immediately after the completion
        // of the current one and will repeat as long as we leave ADSC high.
        while (!(ADCSRA & (1 << ADIF)));

Since the last sentence of the comments is correct, the first two sentences of the comment as well as the code line are not.  Pretty much meaningless (ADIF always set; no waiting for conversion-complete)about 100us after AVR startup until the AVR is again reset.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Lee, I was hoping you would comment.  I knew that part of the code did not make sense, it has bothered me from day one, and even more so when I added the comments yesterday.  So what you are saying is that since it is free-running we don't check for any condition and only loop to read the data registers?  I need more coffee, that is why I am asking.

 

Actually without the check the code does not work correctly.  What critical piece of the puzzle am I missing here?

 

EDIT: I added asm("NOP"); in place of the check and now the code works.  I would still like to get your input on all of this. 

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Sun. Feb 15, 2015 - 07:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Like Cliff,   I would prefer not to use ADATE with changing the mutiplexer.    But I suppose it could be done.   e.g.

 

ISR() {

      ADIF is cleared by hardware on entry

      read ADCW from just completed conversion.

      change multiplexer

      this multiplexer value will be the one used when ADATE fires off the next sample-and-hold

}

 

Somehow you are relying on the sample-and-hold having completed and the conversion begun before you get to service the ISR()

 

I would be happier without ADATE.    Then you will know exactly which channel was being sampled.   e.g.

 

ISR() {

      ADIF is cleared by hardware on entry

      read ADCW from just completed conversion.

      change multiplexer

      allow a microsecond or two for multiplexer to charge stray capacitance.

      set ADSC to start conversion on current multiplexer channel.

}

 

Untested.   You can probably change multiplexer before you read ADCW.   i.e. those cycles allow stray capacitance to charge.

 

David.

Last Edited: Sun. Feb 15, 2015 - 08:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Actually without the check the code does not work correctly.  What critical piece of the puzzle am I missing here?

Define "correctly".  Without the check, the first conversion will not have completed, so the first result will be nonsense.  After that, a read of ADC/ADCW will always give the result of the latest conversion, with or without the check.

 

I guess the check >>does<< serve to burn a couple cycles,  The fact remains that ADIF will always be set so the check is always true.

 

I'm with Cliff and David -- I've rarely found a use for free-running over the years, and certainly none with multiple channels involved.  The only time I can remember putting it into AVR8 apps is when that is the only ADC channel being used, it is used to monitor raw power, and there is no need to conserve the last bit of supply power.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

The following should be a good start.

 

While it is really a trivial matter, Ill leave activating the interrupt up to you...

// Compiler: ICCAVR V7.23
// Platform: Arduino Nano V3.0 hosting the ATMega328P
// Fosc: modified from 16.000MHZ to 18.432MHz
// Avcc: External 0.1uF capacitor connected between AREF & GND
// Aref: Internal 5.0 volt
// Mode of operation: Free running, no interrupt
// ADC configuration: 10 bit, right justified

#include <iom328pv.h> // Or what ever your compiler calls it.
#include <stdio.h>
#include <float.h>

void adc_init(void)

void main(1) {

     float ADC0_Temp;

     adc_init();

     while(1) {
	  // Measureing the 3v3 voltage source provided by the FTDI USB to USART
          ADC0_Temp = (5.00 * (float)ADC) / 1023;
          printf("ADC0: = "); // Send text string to the consol ---> USART0
          printf("%+1.1f Volts", ADC0_Temp); // Send 3V3 meqasurement to the consol
     }
}

/****************************************************************************/
/******************************* ADC0 Handler *******************************/
/****************************************************************************/
// Initialize ADC for Channel 0
// Conversion time: 6.944uS
void adc_init(void) {

     ADCSRA = 0x00; // Disable ADC

     // Channel 0 selected: MUX3 = 0, MUX2 = 0, MUX1 = 0, MUX0 = 0
     // ADC input 0 selected, right Justified (ADLAR = 0)
     ADMUX = (1<<REFS0); // Avcc, external capacitor connected at AREF pin: 0x40 
     ACSR = (1<<ACD); // Disable the Analog comparator: 0x40

     // Turn off digital input buffers on ADC channels: DIDr0 = 0xFF, DIDR2 = 0xFF 
     // For ATMega328P
     DIDR0 = (1<<ADC7D) | (1<<ADC6D) | (1<<ADC5D) | (1<<ADC4D) |/
             (1<<ADC3D) | (1<<ADC2D) | (1<<ADC1D) | (1<<ADC0D); 

     // ADCSRB = 0x00; // ~((1<<ADTS2) | (1<<ADTS1) | (1<<ADTS0)) = Free running

/*******
             |   ADEN   |   ADSC    |   ADATE    |        ADPS2, ADPS1, ADPS0          |
             |   ADC    |   Start   |    Auto    |              ADC CLK                |
             |  Enable  | Conversion|   Trigger  |           Divide by 128             | *******/
     ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADPS2) | (1<ADPS1) | (1<<ADPS0); // 0xE7
}

 

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

Lee, definition of correctly is; LED displays change with varying voltages applied to ADC0.  This was not occurring without the delay.  Interesting that a NOP would be enough of a delay to make it work though.

 

Thanks for the critique, now I can file that away as a very elementary and useless free-running mode ADC example.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

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

Using Fritzing to illustrate your case is not a bad idea. Anyone should consider it sometimes, even the pros. It has a highly educational value and a strong visual effect.

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

How would fritzing add value in this instance? We're talking about code, not wiring.

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

Unless I've coupled the potentiometer wrong (not an impossibility)

 

Don't you think you then should describe to the community here how you did connect it?

 

Anyway: One end of pot goes to GND, the other to VCC. Slider goes to the ADC pin. Wiring the pot up like this will form a variable voltage divider, and since the ADC want a voltage this is how you need to wire it up.

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

Don't you think is worth 1000 words?

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

Tickstart wrote:

This is what I have now. Not working of course, but it should (:P).

int readAdc(char chan)
{
	PRR &= ~(1 << PRADC);
	ADMUX = (1<<REFS0) | (chan & 0x0f);  //select input and ref
	ADCSRA |= (1<<ADSC);                 //start the conversion
	while (!ADIF);          //wait for end of conversion
	return ADCH;
}

I realise this occurred early in the thread but not entirely sure why no one pointed out this obvious error in this?

 

Hint: you might want to explore what "ADIF" is defined as.

 

I rather imagine you meant something like:

    while (!(ADCSRA & (1 << ADIF)));          //wait for end of conversion
    ADCSRA |= (1 << ADIF); // ADIF does not self-clear like ADSC so now you must clear it too

though why anyone uses ADIF for this is a whole new question!

 

EDIT: Oh and even as I posted that I spotted the next error. You are not setting ADLAR in ADMUX yet you are aonly reading ADCH. Again, it's a no-no.

 

So perhaps we should have your code placed in a glass case as an example of "everything you must never do when trying to read ADC?" ;-)

Last Edited: Mon. Feb 16, 2015 - 01:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Usually the problem with an AVR a/d is there aren't ENOUGH bits, not that are two too many bits. Also, mentioning guns by text are not allowed. By extrapolation, I will assume that mentioning guns pictorially are also not allowed.

 

Imagecraft compiler user

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

bobgardner wrote:
Also, mentioning guns by text are not allowed. By extrapolation, I will assume that mentioning guns pictorially are also not allowed.
Bob, sometimes a pot is just a pot.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Mr tickstart has dropped this thread methinks. Hopefully he resolved the problem.