Cannot switch between analogReference options

I tried to implement a function that reads an analog pin using the INTERNAL reference. However, all my other pins are linked to the VCC and I should use DEFAULT for them as such.

However as soon as I call analogReference(DEFAULT) I cannot seem to be able to switch back to INTERNAL.

The following example shows it.

#define ANALOG_IN 0

void setup() {
  Serial.begin(9600);
}

void loop() {
  analogReference(INTERNAL);
  int val = analogRead(ANALOG_PIN);
  delay(100);
  analogReference(DEFAULT);
  int val2 = analogRead(ANALOG_PIN);
  Serial.print(val, DEC); Serial.print(" "); Serial.print(val2, DEC); Serial.println();
  delay(100);
}

If you run the example sending a 2.5V to analog pin 0 for example, you will see the following output:

1023 511
511 511
511 511
...

The first value (1023) for val is ok (since 2.5V is way over 1.1V) but the others are wrong. Why is that so?

Perhaps try it with the delay between the calls to analogReference and analogRead

I really don't see how that could be a difference, given that analogReference doesn't do anything except setting a variable:

void analogReference(uint8_t mode)
{
        // can't actually set the register here because the default setting
        // will connect AVCC and the AREF pin, which would cause a short if
        // there's something connected to AREF.
        analog_reference = mode;
}

a register needs to be set in the ATmega chip for the change to have affect, I am suggesting that perhaps there may be a delay required for this change. You could check the data sheet or just give it a try. Or wait for someone else to come up with another suggestion :wink:

good luck!

Hmm... you might try modifying the code inside the analogRead() function to delay if the analog_reference variable has changed. I have to admit, I didn't test switching between modes for different pins in the same program.

All right, I figured out that you need to wait between the setting of ADMUX and the time of the analogRead. Which can be done under Arduino by calling the analogRead function twice with a delay between both. Here.

/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Returns the analog value at #pin# by using the analog reference mode
 * specified by #mode#. Switches back to original mode after.
 */
int analogReadReference(byte pin, byte mode) {
  // Makes sure mode has been set in ADMUX by calling analogRead() on method's first call
  static bool firstCall = true;
  if (firstCall)
    analogRead(pin);
  
  uint8_t currentReference = (ADMUX >> 6); // copy current reference
  analogReference(mode);                   // switch to new reference
  
  // XXX I don't know why but without these lines the switch from 
  // DEFAULT to INTERNAL does not work well.
  analogRead(pin);
  delay(100);
  
  int value = analogRead(pin);             // read value
  analogReference(currentReference);       // switch back to original reference

  return (value);
}

I think I remember something in the datasheet which suggested throwing out the first sample after switching.

Can't quite remember the details of the context but this would then make perfect sense.