What if you need to know the voltage value of your supply?
Ok you say. Fine, I'll just measure it with the ADC.
The trouble is you get the same reading of 1023 whatever the supply is set to!
The problem is that the supply voltage defines the ADC maximum
voltage so it is useless. Even using a divider is no good as the ADC
is ratiometric - and gives the same value.
There are two things you can do:
1. Use a voltage divider on the supply and feed in an accurate external voltage to Aref.
2. Use the internal bandgap 1V1 voltage reference.
The internal bandgap is not without a problem - its initial accuracy is 10%!
Find out here how to calibrate it, and use it to measure your power supply voltage.
The Arduino Voltage Reference (1.1V) is built into some Arduino
microcontrollers. The Uno and the Nano both have one, and quite a few of
the other Arduinos have them.
Shows you how to measure the "real" value of Vcc (using the reference).
Attempts to quantify the internal voltage reference (how good is it?).
The second item above is interesting as it uses the internal
reference to "calibrate" the supply voltage so you can measure voltages
using the whole supply range not just to 1V1.
You usually set up the Arduino ADC using the microcontroller power
supply as a voltage reference (since it is easy! and it is the default
mode of Arduino software). The trouble with that is the power supply
chip will then define the accuracy of your measurement i.e. you won't have a clue if it is accurate or stable with temperature.
Note: Although the Internal Arduino Voltage Reference is stable with
temperature and voltage, its initial value varies between chips
(probably due to differences in chip manufacture). it needs calibration.
The Arduino voltage reference is useful when you don't want to go to the trouble of adding an
chip to figure out voltages and need a more stable reference than Vcc or where the supply voltage changes.
For instance the Arduino Uno/Nano can operate from 1V8 to 5V5 and using two AA
cells would allow operation (but only if you set the clock to 4MHz - see
the datasheet section 29.3 "Speed Grades"). You can use the internal voltage reference to monitor
the state of the battery - with no extra components.
Bandgap Voltage Reference
The type of reference in the ATMega328P is a bandgap type. This uses
two elements, one with the negative temperature coefficient and
one with a positive temperature coefficient which cancel out
giving you ultra precise voltage readings in the Arduino, the circuit is designed to be stable against changes in
temperature and supply voltage.
This type of circuit layout is used in state of the art references e.g. MAX6143.
However, in the ATMega328 and similar, the process to control the layout
of the chip on silicon is not as well defined and does not use laser
trimming, hence the poor initial accuracy of the Arduino voltage
You can find out how to eliminate this offset later in this page.
Note: If you use an external reference the ADC
measurement will be more accurate since you control the chip specification.
However, remember the
internal ADC in the Arduino is not too accurate anyway (see ATMega328 datasheet:Absolute
accuracy 2LSB (including INL, DNL, quantization, gain and offset errors).
Warning: Never use an external
voltage reference and at the same time enable the internal reference - something will break!
Uses for the Arduino Voltage Reference
The Arduino voltage reference can be used in one of five different ways:
For brown-out detection (See datasheet to enable).
As a measurement value in the ADC (fed in to one of the inputs).
As the reference for ADC measurements.
As an input to the comparator.
Temperature measurement (The ADC must use the internal reference).
Brown out detection
Brown-out detection allows the processor to identify when the supply
voltage has dipped below a threshold but has not completely gone to
zero. This is used to flag to the processor that memory may have been
written badly. It just provides an extra layer of reliability to an
An input to the ADC
Measuring the reference at an ADC input would allow calibration of a
different reference source e.g. the supply (see here) or as a crude comparison to
other ADC inputs (unless you calibrate the reference first as shown in
this page - in which case it could be quite accurate (~1%)).
Using the Arduino voltage reference as you would expect it to be used!
TIP: Using the 1V1 reference means the 10 bit ADC has an LSB value
of ~1mV (1.074mV/LSB). However, you can then only measure voltages up to 1.1V!
Using the voltage reference allows crude comparison i.e you can only
compare any input voltage to 1V1. One interesting point is that any of
the ADC inputs can be compared by the comparator - and that is without
using any more external components. See section 23.2 of the datasheet
labelled "Analog Comparator Multiplexed Input".
You could ask the question "Why bother using the comparator when you can
easily calculate the result using the ADC?" The answer is speed.
The comparator can compare two voltages within 100s of nanoseconds
whereas the ADC is a successive approximation type and takes about 13us
to gather the ADC value. This value has to be retrieved by the processor
and then you would compare the value to a limit setting, taking far
Since the Arduino voltage reference is independent of temperature it can
be compared to the output of a temperature dependent circuit - a
circuit inside the chip. This allows you to measure temperature in the
sensing element in the ADC can be set to one of the ADC inputs. The
datasheet states that the temperature coefficient is 1mV/ºC but that
the initial accuracy is ±10ºC due to process variation in chip
manufacture. (See section 24.8 of the datasheet labelled "Temperature
Measurement"). To get an accurate reading requires calibration of this
How to Measure the Supply Voltage
You can operate the microcontroller (ATMega328p - Uno, Nano) from
between 1V8 and 5V5. The
microcontroller can not detect this "real" value of the supply voltage
this unless you use a known reference
voltage to figure it out. This is because the ADC measures everything
relative to a reference i.e. the supply voltage is the reference!
Warning: At VCC=4.5V clock can be 20MHz and at VCC=2.7V the clock speed must be <= 10MHz, and for VCC=1.8V
the clock speed must be <= 4MHz). See section "29.3 Speed Grades"
which shows that the clock frequency must be linearly reduced with
decreasing supply voltage.
This method is a sort-of reverse method of ADC measurement.
Instead of using the voltage reference as a "reference" you use the
supply voltage as the reference and the "Arduino internal voltage
reference" as the quantity to be measured.
Since you know that the bandgap reference is 1.1V then you can figure
out the supply voltage value by doing a simple bit of maths (below).
...to your measured value. The representation of 1.1V is 11000 which
is a fixed decimal point representation where the decimal point is
assumed to be one place to the right. So you can think of 11000
representing the number of 0.1mVs in the actual voltage i.e. 11000 x
0.1e-3 = 1.1V
Using an ADS1115 or good voltmeter will give you enough digits. If
you use a standard DVM then you will only get 3 digits (on a 2 volt range) so set the
last two digits to zero.
uint8_tlow,high;// ADC bytes.
// Default reference value. Set this to your measured reference voltage (or leave as is).
// The value uses an integer fixed point representation
// with the assumed decimal point one place to the right.
Serial.print(F("Not enough digits"));
Serial.print(F("Too many digits"));
Serial.print(F("Ref calibration value: "));Serial.println(arduinoADCcal);
// ADCSRA |= _BV(ADEN); // Enable ADC. Enabled by init() in Arduino code.
ADMUX=_BV(REFS0)|_BV(MUX3)|_BV(MUX2)|_BV(MUX1);// Set VCC ref and band gap as input.
delay(2);// Vref settling time delay
// Throw away 1st result as datasheet says
// After switch, ref may be invalid.
// Datasheet: "24.5.2 ADC Voltage Reference".
ADCSRA|=_BV(ADSC);// Start conversion
while(bit_is_set(ADCSRA,ADSC));// Wait for conversion complete.
ADCSRA|=_BV(ADSC);// Start conversion
while(bit_is_set(ADCSRA,ADSC));// Wait for conversion complete.
// ADCL must be read first, then ADCH, to ensure that the content
// of the Data Registers belongs to the same conversion
// Datasheet Section "24.2 Overview"
low=ADCL;// Read ADCL first which blocks ADCH updates.
high=ADCH;// After reading ADCH both registers can be updated by the chip.
Serial.print(F("ADC value of 1V1 ref: "));Serial.println(ADCValue);
#define BINS 1024L // VCC/1024 is the value of each LSB of the ADC.
// Note +5 = middle of LSB bin
// Calculate Vcc (in mV); 1125300 = 1.1*1024*1000
// Here ccal value is 1.1*10e4 so no need for *1000 and must divide by 10.
// Calculate Vcc (in mV); 1126400 = 1.1*1024*1000
// should be 1024 / ADCValue = 1125300L / ADCValue; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
// internal1.1Ref = 1.1 * Vcc1 (per voltmeter) / Vcc2 (per readVcc() function)
Serial.print(F("Measured (mV) "));Serial.print(res);Serial.println(F(" mV"));}
Arduino Voltage Reference Block Diagrams
Arduino Uno/Nano ADC Mux block diagram
Source: ATMega328P datasheet
Arduino ATtiny85 ADC Mux block diagram
Source: ATtiny85 datasheet
ATTiny85 Internal Voltage Reference
The ATTiny85 voltage reference, which is selectable as either 1V1 or 2.56V, is slightly differently arranged in the ADC. The AREF pin can only be set up as an input (there is no switching FET that connects the internal reference mux to the AREF pin). So you cannot setup the Arduino voltage reference for measurement at the AREF pin.
Therefore you can't calibrate it directly. You would either assume that
it has the stated value or accurately measure the Vcc supply then take
an ADC reading (but remember the ADC has its own errors as well!).
One way that would eliminate ADC errors is to feed in a variable voltage
to an ADC input - which you measure. Then compare it to the reading
from the voltage reference (ADC reading). Once the two readings match
the input voltage would then reveal the true Arduino reference voltage
(of course only to 1LSB accuracy).
To calibrate the reference in an Uno or Nano you just turn on the
reference and measure the voltage at the reference pin. Remember the
only thing on the pin should be a capacitor and no other driving
circuitry (if you want to preserve the chip!).
Warning: Do not connect any other voltage reference to the VREF
pin when switching the Arduino (Uno/Nano) voltage reference on - there is no
protection and you could damage either the external reference or the
internal reference circuit.
Turning on the reference is quite simply using the following Arduino code:
However, you will need to activate the ADC to enable the reference, so a simple read will do.
analogRead(0); // Could be any channel
This is due to the way the "wiring" code is written - the mux registers
and REFS0/1 are only written just before an ADC read command (within the analogRead() function).
For the arduino Mega you can choose between the following:
Place the above code in the setup() part of the Arduino Sketch.
Warning: Ensure NO voltage is applied to the Vref pin before this test.
If you are going to use the internal reference then there should not be
an voltage applied, but if using a circuit from somewhere else
there could be an external reference of voltage divider attached.
TIP: Attach a 100nF capacitor to the Vref pin for noise reduction.
TIP: Use a standard multimeter, or for more digits use
an ADS1115 in differential mode or a Fluke meter (very expensive).
To set the reference back to the supply use:
...again followed by...
analogRead(0); // Could be any channel
Code for analogue operation is found here:
"C:/Program Files (x86)/Arduino/hardware/arduino/avr/cores/arduino/wiring_analog.c"
Definitions (#define ) are here:
C:/Program Files (x86)/Arduino/hardware/arduino/avr/cores/arduino/Arduino.h
The Arduino code above ( for internal reference selection ) will set the
registers as follows (datasheet section: 24.9.1 ADMUX ADC Multiplexer
ADMUX bits 7 and 6 set high (REFS1 and REFS0).
ADMUX bits 3..0 set to B1110.
Note: The data sheet states:
"The first ADC conversion result after switching reference voltage
source may be inaccurate, and the user is advised to discard this
(See datasheet section "24.5.2 ADC Voltage Reference").
So you should throw away the first ADC result.
Arduino Voltage Reference Performance
The information in the datasheet on the Arduino voltage reference states that it has maximum and minimum values of
1.0V ~ 1.2V, and nominally 1V1. Other than this there is no more information at all.
There is no information about repeatability or stability. It suggests that the voltage could vary by ±9% around 1.1V.
So the real question is:
Is the Arduino voltage reference any good at
The specification seems to imply that it might vary ±9% at any time.
In fact this is not true and the voltage reference is far better, and
On this page there are some voltage reference measurements - these
are not exhaustive but will give you a flavour of the bandgap
Arduino voltage reference Questions
Questions asked here are:
How does the reference voltage change with temperature?
How does the reference voltage change with Vcc?
How stable is the reference voltage in general?
Remember these measurements are based on testing a few chips
and one or two sets of measurements. They will therefore give an
impression and not the absolute answer.
Note: All voltage measurements were made using an ADS1115 on a breakout
board. All voltage measurements were made in ADS1115 differential mode.
Temperature measurements were made using an MAX6675 and type J
The initial accuracy is bad at ±9% but calibrating the Arduino voltage reference allows you to eliminate this error.
Note: The MAX6143 has an initial accuracy of 0.05% (180 times better c.f. 9%).
Two boards are measured, the first is s standard Arduino uno board and
the second is an Arduino Nano board. These both use the same processor
Measurements made on different time/days of an Arduino Uno powered from the USB (hub) power supply gave the following results:
Arduino Uno USB Stability Measurements
Arduino Uno (PDIP)
USB (HUB) Power Supply
Voltage (Ambient temp)
% error (5V)
% error (1V1)
4.806V (21ºC) Diff
4.826V (16ºC) Diff
4.862V (22ºC) Diff
4.878V (21ºC) Diff
4.842V (20ºC) Diff
4.809V (19.5ºC) Diff
4.788V (23ºC) Diff
4.866V (23ºC) Diff
4.853V (20ºC) Diff
4.876V (17ºC) Diff
4.860V (18ºC) Diff 24/2/20
Max error change for Vcc = 4.2 - 2.4 = 1.80 %
Max error change for Vref = 0.39 - 0.18 = 0.21%
Measurements made on different time/days of an Arduino Nano powered from a PC USB port gave the following results:
Arduino Nano USB Stability Measurements
Arduino Nano (MSOP)
USB (PC) Power Supply
Voltage (Ambient temp)
% error (5V)
% error (1V1)
4.831V (17ºC) Diff
4.825V (22ºC) Diff
4.851V (21ºC) Diff
4.852V (15ºC) Diff
4.830V (23ºC) Diff
4.833V (20ºC) Diff
4.862V (17ºC) Diff
4.879V (20ºC) Diff 21/2/20
Max error change for Vcc = 3.6 - 2.4 = 1.20 %
Max error change for Vref = 3.00 - 2.69 = 0.31%
The USB voltage varies by 2.4% to 3.6% and this does not have a big
effect on the error variation in the reference (See voltage measurements
Notice how the reference voltage remains constant i.e. has a constant
offset error. Even though the voltage reference starts off from a value of
1.070V it keeps close to that value. This is probably due to the
manufacturing process and seems to remain constant over time.
For the top set of results, the supply is
taken from a USB hub with its own power output while for the bottom it
is a direct PC USB output. The latter seems a little more stable (Nano).
In both cases using the on board internal voltage reference
will give a more consistent result as it will have tighter voltage regulation.
Note: Remember you are either using the 5V USB supply directly (when
working on the bench) or using an external power block. The on board 5V regulator - LD1117AG (same as NCP1117) - has a
tighter error spec (0.1V in 5V = 2%) than USB power (see supply sensitivity measurements below).
Conclusion on Stability
Even though the Arduino voltage reference has an initial offset error
(probably due to the manufacturing process) the stability of the
reference remains very good. with measurements here showing between
0.21% ~ 0.31% change.
Voltage Supply Stability
Using an ATMega382p on a solderless breadboard and connected to a variable supply voltage.
Supply Stability Measurements
% Initial error
5.261V (20ºC) Diff
4.948V (20ºC) Diff
4.389V (20ºC) Diff
4.056V (20ºC) Diff
3.615V (20ºC) Diff
3.370V (20ºC) Diff
2.759V (20ºC) Diff
Note: The reference produced odd values at 2.3V so
they are not included. The reason is that the maximum clock speed
allowed is proportional to the supply voltage - should lower clock speed
to 4MHz for operation at 1V8 (See datasheet section 29.3 Speed Grades -
safe operating area).
The error changes by -1.2mV per Supply volt drop when starting from from 5.26V. This is -.11% per supply volt drop.
The bandgap voltage reference seems quite good, being insensitive to
supply voltage changes. It drops by 1.2mV per supply volt drop starting
at 0.05% error at 5.26V supply. If the supply is held constant then this
offset error can also be eliminated by calibrating the reference.
Using a thermocouple (type J) with the MAX6675 chip and the MSOP Arduino
Nano. Heating the chip for a minute and waiting until the temperature
stabilised. The MAX6675 thermocouple has an offset temperature error but
what we really want is the change in temperature
and how that relates to the reference output. The ambient temperature
is also measured using a different device to give a reference point for
Arduino Nano Temperature Measurements
For the Nano ambient temperature measured by the thermocouple is 24.5ºC
(original thermometer says 23ºC) so quite close. Chip temperature is
Vref is 1.0674V.
Vref is 1.0659kV heated chip to 75ºC
Drop is : -1.5mV
Change over temperature
For a 35ºC temperature change the reference voltage changes by -1.5mV.
roughly -1.5/35 = -0.043mV/ºC. However this is based only on one device
and one measurement!
Change is -0.043mv/ºC
For a temperature increase from 25ºC to 125ºC (100ºC delta) the reference
should drop by 4.28mV. In percentage terms that is (4.28e-3/1.1)*100 =
For a temperature decrease from 25ºC to -40ºC (-65ºC delta) the reference
should increase by 2.79mV. In percentage terms that is (2.79e-3/1.1)*65 =
If you consider a simple transistor that has a -2.1mV/ºC temperature
change then for the same temperature delta you would get a 201mV voltage
change (18.2% change) so the bandgap circuit is doing quite well!
Vref is 1.0665V.Temp 30ºC
Vref is 1.0652kV heated chip to 75ºC
Drop is : -1.3mV - So this is a similar result to the first one.
Vref is 1.0688V.Temp 30ºC
Vref is 1.0683kV heated chip to 75ºC
Drop is : -0.5mV - A little different, but in the same range.
Conclusion on Temperature
The temperature performance is good with only 0.55% reference
change over the full temperature range (estimated from 35ºC to 75ºC
The reference voltage changes by 0.003% per ºC (estimated) [ 0.55%/165 (estimated) ].
Note: The MAX6143 has 1000 times better temperature performance at 3ppm/ºC.
Over the full temperature range (-40ºC to +125ºC) the reference will
change by about 0.55% (0.39% + 0.16%) = 0.55% (from 1V1) which is not too bad.
The voltage reference should change by +2.79mV ~ -4.28mV (from 1V1) over these temperatures.
Conclusions on the Arduino Voltage Reference
The reference can have a large offset (due to the manufacturing process) º9% so its initial accuracy can be bad.
Supply voltage sensitivity: ~-1.2mV per Supply volt drop.
This is ~-.11% per supply volt drop.
Temperature stability: ~0.003% per ºC (estimated)
~0.55% over the full temperature range.
Output voltage stability: ~0.31%
To get the best results from the Arduino voltage reference you should
calibrate it (just measure the voltage reference with a multimeter. This will then eliminate offset voltages due to
manufacturing process and supply volt sensitivity (if the voltage source
remains constant i.e. supplied through a regulator).
This will then give a stability of 0.55+0.31 = ~0.86%.
Remember this is an estimate based on very few samples, so your
results may vary, but it does show that the reference can be made more
stable if calibrated. It also shows that the Arduino voltage reference
may be more useful than you imagined.