I'm using the USB to power my Arduino UNO, and therefore my analogRead() values are relative to the actual internal Vref at the "5V" pin, not a nominal "5 volts". So my voltage values are calculated by the 0 - 1023 analogRead() values being multiplied by whatever the Arduino has decided that Vref is.
So is there any way in my sketch to determine what that Vref value is? I guess analogReference() just sets the source, but is there any way to find out what the internal value is? Seems like it should be easy. And I'm getting tired of turning on my multimeter to measure the volts on the "5V" pin.
// Here is a trick that allows you to check the
// power rail voltage against the 1.1V (+/- 10%)
// internal reference.
//
// Run the sketch, send 'R', and use a good meter
// to measure the voltage from the AREF pin to
// Ground. Put the measured reference voltage
// in millivolts (should be between 1000 and
// 1200) into the sketch as
// 'InternalReferenceMillivolts'.
//
// Upload the (now-calibrated) sketch again and
// send 'V' to read the current "+5V" voltage
// (should be around 5000 mV). Compare that to
// the voltage measured at the +5V pin. If the
// answer is not close enough, adjust the
// InternalReferenceMillivolts to get a closer
// result.
//
// Now you can use "(getVccMillivolts()/1000.0)"
// in place of "5.0" in your sketch to get analog
// readings less dependent on fluctuations in the
// "5V" line.
void setup()
{
Serial.begin(115200);
while (!Serial); // Wait for USB connection on Leonardo/Micro
delay(1000);
Serial.println("Send 'R' to put reference voltage on AREF pin for measurement.");
Serial.println("Send 'V' to measure supply voltage.");
}
void loop()
{
switch (Serial.read())
{
case 'r':
case 'R':
analogReference(INTERNAL);
delay(500);
Serial.println("Now measure the voltage at the AREF pin.");
Serial.println("Put that value in this sketch as InternalReferenceMillivolts.");
break;
case 'v':
case 'V':
analogReference(DEFAULT);
Serial.print("Power rail (millivolts): ");
Serial.println(getVccMillivolts());
break;
}
}
/*VVVVVVVVVVVVV The part below here goes into your sketch VVVVVVVVVVVV*/
// Adjust this value to your boards specific
// internal bandgap reference voltage in millivolts
const unsigned long InternalReferenceMillivolts = 1080UL;
// Returns actual value of Vcc in millivolts
int getVccMillivolts()
{
// Set the analog reference to DEFAULT (AVcc == Vcc power rail)
// REFS1 REFS0 --> 0b01 -Selects DEFAULT (AVcc) reference
// Set the analog input to channel 14: the INTERNAL bandgap reference (1.1V +/- 10%)
// MUX3 MUX2 MUX1 MUX0 --> 0b1110 -Selects channel 14, bandgap voltage, to measure
ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0);
delay(50); // Let mux settle a little to get a more stable A/D conversion
// Start a conversion to measure the INTERNAL reference relative to the DEFAULT (Vcc) reference.
ADCSRA |= _BV( ADSC );
// Wait for it to complete
while (ADCSRA & (1 << ADSC));
// Calculate the power rail voltage (reference voltage) relative to the known voltage
return (InternalReferenceMillivolts * 1024UL) / ADC;
}
Koepel, I'm not sure I understand your point. The input on an analog pin can vary from 0 - 5 volts. The Arduino converts those values into 0-1023 representations of the voltage. And it uses whatever it has determined the 5V Vref value is. I just measured mine at the 5V pin with my multimeter and it was 5.21 volts. So it uses the value of "5.21" to represent a reading value of 1023. I don't care about any 1.1 volt internal references, unless you're suggesting that somehow I can convert the actual reading of that 1.1 volt value and scale it up to 5 volt range?
John, thanks for the response. If it requires all that code I think I'll stick with my multimeter
That actual value can change instantaneously by small amounts. So if you measure it and then measure it and then measure it again, and something on the 5 volt power has changed, then your next reading will also change. It is a no-win proposition.
Paul
Paul, yeah, it continuously varies, but my main concern is just getting in the ballpark. When the actual internal Vref is 5.21 and if I just assume it's the nominal 5V (which I think many do), the results are off by 4 or 5%. But if I measure once and use that value, it generally gives me some very accurate readings that don't vary much. And since we're talking about 1024 values, accuracy of pico-volts isn't really an issue
SO much depends on what you are doing. I recall using the analog value with a keyboard and changing from USB power to internal power changed one of the keyboard values.
Paul
I cringe every time I've seen a video where someone says the equation to convert from 0 - 1023 analogRead() values to actual voltages is the standard:
volts = value * 5.0/1023;
Of course that's virtually NEVER the correct equation. A while back I measured a bunch of USB devices with my multimeter and the "5.0" volts is all over the place.
@mccabejc Do you want to measure the analog input for the range of 0...5V and measure the VCC to determine the actual voltage of the 5V ? So you can do a small correction for the voltage that is read at the analog input ?
The normal way is to use a voltage divider with two resistors and the internal voltage reference.
It is also possible to measure the voltage of VCC by making use of the internal voltage reference. You still have to determine the actual voltage of the internal voltage reference for each individual board. Search for: arduino secret voltmeter
I'm finalizing a C# application that creates an oscilloscope that uses only one analog input from the Arduino. Adding external circuitry really isn't something I want. Like I said, I've monitored the Vref generated by the Arduino when fed from my USB hub, and it always hangs around 5.2 volts, so I use that as the reference voltage to convert the 0 - 1023 values the C# receives from the Arduino. See below. I even calculate the max. volts each scan. So if I'm going to use this app, I just have to remember to hook up the multimeter to see if the default 5.2 volts is still accurate. But like I say it's usually pretty close.
There are 1024 values in a 10 bit number. And 0 is one of them. So the values go from 0 - 1023, with "1023" representing the Vref value.
So assuming the Vref is 5.00 volts (which it isn't), the Arduino will send a value of "1023" when it reads 5.00 volts. Therefore, to convert the 0 - 1023 reading to volts you use 1023, right?
I just hooked up my bench power supply, wrote a quick sketch for my Nano to read A0, and set the power supply at little over 5 volts (5.09) and plugged it into A0. The the largest value I could get from the Arduino was 1023. I hope I didn't fry my Nano
Check out that link, I think someone else above was trying to explain the same thing they talk about in the above link.
Basically the point is that the 1.1v internal reference will be more accurate than your 5v supply. So you measure the more accurate 1.1 with the less accurate 5v. Then you can see the error from 1.1 and assume it's from a difference in the 5v supply, and correct accordingly
Thanks winner10920, but I think if people are considering the assumption that an "accurate" 1.1 volt reference can be translated to a 5 volt reference they need to be very careful.
Consider that 1% of a 1.1 volts reference is 11 mV. But 1% of a 5 volt signal is 50 mV. If you consider digits and accuracy it becomes clear that your 1.1 V reference has to be about 5x more accurate than the 5 volt reference in order to reflect changes in the 5V reference accurately.
I think it's far better to actually measure, not speculate. And that's why I hook up a very accurate multimeter to measure the 5V Vref and use that. And the resulting measurements from the Arduino match the multimeter very well.
Every voltmeter (lab bench, multimeter, Arduino) can only measure compared to a reference voltage.
The arduino can use one of three references:
Its Vcc power (~5v or 3.3V) = can vary from day to day, with changes in load etc
the Internal 1.1V = is not precise but stable. Once you know what it is, you can program a gain parameter to compensate for its inaccuracy.
Or if you use @johnwasser's code and know the 5V Vcc voltage, you can deduce the value of the 1.1V ref. Now you can use the Vcc as a reference (so you can measure up to~5V) and compensate for its current value by measuring the (now known) 1.1V ref.
Purchase an accurate and stable external reference.