Switching ADC pins on 328P

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

I want to read from 2 different ADC channels in each loop of my code, but I'm having trouble successfully switching the channel in ADMUX. I can successfully read from either one. It seems like somehow the setting ADMUX isn't actually taking effect, or I'm reading before it takes effect (which seems unlikely because I'm recording for 100 samples). I'm getting pretty frustrated at this point, since my Google fu seems to be failing me. Here's what I've gotten so far:

 

#define num_ir_samples 100

uint16_t sample_light(uint8_t adc) {
    // Measure light level from phototransistors (multiple samples)
    
    // Set pin to sample from
    ADMUX = adc;
    ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler /128; enable
    
    // Read once and throw away to enact change channel?
    ADCSRA |= (1 << ADSC) | (1 << ADIF);
    //while (ADCSRA & (1 << ADIF) == 0);
    while (ADCSRA & (1 << ADSC));
    
    // Collect and average multiple samples
    uint32_t accum = 0;
    uint16_t i;
    for (i=0; i<num_ir_samples; i++) {
        // Initiate conversion
        ADCSRA |= (1 << ADSC);
        // Wait for completion
        while (ADCSRA & (1 << ADSC));
        // Accumulate result
        accum += 256*ADCH + ADCL;
    }
    // Get average light sample and invert for sanity
    return 1023 - (accum/num_ir_samples);
}

int main(void) {
    uint16_t val1, val2;
    while (1) {
        val1 = sample_light(0);
        val2 = sample_light(1);
        // Set 2 LEDs on/off depending on vals
    }
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
uint16_t sample_light(uint8_t adc) {
    // Measure light level from phototransistors (multiple samples)

    // Set pin to sample from
    ADMUX = adc;
.
.
.
        val1 = sample_light(0);
        val2 = sample_light(1);

That's setting REFS[1:0] to 0, which selects the AREF pin as a reference.  Do you have anything connected to that?  If not, you probably meant to select AVCC:

    ADMUX = (1<<REFS0) | adc;

 

Here:

        accum += 256*ADCH + ADCL;       

... C doesn't guarantee the order of evaluation in the above expression, but the AVR requires that you read ADCL first (unless you've set ADLAR).  You could:

        accum += ADCL;
        accum += 256*ADCH;        

... but why not just:

        accum += ADC;

?

 

 

"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

Thanks for the response. I'll check on REFS[1:0] when I'm back at my desk with my PCB layout. I'm getting accurate readings for a single sensor, though, so I'm guessing that's not my issue. (EDIT: just checked; AREF is routed to VCC, so that shouldn't be an issue.)

 

I didn't realize that the order of evaluation wasn't guaranteed. Is that a general thing? Because I don't think I've ever run into an issue with that.

 

And I didn't use accum += ADC because I cluelessly didn't realize that was an option.

 

But I don't think any of these would explain the problem with switching channels, would they?

Last Edited: Sun. Dec 10, 2017 - 05:55 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

pterosaur wrote:
I didn't realize that the order of evaluation wasn't guaranteed. Is that a general thing?

For an arithmetic expression, yes. Standard C.

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 REF bits in ADMUX? 

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

REFS[1:0] in ADMUX are both 0, which is what I want here.

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

pterosaur wrote:

Thanks for the response. I'll check on REFS[1:0] when I'm back at my desk with my PCB layout. I'm getting accurate readings for a single sensor, though, so I'm guessing that's not my issue. (EDIT: just checked; AREF is routed to VCC, so that shouldn't be an issue.)

 

I didn't realize that the order of evaluation wasn't guaranteed. Is that a general thing? Because I don't think I've ever run into an issue with that.

 

And I didn't use accum += ADC because I cluelessly didn't realize that was an option.

 

But I don't think any of these would explain the problem with switching channels, would they?


Apart from what I already said, your code looks fine. And the issue of order can indeed be the problem. Since order is not guaranteed, it could be in one order for the above case, and a different order for your single-channel case.
Further, the code you've posted is not complete. The problem could be in the omitted code which "// Set 2 LEDs on/off depending on vals". Post a >>complete<< but minimal program which demonstrates the problem so we can see the whole story. And post the complete working single-channel code.

"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]