Arduino’s analog-to-digital converter: how it works


Think of any number between 0 and 255 and I can work it out in eight attempts or less. If you’re a high-school maths teacher, it’s the sort of nerdy game you can use to teach students binary maths. In the world of electrical engineering, it’s an analogy to the process that goes on inside a typical analog-to-digital converter.

Analog-to-digital converters are everywhere — every smartphone, tablet, notebook and PC has at least one because they all convert audio (voice or music) into digital data. But audio is just the tip of the iceberg when it comes to analog-to-digital converter applications. Digital storage oscilloscopes (DSOs) turn analog voltages into digital data displayed on an LCD panel in real time; electronic thermometers turn analog temperature readings into digital data shown on 7-segment displays; digital cameras use ADCs to turn light into digital images; CPUs use them to measure core temperature etc. The real world is analog — and analog-to-digital converters are the link between the real world and our digital approximation of it.


Digital Storage Oscilloscopes use ADCs by the bucket — this one from Hewlett-Packard spinoff, Agilent.

Arduino’s analog-to-digital converter

Every microcontroller chip worth its silicon comes with at least one analog-to-digital converter and Arduino is no different. But at this point, we need to get geeky and talk about the specific microcontroller chip rather than using the generic Arduino term. The Arduino Uno R3 board we’ve used in this series is powered by Atmel’s ATMEGA328P 16MHz/8-bit microcontroller chip. You can download the Atmel 8-bit Microcontroller datasheet from the Atmel web site and I recommend you do — if you ever want to do anything complex with an Arduino, getting to know this document is key.


The 10-bit ADC inside Atmel’s ATMEGA328P microcontroller.

The Arduino’s implementation of the ATMEGA328P chip has six analog inputs that appear as A0 to A5 on the Arduino shield header. However, the chip only comes with a single 10-bit analog-to-digital converter (ADC). So how does six go into one? It happens through a device called a multiplexer — similar to how six trains can use the same main railway line, the six analog inputs are routed to the analog-to-digital converter through this multiplexer, switching each input automatically to the analog-to-digital converter as required by our program or sketch. It means that the ATMEGA328P cannot take more than one analog measurement at once — something to remember.


The Atmel ATMEGA328P microcontroller found in every Arduino Uno board.

Analog-to-digital converter techniques

