phrase there is “so far.” You won’t see much benefit when
performing simple digital I/O, but you will see great
benefits as we continue on our journey. Because digital
I/O is so straightforward, it is the perfect place to cut your
teeth on the concepts of registers, bitwise operations, bit
masking, and so on.
If you’re ready to go on and don’t feel like I’ve been
cheating you by making things complex for no good
reason, then fasten your safety belt as we move onto
reading analog values.
Advancing with Analog
Grab yourself a cup of coffee; it’s going to get fun in
this section! You likely already know that microcontrollers
use an ADC (Analog-to-Digital Converter) to read analog
inputs and convert them to digital values that they can
work with. The sidebar, ADC Successive Approximation
gives you a quick look into how the ATmega ADC actually
Before we get into the “how,” I’ve listed a few features
of the ADC that we can access now that we’ve moved
away from the Arduino IDE (I’m working hard to sell the
Conversion Modes: Single, Continuous, and Triggered
In the Arduino IDE, you worked in single mode; in
other words, the ADC performed a conversion each time
it was instructed to with the analogRead() function.
Working directly with the ADC, you can now choose to
work in continuous mode (or free-running mode as the
datasheet refers to it) in which a new conversion starts as
soon as the previous one has completed. Alternatively,
you can specify that the conversion is triggered by an
interrupt — either an internal interrupt such as a timer, or
an external one such as an interrupt on an I/O pin.
Conversions can Cause Interrupts
Using registers, you’re able to configure the ADC to
trigger an interrupt when a conversion has been
completed. As we move through this series, we’ll start
using various interrupts increasingly, and the ADC
interrupt can be a useful one — resulting in simpler code
and saved resources.
Speed vs. Accuracy
If the standard 10-bit ADC accuracy is not needed,
you are able to trade accuracy for speed. The Arduino
IDE’s analogRead() function can perform approximately
10,000 conversions a second. Working with the ADC
directly at the same level of accuracy, you can achieve
about 13,000 conversions a second. From there, you can
increase the conversion frequency further, for a reduction
in accuracy — perhaps this is an experiment to include in a
I won’t cover all these features this time, but it is
useful to know they exist. Finally, before we get into the
details, I recommend you read section 24 of the ATmega
datasheet ( www.atmel.com/devices/ATMEGA328P.aspx).
It may seem like a foreign language to you, but the more
you read these seemingly endless documents, the more
you’ll start to see their usefulness.
40 May 2015
The ATmega328 ADC uses a method called successive
approximation to convert an analog signal into a digital value,
meaning that it is equipped with an SAR (Successive Approximation
Register) ADC. Don’t be put off by the mouthful of mnemonics as it’s
actually quite a simple concept.
The SAR-ADC works by generating a voltage using a DAC
(Digital-to-Analog Converter). I know, it sounds rather back to front
that the ADC in reading a voltage, in fact, generates a voltage.
However, it uses it in a pretty smart way, utilizing a binary search
(for those of you that are from a software background).
An example is probably the easiest way to demonstrate this. I
won’t go the full 10 bits of the ADC’s resolution as I know you have a
life outside of this sidebar, so let’s keep it to six bits.
Let’s say that our AREF (remember, this is our voltage
reference) is 5V, and that the voltage on pin PC0 is 1.68V. The ADC
finds the voltage by:
1. Generating a voltage on the DAC.
2. Comparing the DAC voltage to the voltage on the analog pin.
3. If the DAC voltage is higher, set the current bit in the SAR
register to 0, and subtract half the difference between the
current and previous DAC value.
4. If the DAC voltage is lower, set the current bit in the SAR
register to 1, and add half the difference between the current
and previous DAC value.
Figure A shows a graph of the approximation process using a
six-bit ADC, resulting in a SAR register value of 010101. This is 21
decimal (the maximum value for a six-bit ADC is 63), resulting in a
calculated voltage of:
21 / 63 5V = 1.667V
This is pretty close to the actual voltage on pin PC0.
As you can see, there is a fair amount of work involved in
taking an ADC reading – which explains why it is not an
instantaneous process, and therefore why we need to wait in a loop
until the conversion is complete.
Figure A: A graph illustrating successive approximation
on an ADC.