An analog to digital converter (ADC) is a peripheral that can read an analog voltage value and convert it into a digital or numeric value. This is perfect for reading some types of sensors like thermistors, photocells, force sensitive resistors, load cells, and more that change resistance based on what they're sensing. When a sensor changes its resistance it can cause a change in voltage that an analog to digital converter reads and converts into a number that a microcontroller understands.
Most MicroPython boards have built-in analog to digital converters. This means you can easily connect sensors and other analog components to read their values. However be aware each board is different and its analog to digital converter will have different specs like accuracy and voltage limits. Be sure to check out your board's documentation for more details:
- MicroPython ESP8266 ADC Documentation
- The ESP8266 has one ADC with 10-bit accuracy and a maximum voltage of 1.0 volt. Be sure not to exceed 1 volt on the ADC input or you could damage the board!
- MicroPython pyboard ADC Documentation
- The pyboard has three ADC's with 12-bit accuracy and a maximum voltage of 3.3 volts.
- MicroPython WiPy ADC Documentation
- The WiPy has four ADC's with 12-bit accuracy and a maximum voltage of 1.4 volts.
For this example we'll wire up a potentiometer, which is a variable resistor you can change by turning a knob, so that MicroPython on an ESP8266 board can read its value. To follow this example you'll need the following parts (which are all available in the Adafruit Parts Pal):
- MicroPython ESP8266 board, like the Adafruit Feather HUZZAH ESP8266. Other MicroPython boards can work too, but you might need to change the syntax slightly as mentioned further below in the code.
- 1x 10 kilo-ohm or 1 kilo-ohm potentiometer
- The value of the potentiometer doesn't actually matter for how it will be used in this circuit.
- 1x 10 kilo-ohm resistor
- 1x 47 kilo-ohm resistor OR 22 kilo-ohm resistor
- If you have a 22 kilo-ohm resistor you can use it to get the full range of 10-bit values. If you only have a 47 kilo-ohm resistor then you'll only get about half the range of values.
- Breadboard and jumper wires.
Note the value of the two resistors used in this circuit are very important. These resistors will form a voltage divider that drops 3.3V down to 0.5-1V which is below the voltage limit of the ESP8266 ADC. It's very important to use a voltage divider or other means to make sure the maximum voltage to the ADC is 1V or less!
Wire up the components as follows:
- Board 3.3V power to one side of the 47 kilo-ohm (or 22 kilo-ohm) resistor.
- The opposite side of the 47 kilo-ohm (or 22 kilo-ohm) resistor to one of the outside pins of the potentiometer (i.e. not the middle pin, pick the left or right outer pin as it doesn't really matter which one you use).
- The opposite outer pin of the potentiometer connects to board ground.
- One side of the 10 kilo-ohm resistor connects to the where the 47/22 kilo-ohm resistor connects to the potentiometer.
- The opposite side of the 10 kilo-ohm resistor connects to board ground.
- The middle pin of the potentiometer connects to the board ADC input.
Double check you have the two resistors in the circuit exactly as shown above. If you accidentally swap them you might damage the ADC on the board!
This circuit works by converting the 3.3 volt output of the board to a smaller voltage that's safe for the ADC to read. The two resistors form a voltage divider that cuts the voltage down to about 0.5 volts when using a 47 kilo-ohm resistor and about 1 volt when using a 22 kilo-ohm resitor. This voltage goes into one side of the potentiometer and will travel down to ground on the opposite side.
As the knob of the potentiometer rotates it changes the resistance and voltage seen by the middle/output pin. On one extreme of the knob the middle pin will see the full input voltage (0.5 or 1 volt) and on the other extreme it will see 0 volts/ground. At the half-way point the output voltage will be half of the input. Try using a multimeter to read and confirm the voltage output by the potentiometer!
Now to read the ADC value open a serial or other REPL on the MicroPython board. First enter the following code to import the machine module:
pyboard note: Currently the pyboard uses the older pyb module instead of the machine module for ADC access. Check out the pyboard ADC examples for the slightly different syntax to use.
Now you can create an instance of the ADC class by running:
adc = machine.ADC(0)
adc = machine.ADC(0)
pyboard note: Since the pyboard has multiple ADC channels you should instead pass a Pin instance to the ADC initializer with the pin name for the desired ADC channel (like X19, X20, etc). See the pyboard ADC examples for more details.
WiPy note: The WiPy also has multiple ADC channels but has a slightly different syntax to choose the right one to read. Check the WiPy ADC example to see how you call the channel function on the ADC object to pick the channel you want to read.
Once you have an instance of the ADC class (or ADC channel) you can read its value with the read function:
WiPy note: The WiPy has a slightly different syntax where you call value or invoke the channel object as a function instead of calling read. Check the WiPy ADC example for more details.
This function should return a number that will change depending on where the potentiometer knob is pointing. Try moving the potentiometer knob and calling the read function again. Keep moving the knob to different points and calling read to see how the number changes.
If you turn the knob to one extreme you should get a value that's less than 10 or even close to zero, and on the opposite extreme you should get a large value that's 300 or higher (800 or more if using the 22 kilo-ohm resistor). As you turn the knob between the two extremes you should see the reading grow and shrink evenly between those extreme values.
Note that the value might change slightly each time you call read even if you don't move the knob. It's normal for ADC readings to be 'noisy' and fluctuate up or down a tiny bit. You could read the ADC a few times and average the readings to get a more stable value if necessary.
The value you're seeing is the raw output of the analog to digital converter. The ADC is taking the voltage that it reads from the potentiometer and converting it to a number that ranges from 0 to the maximum bit accuracy of the ADC. For the ESP8266 it has a 10-bit ADC which means it can give values that range from 0 to 1023. For boards with a 12-bit ADC they can range from 0 to 4095.
The ADC determines the value to return based on where the voltage falls within the range it supports. For the ESP8266 it only supports a range of 0 to 1 volts, so an input of 0.5 volts would return a value exactly in between 0 and 1023, or around 512. An input of 1 volt would return 1023 (the maximum), and an input of 0 volts would return 0.
That's all there is to reading a potentiometer with an analog to digital converter in MicroPython! Just create an instance of the ADC class or channel and call its read function. With access to an analog to digital converter you can explore many different types of analog sensing using MicroPython. For example use a thermistor and an ADC to measure temperature!