But once the analog input is routed to the analog-to-digital converter, what happens next? There are a number of different techniques engineers can use to build an analog-to-digital converter. The simplest and least efficient is the ‘ramp ADC’. Here’s how it works — the analog input is fed into what’s called a ‘sample-and-hold comparator’ while the outputs of a binary counter are fed into a digital-to-analog converter (DAC), whose output is fed back into the comparator. A comparator is a simple circuit element that compares two analog inputs — if one input designated the ‘non-inverting’ input has a higher voltage than the other ‘inverting’ input, the output is digital 1, otherwise, it’s digital 0. It’s the electronic equivalent of an ‘if..then..else’ command in a programming language. IFTTT ( is a simpler example.

The binary counter increments on each clock cycle until the DAC voltage is greater than the analog input, triggering the comparator to stop the clock and the binary counter now holds the digital conversion value. The problem with ramp ADCs, however, is they can take many clock cycles to complete that conversion — imagine a 16-bit counter having to reach 65,535 to finish a conversion. That’s 65,535 clock cycles spent.

The other end of the extreme is the ‘flash ADC’ — no matter what the bit size, it theoretically takes just one clock cycle to convert. Instead of using a binary counter, a flash ADC uses a series of comparators that all look at the same analog input, each one comparing the input to a slightly different voltage through what’s called a ‘linear voltage ladder’. The comparator outputs are fed into digital logic elements to create the digital conversion number instantly. The problem is that even with just an 8-bit ADC, you need 255 comparators; a 16-bit ADC needs 65,535 comparators — the precision required makes these expensive.

Successive Approximation

The compromise solution is the ‘successive approximation ADC’ (SA-ADC) — it’s much faster than the ramp ADC but costs only a fraction of a flash ADC.

This is where our nerdy numbers game comes in. Grab a piece of paper and write down a random integer (whole number) between 0 and 255 at the top. Let’s say ‘177’ for example. As the name suggests, the SA-ADC works out the digital equivalent of the analog input through a series of successive approximations, each one getting closer to the right answer.

Now 0 to 255 is the number range of eight binary bits, so this is how an 8-bit SA-ADC works. Just as a refresher, the most significant bit (MSB) counts 128, the next bit counts 64, the next 32 and so on until you get to the least significant bit (LSB) which counts one.

We start off by checking if our number (representing our analog input voltage) is greater or less than the MSB, which is 128, or 27. Write 128 on the new line. If the number is greater than 128, write ‘1’ in a new column; if not, write ‘0’. Since 177 is greater than 128, write ‘1’. That’s our first approximation — it’s obviously pretty rough, but now we refine it by coming down to the next bit, 26 or 64. Since we know the number is between 128 and 255, we now add 64 to the 128 and check to see if the number is greater or less than 192 (128+64). Write ‘64’ on a new line and since our guess number is less than 192, we write ‘0’ next to it.

Now we go another bit lower — 25 or 32 — and do the same thing: write ‘32’ on a new line, but this time we’re comparing our guess number with 160 (128+32) because we know it’s less than 192 (128+64). Since 177 is greater than 160, we write ‘1’ next to our ‘32’.

You can see this step-by-step process in the table. What you end up with is a series of 1s and 0s and reading from top down, the series of numbers is the digital conversion binary number. So ultimately, we can guess (count) any number between 0 and 255 in at eight attempts (bits). Each bit nominally takes one clock cycle.

Successive Approximation Example


Guess any integer between 0 and 255 inside eight attempts through successive approximation.


The SA-ADC inside the ATMEGA328P is a 10-bit precision type and compares the analog input voltage to a reference voltage. It runs through these successive-approximation steps to arrive at a 10-bit (1024) number that represents the analog input. Look at the Arduino Uno board and you’ll see a pin labelled ‘AREF’ — this is the analog reference voltage.


The Arduino Uno R3 has an AREF output top-left and six analog inputs bottom-right.

Practical Arduino analog-to-digital converter

So that’s the theory — how does it work in practice in an Arduino? The ATMEGA328P’s 10-bit ADC has a small overhead and takes 13 clock cycles to complete an A-D conversion. However, the ADC’s clock input isn’t taken directly from the 16MHz controller clock, but instead, comes off what’s known as a ‘prescaler’ or divider. By default, this prescaler is set to 128, making the clock input into the ADC 16MHz/128 or 125kHz (0.125MHz).


The prescaler defines the ADC sample rate by dividing the Arduino clock.

Since it takes 13 clock cycles for the analog-to-digital converter to complete a conversion, the actual sample rate ends up being 125kHz/13 or approximately 9.6kHz. This sample rate is the same as you’ll probably know from audio, where CDs have a 44.1kHz sample rate at 16-bit depth in stereo (two channels). So just from that info, we know the ATMEGA328P’s analog-to-digital converter isn’t quick. If you were thinking of creating a 10-bit audio recorder from an Arduino Uno R3, the Nyquist Theorem says that at a 9.6kHz sampling rate, the best audio bandwidth we can possibly capture is 4.8kHz — about telephone quality.

Changing the prescaler

You can increase the sample rate proportionally by overclocking the Arduino’s 16MHz clock, but that’s not easy on a prebuilt board. However, what isn’t so commonly known — unless you read the ATMEGA328P datasheet — is that the prescaler is adjustable. Most microcontrollers have two programming levels — the standard high-level/C-language command-based option and a lower-level control register level.


The ADC Control and Status Register A sets the ADC prescaler.

One of those registers accessible within the Arduino IDE is called ADCSRA (ADC Control and Status Register A). The first three bits of that register (ADPS2..ADPS0) set the prescaler divider. By default, those bits are set to ‘1’ (111), defined as divide-by-128. But by lowering the prescaler set, you increase the clock speed to the analog-to-digital converter and increase the sample rate. If we set ADPS2..ADPS0 as ‘110’, the prescaler is set to 64, ‘101’ sets it to 32 and so on down to ‘001’ dropping the prescaler to just two.

ATMEGA328P ADC Prescaler settings


NOTE: () indicates not for practical use, see text.


The downside

In theory, a prescaler of two would give us an 8MHz ADC clock and a sample rate of 615kHz. If only. The problem is, the analog-to-digital converter can only go so fast and the faster you push it, the less accurate it becomes. Chipmaker Atmel says that the analog-to-digital converter needs a clock frequency of 50 to 200kHz to get maximum resolution, but “if a lower resolution than 10-bits is needed, the input clock frequency to the analog-to-digital converter can be higher than 200kHz to get a higher sample rate” (datasheet page 245). Through experimentation, it’s been found that pushing the analog-to-digital converter clock to 1MHz still delivers near-to 8-bit accuracy, which means that the eight MSBs still deliver a fairly accurate result, while the two LSBs are rubbish.

An 8-bit ADC isn’t to be sneezed at and with a 1MHz clock, we now get a sample rate peak of 1MHz/13 or approximately 77kHz — that’s much better than the default 9.6kHz and certainly far more useable for audio applications. Because the ATMEGA328P is an 8-bit controller and the ADC is 10-bit, the ADC result is split into two 8-bit registers — ADCH (two MSBs) and ADCL (bottom 8 bits). However, with some extra trickery, you can swap the bits around so that the eight MSBs are loaded into ADCH, quickly read the register from your sketch and manipulate the data more easily.

What can you do with it?

So what’s the point of all this? What can you do with the analog-to-digital converter? If you’ve been following our Arduino series, you may remember we did weatherstation projects using the DHT11 temperature/humidity sensor. That sensor performs its own analog-to-digital converter function (of sorts) and spits out a time-proportional result. Using an electrical component called a ‘thermistor’ (a resistor that changes its resistance proportionally to temperature), you can capture your own readings using the controller’s analog-to-digital converter. You can capture light readings from a light-dependent resistor (LDR), which changes its resistance proportionally to light. Digital light-meters used by cricket umpires feature ADCs doing a similar job.


A thermistor changes resistance on temperature.

Coming from an electronics background, my interest in ADCs has been peaked over the last couple of months as we’ve looked at TFT LCD shields with the possibility of building a digital storage oscilloscope (DSO). An oscilloscope is the most useful piece test equipment an electronics engineer can have — it visualises voltage signals, allowing you to see in real-time what’s going on inside a circuit. If you’ve been watching the Ashes cricket this summer, Snicko is an oscilloscope display of audio captured from the stump microphone.


Cricket’s Snicko is an oscilloscope view of stump microphone audio.

More to come

Good DSOs typically have a bandwidth of at least 50MHz. While Nyquist says you only need to sample at twice your desired frequency bandwidth to capture it accurately, that’s just to capture it — not display it. For DSOs, the rough rule of thumb is you need a sample rate ten times your input bandwidth to be able to display it and see more than just a couple of ‘blips’ on the screen. That’s why ADCs exist that capture in megasamples and gigasamples per second — beyond 1,000,000,000 samples per second (1Gsps) — which is a long way from Arduino’s 77,000.

But that doesn’t mean the Arduino Uno’s ADC isn’t useful and beginning next month, we’re going to start putting some of this theory into practice and use the ADC in real applications — showing you how to program it, how to adjust the prescaler and do useful work with its results.


This phone-sized four-channel DSO uses an ARM processor with built-in ADC.

  • Anon

    Absolutely loved the way you explained it. So easy to understand.

  • Abasourdix

    Thank you very much for this GREAT article.

    Any plans for a follow up? It mentions more to come…
    “But that doesn’t mean the Arduino Uno’s ADC isn’t useful and beginning next month, we’re going to start putting some of this theory into practice and use the ADC in real applications — showing you how to program it, how to adjust the prescaler and do useful work with its results.”
    …but I was unable to find it :(


    • Abasourdix, what you’re looking for is my ‘digital audio recorder’ story, elsewhere on this site (just do a search here – unfortunately, I can’t add URLs). That’s what you’re looking for.

      • Abasourdix

        Found it! Thank you for your quick and helpful response :)

  • Sharifu Rajabu

    Hi? What if I need a sample rate of 1khz is it possible to get it?

    • Not through the ADCSRA register – what you’re better off doing is setting up the ADC for one-shot mode (it takes one sample and stops), setting it to run as fast as your precision requirements allow (77kHz sample rate for 8-bit accuracy for example), then setting up a timer to fire every one millisecond and using that to grab a sample. That will give you a sample rate of 1kHz.

      • Sharifu Rajabu

        Sorry can you explain a little bit more if possible with example

  • White Rabbit

    Great article! Where are the promised follow-ups about the ADC? Please write more!

    • Search for the Digital Audio Recorder project on this site.

  • White Rabbit

    Also, to measure battery voltage using a multi-megaohm voltage divider (to minimize leakage current through the voltage divider), there’s a concern that the ADC may not have enough time to charge its capacitors to take an accurate reading because of the high resistance values. Would taking the voltage measurements in “one shot” mode solve that problem, or would it still be insufficient time because of the way the ADC works? If that doesn’t work, what would?

    • Well, for starters, I wouldn’t bother measuring battery voltage with a multi-megaohm anything. It’s pointless. The open-circuit battery voltage tells you nothing about the battery capacity.
      Sure, you may have a specific reason for doing so (such as the battery already has a decent load on it at the time of measuring) and that’s obviously fine. But if you’re trying to measure battery voltage and you have nothing else loading the battery than a few megaohms, whatever value you read will be useless.
      You need to measure the voltage under-load to get a more accurate guide to how the battery is fairing – and in that situation, using something in the tens-of-kilohoms (if we’re talking about anything beyond a coin battery) won’t do any harm.
      As a battery weakens, it’s internal resistance goes up – but not to a few megaohms, which will always swamp a battery’s internal resistance (in terms of a voltage divider).

  • kerry

    maybe a dumb question, but is the reference voltage always 255?

    • No, not a dumb question. Because the reference voltage is the basis on which the ADC ladder is set, that voltage will always be the maximum level the ADC supports. For the Arduino Uno, its 10-bit ADC means the max value is 1023 (one less than 2 to the power of 10).

  • lewlssss

    how to display 9999 on a 7 segment using ADC ? Can’t it go beyond 255 ? im using pic18f452 btw