Accuracy of an Arduino voltmeter

Hi everyone!

I know there are probably quite a lot of forum posts about this topic, but I'm still new to Arduino and somehow not able to figure all the things out. So here is my problem:

I'm using an Arduino Nano to measure the voltage of a capacitor from another circuit and then sending it via bluetooth to a PC/phone. The arduino is run by an 7.4V battery pack through the Vin pin. Since the voltage range is to be expected around 0-5V and I don't need the measurements to be super exact, I thought I can just wire the capacitor up to an AnalogIn Pin on the Arduino (and of course connect the grounds).
When testing this with an regulated power supply and an actual precision Voltmeter I noticed a difference between the two measurements which I just calibrated with a factor in the Arduino code. The effective range of my arduino is limited to 0-4.7V because of that, but it's still fine for my application.

Now I've read a few other forum posts which raised some questions:

  • The accuracy of the ADC in the Arduino is around +/- 2*LSB, which means 9.8mV. But this should be more or less constant and I should be able to correct it with an offset in the arduino code, isn't it?
  • The internal reference voltage is instable/is dependent on the VCC voltage. If I understood correctly Vcc is the digital supply voltage and thus the voltage the Arduino with. So if I connect my battery to the Vin pin it gets regulated down to 5V by the internal voltage regulator, which again is the Vcc the Arduino uses, correct? Is the internal voltage regulator the reason for the instability of the Vcc and thus the reference voltage and/or does the voltage of my battery affect it? Would it be more stable if I used an external voltage regulator and the 5V pin on the Arduino?
  • Often an external precision voltage reference is suggested for people who use an Arduino as a voltmeter. Does anybody know how much the instability of the internal reference usually affects the accuracy of the measurement? Is it also a few mV like the accuracy of the ADC or can it be way more?

Thanks in advance for every answer!

If you have calculated a correction factor to calibrate the ADC, then the result is more accurate than the manufacturer's "absolute accuracy" specification, which you can easily verify by making measurements against other standards.

If you want stable, accurate absolute measurements, you need an accurate, stable external voltage reference applied to AREF. Observe the precautions when connecting and using it in a program.

Thanks for your answer!

Okay, that is what I was going for. What still confuses me though, is the absolute accuracy of the ADC is stated as 9.8mV but my measurements were up to 400mV off. That is quite the difference and makes me wonder where that comes from.

If someone has some further detail into that I would be glad to hear!

A 400 mV error indicates that you have not calibrated the ADC correctly or are using an unstable voltage reference. Good tutorial here.

Please describe your measurement setup (post a wiring diagram) and calibration procedure (post code, using code tags).

I have calibrated my NANO this way to measure an unknown DC voltage (range: 0 to 5V) --

1. NANO is powered by USB.

2. Measure DC Voltage by DVM at 5V point of NANO, and it is found as 4.82V.

3. Measure DC Voltage by DVM at 3V3 point of NANO, and it is found as 3.25V.

4. I have executed the following sketch to get the ADC value by --
(a) Connecting 4.82V at analog channel 0 (A0). The ADC value is 1023. This is point A(4.82, 1023).
(b) Connecting 3.25V at analog channel 0 (A0). The ADC value is 688. This is point B(3.25, 688).
(c) The unknown point is C(v, x) = C(unknown DC voltage, ADC value).

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

void loop()
{
  int x = analogRead(A0);
  Serial.print(highByte(x), HEX);
  Serial.println(lowByte(x), HEX);
  Serial.println(x, DEC);
  delay(2000);
}

5. From the readings of Step-4, I have found the following equation for v(unknown voltage) in terms of x(the ADC value) --

v = 0.0047*x + 0.0256.

6. The execution of the following sketch shows the unknown voltage on the Serial Monitor at 2-sec interval.

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

void loop()
{
  float v = (float) 0.0047 * analogRead(A0) + 0.0256;
  Serial.println(v, 2);
  delay(2000);
}

7. Testing Procedures
(a) Upload the sketch of Step-6 into NANO.
(b) Connect 4.82V point (5V -point of NANO) at Ch-A0; the Serial Monitor shows: 4.83V
(c) Connect 3.25V point (3V3-point of NANO) at Ch-A0; the Serial Monitor shows: 3.26V

Thank you for your replies!

Sorry for not responding for a while, I did some more tests with the Arduino and somehow forgot about this.

In the newer tests the accuracy of the Arduino was much higher and always very close to what my digital voltmeter was showing. Also I could measure the whole range from 0-5V. When thinking about what could have changed since the first test, I remembered that I was powering the Arduino via USB the first time and with the 7.4V battery pack in the second test.

So as GolamMostafa suggested I measured the voltages at the 5V, 3,3V and the AREF pin with my digital Voltmeter and there were interesting results: While powering the Arduino with the battery pack the voltage at the 5V pin was stable at 5.028V, at the AREF at 5.0255V and at the 3.3V pin at 3.2786V. While powering the Arduino through USB the voltages at the 5V and AREF pin were fluctuating between 4.6655 and 4.6681V and at the 3.3V pin stable at 3.2752V. This matches with my first measurement in which I was only able to measure up to 4.7V.

So it seems that the reference (and internal?) voltage is unstable and lower when powering the Arduino via USB, while connecting a battery pack through the Vin pin results in a more stable voltage and the full 5V.

I was able to calculate a new (much lower) correction factor and the Arduino now measures reliably voltages between 0V and 5V. Thank you all!

Small Arduino boards, like the Nano, have a simple USB backflow protection diode instead of a p-channel mosfet (Uno, Mega). That schottky diode causes the ~0.4volt drop of the USB supply, and a less 'solid' supply voltage with load changes (flashing LEDs, etc.).

If you use an Arduino as a voltmeter, it usually is better to use the internal 1.1volt Aref, and drop the 'voltage to measure' to <=1volt with a voltage divider.

Another way is to use the 3.3volt supply as reference, by linking the 3.3volt pin to the Aref pin.
MUST set Aref to EXTERNAL if you do so. Leaving it on default will damage the Aref circuit.

The 3.3volt supply of a Nano is not as good as on the bigger boards, because a Nano shares it with the USB<>Serial chip. The Uno/Mega has an independent voltage regulator.
Leo..

The Nano 3.3V supply comes from the FTDI chip, and is limited to 50mA.
Clones might have a 150mA regulator and the Chinese USB chip.

Nano clones also get the 3.3volt from the USB<>Serial chip (pin-4 of the CH340 chip),
but that voltage already starts to collapse at about 30mA (measured).
AFAIK only the bigger boards (Uno, Mega) have a dedicated 5-pin 150mA voltage regulator.
Leo..