Does ADC conversion to a voltage rely on the actual value of the +5 V pin? Questions:


Does the conversion of the ADC count to voltage depend on the actual voltage of the +5&nbsp;V pin?
If yes, what is the accepted method of getting that voltage from the board?


Background/Detail:

I have a circuit in which I have an Arduino Nano (clone) running from a USB connector (from a hub). The job of the Arduino is to measure the voltage on a battery which will drive a second circuit switched on/off by the Nano. For reference it is a battery tester.



There is a Nokia 5110 screen which displays the voltage from the very simple sketch below.

void setup() {
  Serial.begin(9600);
  display.begin();
  // Init done

  // You can change the contrast around to adapt the display
  // for the best viewing!
  display.setContrast(50);

  // Text display tests
  display.setTextSize(1);
  display.setTextColor(BLACK);
}


void loop() {
  display.clearDisplay();   // Clears the screen and buffer
  display.setCursor(0,0);
  display.print("Vin=");
  int rawVIN = analogRead(VIN);
  float floatVin = (rawVIN*4.75)/1023.0;
  display.println(floatVin);
  Serial.println(rawVIN);
  display.display();
  delay(1000);
}



I measured the voltage of the battery using a DVM and it is 4.13 V, yet
the Nano reports 4.35 V.
I have a common ground between the battery and Arduino.
Because the connection to test the voltage can float, I have a pulldown resistor to stop wild fluctuations (>10 kΩ)


After some investigation I found that the +5&nbsp;V was actually outputting 4.75&nbsp;V and changed my sketch from

float v = (rawVIN*5.0)/1024.0;


to

float v = (rawVIN*4.75)/1024.0;


and the voltage reading on the Arduino was now correct. I did this not because I understand what I did, I did it because I had a hunch it might change the value to the correct one.
The ADC inside the Arduino does not measure voltage, but rather a
voltage ratio. Namely the ratio from the voltage at the analog input
to the voltage at the Vref pin.

In the default configuration, the Vref pin is internally tied to the
+5&nbsp;V line. You can select to use instead an internal reference as
Vref:



analogReference(INTERNAL);


This reference  is about 1.1&nbsp;V, and is is quite immune to
fluctuations on the +5&nbsp;V. The problem is that you cannot measure
voltages higher than the reference.

For your battery tester, if you want some sort of “absolute”
measurement, you could use the internal reference and a voltage divider
to ensure the measured voltage is below 1.1&nbsp;V.

Edit: Another option which does not require a voltage divider is to
use Vcc as a reference to measure both the analog input and the
internal 1.1&nbsp;V “bandgap“ reference. Measuring the 1.1&nbsp;V
against Vcc is an indirect way to measure Vcc. This is not supported by
the Arduino core library, but you can do it by programming directly the
control registers of the ADC:

// Return the supply voltage in volts.
float read_vcc()
{
    const float V_BAND_GAP = 1.1;     // typical
    ADMUX  = _BV(REFS0)    // ref = Vcc
           | 14;           // channel 14 is the bandgap reference
    ADCSRA |= _BV(ADSC);   // start conversion
    loop_until_bit_is_clear(ADCSRA, ADSC);  // wait until complete
    return V_BAND_GAP * 1024 / ADC;
}


Beware that the very first reading after boot may be bogus.