Analog to Digital Converter (Inputs)

An analog to digital converter (or ADC) is a device that reads the voltage of an analog signal and converts it into a digital, or numeric, value. The microprocessor in your development board can’t deal with analog signals directly because they can be an infinite range of values. However if the analog signal is converted into a numeric value then it can be processed and reasoned about by the microprocessor just like any other number. The ADC is the key to reading analog signals and voltages with a microprocessor.

Typically development boards have one or more built-in analog to digital converters. Check your board’s documentation for details on the number of ADCs and which pins are used as inputs for them (some boards like the Metro M0 Express, Circuit Playground Express, Trinket M0, and Gemma M0 note their analog inputs with names like A0, A1, etc.).

Along with the number of analog to digital converters your board’s documentation also might mention the resolution or ‘bits’ used by the ADC. The resolution of the ADC controls how accurately it can read a voltage. For example a 12-bit ADC can represent analog voltages with 12-bit values, i.e. 0 to 4095 (use the equation 2^12 - 1 to understand how the number of bits relates to the possible values). This means the 12-bit ADC can see 4096 different voltages (remember 0 is a unique value too). That’s a lot of voltages, but remember analog signals have an infinite range of values so there might be cases where two measurements aren’t different enough for the ADC to measure and will appear as the same numeric value!

To understand the accuracy of an ADC you also need to understand its range of possible input values. Again check your board’s documentation to see how it defines (or lets you define) its analog reference voltage. The reference voltage sets the range of possible input voltages the ADC can measure. When the ADC reads the voltage it will see where it falls within the range of input voltages and output a number that falls within the same range of its bit resolution.

For example if a 12-bit ADC has a reference voltage of 3.3 volts (a typical value for most ADCs built-in to microprocessors) and reads a 2.5 volt value you can calculate the value output by the ADC (try running this in an interactive Python REPL):

Download: file
>>> int(2.5 / 3.3 * 4095)
3102

This means the ADC would return a value of 3102 for an input of 2.5 volts! You can try other input voltages too, like 0.1 volt:

Download: file
>>> int(0.1 / 3.3 * 4095)
124

Notice it returns a much smaller value of 124. What if you ever so slightly increase the voltage to 0.1001 volts?

Download: file
>>> int(0.1001 / 3.3 * 4095)
124

Wow you get the same 124 value even though the input voltage is slightly higher! This highlights a constraint of analog to digital converters that their analog reference range and bit resolution dictate the accuracy of voltage measurements. If you want to read very small changes in voltage you need a higher bit ADC, like 24 or even 32 bits of range, or a much smaller and more constrained reference voltage range.

To demonstrate the analog to digital converter you can read the voltage output by a potentiometer. A potentiometer is a small variable resistor that you can twist a knob or shaft to change its resistance. By wiring the potetiometer to your board in a special way (called a voltage divider) you can turn the change in resistance into a change in voltage that your board’s analog to digital converter can read. You’ll need the following parts to try this:

  • A potentiometer. Almost any potentiometer will work as long as it has 3 pins. A potentiometer is like a resistor and classified by its resistance in ohms (typically 1, 10, 100, etc. kilo-ohms). By twisting the knob or shaft on the potentiometer you can change the resistance of the middle pin (called the wiper) to be anywhere inbetween the range of resistance of the potentiometer.
  • A breadboard and wires to connect the components and board together.

Connect the components to your board as follows:

  • One of the outer legs of the potentiometer to the board ground or GND pin.
  • The opposite outer leg of the potentiometer to the board 3.3 volt output.
  • The middle leg of the potentiometer to an analog input of the board, like A0.

Now at the REPL import the analogio and board module to create an instance of the analogio.AnalogIn class:

Download: file
>>> import board
>>> import analogio
>>> adc = analogio.AnalogIn(board.A0)

Notice the analogio.AnalogIn class initializer needs to be told which pin will be used as the analog input. In this case the board pin A0 is being used as the ADC input.

Once the analog input is initialized you’re ready to start reading from it with the analogio.AnalogOut.value property. Simply read the value property to see the numeric output of the ADC:

Download: file
>>> adc.value
32683

Try twisting the knob of the potentiometer and reading the value property again, for example twist the knob all the way towards the ground input:

Download: file
>>> adc.value
65

If you read the value a few times you might notice the value changes a bit but stays around a low value near zero. Remember analog signals can be an infinite range of values so even though the potentiometer knob hasn’t moved, the voltage read by the ADC might be very slightly changing based on heat, electrical interference, vibrations, etc. that can affect analog devices and signals.

If you twist the knob of the potentiometer all the way to the other extreme near 3.3 volts and read its value:

Download: file
>>> adc.value
65476

You should see a very high value near 65000. As the voltage to the analog input increased the ADC value increased too!

As an aside if you have a multimeter try using it to measure the voltage output from the potentiometer. Connect the positive lead of the probe to the center output pin of the potentiometer and the ground lead of the probe to the ground pin of your board or potentiometer. Set the meter to read DC voltage and watch how the voltage and ADC value change as you twist the potentiometer knob. Remember the ADC is just converting the voltage into a number so as the voltage measured by the meter increases you’ll also see the ADC value increase!

For ADC values in CircuitPython you’ll find they’re all put into the range of 16-bit unsigned values. This means the possible values you’ll read from the ADC fall within the range of 0 to 65535 (or 2^16 - 1). Remember when you twisted the potentiometer knob to be near ground you saw a value close to zero and when you twisted it to the other extreme near 3.3 volts you saw a value close to 65535–you’re seeing almost the full range of 16-bit values!

One important note about this 16-bit range is that it applies even if your board’s ADC has a different resolution (like 10 or 12 bits). Using 16-bits as a base resolution is handy to make code work across many different boards but be aware you might not actually be getting 16-bits of resolution from your ADC. Check your board’s documentation to see the true resolution of its ADC.

Finally there’s one more handy property of the analogio.AnalogIn class, the analogio.AnalogIn.reference_voltage. This property lets you read the reference voltage used by the ADC to convert voltages into numbers. This is useful to convert the number you read from the ADC into an actual voltage value. Try running this code to read the ADC value and convert it into voltage using the reference voltage:

Download: file
>>> adc.value / 65535 * adc.reference_voltage
3.2998

Twist the potentiometer knob and run the same line again to see how the voltage value changes!

You can also wrap the above equation into a Python function that's easy to call and convert ADC values into voltages:

Download: file
>>> def adc_to_voltage(val):
...    return val / 65535 * 3.3
>>> adc_to_voltage(adc.value)
3.2998
This guide was first published on Sep 02, 2017. It was last updated on Sep 02, 2017. This page (Analog to Digital Converter (Inputs)) was last updated on Aug 24, 2019.