Arduino ADC:Everything you Must
Know about the Built-In ADC. How does the Arduino
ADC work? Should you use 1023 or 1024 in your calculation? Find out
the sample rate and how to use the reference.
Find out why your calculated value is wrong (divide by 1023 or 1024).
Find out the sample rate for the Arduino.
Exactly how does a successive approximation ADC work?
Find out what the Arduino voltage reference voltage is for.
The ADC or Analogue to Digital Converter takes an input
voltage and converts it into a digital value. With the standard setup
you can measure a voltage between 0V and 5V with a resolution of 4.9mV
so you can get a lot of detail when measuring
Arduino Analog Pins
There are six pins on the Arduino Uno (shown below A0 ~ A5) that
can be selected for an ADC measurement; A multiplexor feeds one of the six
analogue input pins into the ADC.
To read an analogue voltage from pin A4 you use the following code and function:
val = analogRead(A4);
Setting of the multiplexor is done in that function for
In the above diagram you would read an analogue value from 2 pins up on the left with analogRead(A4).
 for 4V operation and 200kHz ADC sampling clock.  for 5V operation and 125kHz ADC sampling clock (See below).
Arduino ADC size
The Arduino ADC has a 10 bit converter, and that means there are
1024 distinct values that can be returned as a result from the ADC:
since pow(2,10) = 2^10 = 1024
Divide by 1023 or 1024?
There is always some confusion about whether to divide by 1024 or 1023
to get the voltage value for each bit.
However the ATMega328P datasheet gives the following formula:
re arranging that gives:
Vin = (Vref/1024)*ADC
Arduino ADC resolution at 5V
So for Vref=5V, an ADC value of 1 would result in a Voltage step of
4.88mV - the value of voltage for one LSB - this is the Arduino ADC
resolution for a 5V Vref.
Note however that the maximum ADC value is 1023 so the maximum ADC value that can ever be reported is:
1023 * (5/1024) = 4.9951V
Warning: If you see the following type of equation Aout = 612 * (5 V / 1023)
-It is wrong! it should be Aout = 612 * (5 V / 1024).
The reason that 1023 is used incorrectly is gives values that feel
right i.e. 512 gives 2.5V and 1023 gives 5V (Both are wrong).
As it states in the datasheet:
"0x000 represents analog ground, and 0x3FF represents the selected reference voltage minus one
The reason that you will see the wrong equation on the web is so that
the output "feels" right i.e. 1023*(5/1023) = 5.000. This is the wrong
equation to use and means there is an offset added to all values.
How the Arduino ADC works
This ADC is known as a successive approximation ADC and requires several clock cycles to zoom in on the correct ADC output.
The ADC converter compares the input analogue voltage to a portion of
the Vref voltage using a divide by two sequence. The sample and hold
charged to the input voltage and then the input disconnected so that the
same voltage is measured throughout the conversion process.
It first checks whether the input voltage is higher or lower than
half of the Vref voltage, by using a DAC to generate half the reference
voltage. The DAC voltage is the fed into a comparator.
The output of the DAC forms the high bit of the result (stored in a shift
register). If the input voltage is higher then the bit is one, otherwise
the bit zero.
If the input is lower than half of the Vref voltage then control logic generates a
DAC voltage that is 1/4 the reference voltage. The comparison is made
again and this forms the next bit in the ADC output.
The process continues until all the bits are collected.
For the Arudino the conversion process takes 13 cycles of the ADC
clock - which you set using a prescaler in the ADC module. The ADC clock
must be between 50kHz and 200kHz so you choose the prescaler value to
get a valid ADC clock.
The ADC clock prescaler can be set as a 2n division from 2 to 128.
You obviously want the fastest conversion rate for the clock in use so
for a 16MHz system clock you would calculate 16e6/200e3 = 80 so the
closest could be 64.
However 16e6/64 is 250kHz and is too big. Therefore choosing a divisor of 128 must be used so the ADC clock will
be 16e6/128 = 125kHz.
A conversion will take 13 ADC clock cycles :
13 * 1.0/(125e3) = 104us
Check that these settings are used in the Arduino
Source code! - I have not - they are extremely likely though.
Uno sampling rate (16MHz crystal)
1.0 / ( 13 * 1.0/125e3) = 9615Hz
Actually, reading the Arduino reference page it says the sample rate is
about 10kHz so this calculation matches that information.
So the maximum Arduino ADC sampling rate is:
The above rate is the
maximum sampling rate but to reproduce a sinewave requires double the
sampling rate (Nyquist theorem). Another way of looking at it is that
the bandwidth of the signal you can safely reproduce is half the
Warning: 9.615kHz the sample rate, the bandwidth is half (4.8kHz).
However this is only dealing with sinewaves and not "real signals".
You cannot reproduce a square wave at 4.8kHz because the edges of the
signal are at a far higher frequency (Fourier analysis) - in fact you
would end up with a 4.8kHz sine wave if trying to reproduce a 4.8kHz
square wave by converting it with and ADC with a 9.615kHz ADC clock.
This is why digital oscilloscopes have sample rates about 10 times
higher than the maximum desired operational frequency.
Changing the Arduino Sampling Rate
ADC clock calculations
If you set the system clock to 20MHz you get 20e6/128 = 156250.0 - for a bit faster conversion.
Interestingly if you go the other way as a design decision you want
the fastest ADC clock rate of 200kHz, then you have to ask the question:
"What crystal clock results in a 200kHz rate after ADC prescaling?" i.e.
So reducing the Xtal clock allows a faster conversion rate of 200kHz!
Giving a max samping rate of:
1.0 / ( 13 * 1.0/200e3) = 15384Hz (THIS IS FOR A 12.8MHz XTAL)
...and yes you can get crystals made to your spec! - but you'll probably
use a 12MHz crystal, as its easier to get, so the sample rate above
will be a bit lower.
Example operation of 4bit ADC
This is a diagram of the action or the successive approximation ADC
using Vref as 5V. Here a 4 bit ADC is shown but the principle is the
same however many bits are used.
4 bit ADC Operation
Initially the input voltage (Vin) is greater than the starting value of
the DAC voltage (set by initial DAC value of B1000) so this bit is kept.
In the next processing period the DAC output is set to B1100 but in
this case the DAC voltage becomes greater than Vin (and that bit is
The next two DAC values are kept because the DAC voltage is always
lower than Vin and you end up with an ADC output value of B1011 - the
ADC successively approaches the final value.
The final output DAC voltage is 2.5 + 0.625 + 0.3125 = 3.4375V
The advantage of the successive approximation ADC is that it is
deterministic i.e. it always takes the same amount of time. Consider
using a binary counter as the input to the DAC that always started at
zero and counted up. For a low Vin it would take a few counts to find
the value and for a high Vin it would take lots of counts (possibly 255
cycles for an 8 bit DAC) i.e. it would take different times depending on
the input voltage!
Note: As the number of bits in the ADC increases so does the acquisition time.
Arduino Uno ADC resolution
As we saw earlier the resolution of the ADC, when Vref=5V is 4.88mV per step.
The Arduino analogRead resolution which is the same as the resolution of the ADC is governed by two things
The ADC size - 10bits for the Uno.
The ADC reference voltage - You can feed in your own voltage as well or use the internal reference.
Note: The arduino function analogReadResoution() allows the analogRead() function to return a different number of bits (The number of bits depends on your Arduino chip).
Some of the Arduinos e.g. DUE have 12 bit ADCs built in, so returning
10bits will keep the code in these boards compatible with other Arduino
boards that only have a 10 bit ADC. This is the default operation - to get 12 bits you will need to use analogReadResoution(12).
Using an ADC with more bits makes the the minimum step size (LSB)
smaller to give higher resolution. The Arduino Uno is fixed at 10 bits
but there is a way of increasing the number of bits through a clever process of
aceraging and decimation; See this
page: Arduino ADC oversampling.
ADC Reference voltage
You can use three sources of ADC reference voltage:
The power supply.
The internal reference diode (nominally 1.1V).
An external voltage reference.
The reference voltage is the full-scale
voltage applied to the ADC converter operating as described above.
Say you changed the Vref value to 1V then the minimum LSB you could detect would be 1/1024 or
TIP: You can select the internal 1.1V reference and this will give a
step size of about 0.1V: Exact calculation is 1.1/1024 = 0.00107V
~0.11mV per step . This does mean the ADC can't read voltages above 1.1V
- they will just return 1023.
Warning: Never turn on the internal reference while applying an external voltage to the reference pin.
Before turning on the internal reference check that there is no external
voltage applied. If there is it is likely you will blow something up
(see the ADC block diagram below).
Reason for the smoke problem
The problem is that you might create a direct path from AREF to AVCC,
or the internal reference, by turning on the FET while there is a
voltage at AREF. To avoid this problem don't fiddle with the Analogue reference if there is any voltage applied to Aref.
The 'Internal 1V1 reference' voltage and the AVCC voltage are
controlled though a MUX, and then through a MOSFET, and are then
connected to AREF. If an external voltage is applied and the reference
or AVCC selected then the MOSFET (and MUX) offers a path (its resistance
Rds) to the voltage difference = heat and possible smoke!
The default state of the ADMUX bits REFS1 and REFS0 is zero, meaning
that AREF and "Internal Vref" are turned off (from datasheet). So from
power up the reference source is from the AREF pin i.e. it is "safe".
What is the default reference voltage?
If you examine the code in the example below you will see that the
analogue reference AREF is not mentioned at all. For the ADC to measure
voltage it must have a reference!
In fact if you use the analogread() function then the it will
activate the selected reference source. The default reference source is
AVCC (the power supply).
When writing Arduino code this makes it easy to use the analogue read
function as the default state is to use the power supply for the
This presents a problem if you want to use the AREF input pin as the
reference source. The solution is always, at the start of code - in the
setup() function - to select the reference source before any analogue
read function is used.
Setting the Arduino reference source
The Arduino function to use the internal 1V1 reference is:
The Arduino function to use the voltage at the AREF pin as the reference is:
This function sets the ADC to use the Supply (VCC) as the reference.
NOTE: The reference is updated just during analogread(<n>).
NOTE: Some boards have other
internal voltage reference levels available. See the Arduino page on
analogReference for more information.
You can find out much more about the internal (1V1) reference here.
Example ADC Use
Connect a 10k potentiometer with wiper (middle) to pin A0 and one end
to 5V, and the other end to Ground. This example simply uses the arduino analog read function analogRead() to read data from the specified analogue pin.
Start the serial monitor, and observe the led period. The on-off time
is twice the value of the analogue value so it varies from 2s to ~0.
Demonstrates analog input by reading an analog sensor on analog pin 0 and
turning on and off a light emitting diode(LED) connected to digital pin 13.
The amount of time the LED will be on and off depends on the value obtained
center pin of the potentiometer to the analog input 0
one side pin (either one) to ground
the other side pin to +5V
anode (long leg) attached to digital output 13
cathode (short leg) attached to ground
- Note: because most Arduinos have a built-in LED attached to pin 13 on the
board, the LED is optional.
created by David Cuartielles
modified 30 Aug 2011
By Tom Igoe
This example code is in the public domain.
intsensorPin=A0;// select the input pin for the potentiometer
intledPin=13;// select the pin for the LED
intsensorValue=0;// variable to store the value coming from the sensor
// declare the ledPin as an OUTPUT:
// read the value from the sensor:
// turn the ledPin on
// stop the program for <sensorValue> milliseconds:
// turn the ledPin off:
// stop the program for for <sensorValue> milliseconds:
Other Uses for Arduino ADC pins
You can use an ADC pin as an:
A digital input,
A digital output.
Note: Other functions can be shared by a pins e.g. A5 is also SCL.
The internal structure of an ADC input pin allows the pin to be multi
functional. Some people get confused using an ADC pin as a digital
input or output but it is perfectly valid to do so (as long as it has
digital logic driving the input signal).
The only caution on using ADC pin as a digital input is that if you
have designed the external circuit for measuring an analogue voltage,
that voltage could cause the digital input to overload.
In CMOS circuits there are two FETS, a high fet and a low fet,
connected to the a common output - their inputs are also connected.
These act as current source and sinks - to allow a large fan out. In
normal use the logic driving these inputs is logic high or low. If you
drive them at the mid range voltage (think analogue input at Vcc/s) then
you are turning both on at the same time. Therefore lots of current
To avoid this situation for a "digital only" input you tie the input
to the high voltage using a pull-up, and of course the Arduino has
internal pull-ups provided for just this operation.
The reason for the pull-up is that bias voltages in the CMOS circuit
(FET circuit) will set the input to some floating value which could turn
on both FETs. So to be certain this does not happen, enable the pull-up
on each digital input pin.
You can see that if external analogue circuitry drives the inputs to
mid range, there will be a problem if you set the pin to digital input.
So avoid doing this!