Raspberry Pi ADC (Analog to Digital Converter)

In this tutorial, I go through the steps of setting up a Raspberry Pi ADC (Analog to digital converter).

Raspberry Pi ADC

As you may already know the Pi doesn’t have any GPIO pins that are analog. This lack of analog pins makes connecting analog sensors a little more complex.

There are several solutions to the lack of Analog pins like the one I did in the Raspberry Pi LDR tutorial which involved using a capacitor to measure the resistance of the LDR (Light Dependent Resistor).

A better solution to this would be to use what is known as an analog digital converter (MCP3008). This chip involves a little bit of setting up which I will go into below.

I also go into setting up the MCP3008 with MyDevices Cayenne, this is a much easier process than writing the code from scratch, but sometimes half the fun is in learning how to code.

Equipment

You will need the following equipment for this Raspberry Pi ADC tutorial. You can use different versions of the analog to digital converter such as an MCP3004 but steps to getting it working may differ from this tutorial.

Recommended

Optional

Video

If you want to see how to do everything visually, then be sure to check out the video I have prepared below.

It goes through all the steps to getting the chip wired correctly and how you can access the devices connected to it.

Adblock removing the video? Subscribe to premium for no-ads.

The Raspberry Pi ADC Circuit

The circuit for connecting the MCP3008 to the Pi looks quite involved, but it’s all about just connecting the wires up correctly.

The MCP3008 is the chip that I will be using in this Raspberry Pi ADC tutorial. There is a lot of technical information on this chip, but I will just touch on the bare basics.

For anyone who is new to microchips, you will find that one end of the chip will have a notch in it. This notch represents the end where pin 1 is. It is usually the first pin on the left-hand side with the notch facing away from you (see diagram below). Pin one also sometimes has a little dot above it.

This particular chip makes use of the SPI (Serial Peripheral interface bus) which means it will only require four pins and is relatively easy to communicate to thanks to the SPIDev library for Python.

The CH0->CH7 pins (Pins 1-8) are the analog inputs for the MCP3008. On the other side, we have a whole range of different pins.

  • DGND (Pin 9) is the digital ground pin for the chip.
  • CS (Pin 10) is the chip select.
  • DIN (Pin 11) is the data in from the Raspberry Pi itself.
  • DOUT (pin 12) is the data out pin.
  • CLK (Pin 13) is the clock pin.
  • AGND (Pin 14) is the analog ground and obviously connects to ground.
  • VREF (Pin 15) is the analog reference voltage. You can change this if you want to change the scale. You probably want to keep it the same so keep this as 3v3.
  • VDD (Pin 16) is the positive power pin for the chip.
Raspberry Pi mcp3008


If you want more information on the chip, then you can find the full datasheet over at Adafruit.

Putting the circuit together is pretty straightforward. The circuit is likely to look a bit messy since we’re going to have to use quite a few wires. You can clean this up later if you want to make it more of a permanent project.

In this example, I have included an LDR to show how you can get the value of the LDR back to the Pi by using the analog to digital converter (ADC).

First, connect a 3v3 pin to the positive rail on the breadboard and a ground pin to the ground rail on the breadboard. Also, place the MCP3008 chip into the middle of the breadboard.

  • VDD (Pin 16) wire this to 3.3V
  • VREF (Pin 15) wire this to 3.3V
  • AGND (Pin 14) wire this to ground
  • CLK (Pin 13) wire this to GPIO11 (Pin 23/SCLK)
  • DOUT (Pin 12) wire this to GPIO9 (Pin 21/MISO)
  • DIN (Pin 11) wire this to GPIO10 (Pin 19/MOSI)
  • CS (Pin 10) wire this to GPIO8 (Pin 24/CE0)
  • DGND (Pin 9) wire this to GROUND

Now once you have done that you will probably want to connect the LDR up to the MCP3008, this is pretty easy to do.

First, place the LDR onto the breadboard. Next, have the 10k resistor go to one end of the LDR and the other end to the positive rail. Have a wire go from in between the LDR and the positive wire to pin 1 (CH0) of the MCP3008. Lastly, have a wire go from the other side of the LDR to the ground rail on the breadboard.

If you need further help on making the circuit, you can find a detailed diagram below. If you’re still having trouble, double check the chip connections, and also making sure all the pins are connected correctly.

Raspberry Pi ADC Circuit

The Code

The code for this is pretty simple but is also only handling just one input, the LDR. The code may be a little more complicated the more devices you add.

All the required packages for this tutorial should be installed by default on Raspbian. If you find it a little overwhelming than an easier option would be to use a tool such as Raspberry Pi Cayenne that I mention below.

Our Python basics guide is excellent if you’re new to Python coding and wish to learn more. You should still be fine to complete this tutorial with little to no Python knowledge.

If you come across any issues, then check out my guide on the Raspberry GPIO pins. It goes through how to set them up and install the necessary software.

To quickly download the code straight onto your Pi just run the following line in the terminal. Alternatively, you can download it over at GitHub.

git clone https://github.com/pimylifeup/Pi-ADC-Example-Code

You will need to change directory into the directory that contains our script by running the following line.

cd ./Pi-ADC-Example-Code

You can now launch it by running the following line.

sudo python adc-code.py

You can stop the script by press CTRL + C.

I will now just briefly explain the code. At the start of the code, we define the path of where Python is installed. After this, we import two packages that we will need. Time allows us to put the script to sleep (Add a delay). Spidev allows us to communicate with SPI devices, in this case, it is the MCP3008.

#!/usr/bin/python
 
import spidev
import time

Next, we define the variables and create our SPIdev object. We create two variables first being a delay in milliseconds. Alter this if you want there to be a more considerable amount of time between updates. Next is the channel our LDR is located on, this is channel 0/pin 1.

Finally, we create the SPIdev object. This object allows us to get the values we need from the device connected the SPI enabled pins.

#Define Variables
delay = 0.5
ldr_channel = 0

#Create SPI
spi = spidev.SpiDev()
spi.open(0, 0)

Next, we have the readadc function in which we do a couple of things. Firstly, we check the parameter value to make sure it’s between 0 and 7, if not then return -1. If it is, we then proceed to get the value from the channel specified and then return the value.

def readadc(adcnum):
    # read SPI data from the MCP3008, 8 channels in total
    if adcnum > 7 or adcnum < 0:
        return -1
    r = spi.xfer2([1, 8 + adcnum << 4, 0])
    data = ((r[1] & 3) << 8) + r[2]
    return data

Lastly we have a while loop that continues until you force quit it by pressing CTRL + c. The first thing we do is call the readadc function with the ldr_channel variable as the parameter.

Once we get the value, back we simply print it. The %d refers to a decimal value; we then have our variable after the print statement. You can print multiple values per line by doing something like this. print '%s %d' % (name, number)

After we have printed the data, we delay the script for whatever the delay time is set to. By default, it is set for half a second.

while True:
    ldr_value = readadc(ldr_channel)
    print "---------------------------------------"
    print("LDR Value: ".ldr_value)
    time.sleep(delay)

I hope this has helped you understand the code a little. As I mentioned above, you can download the full script over at the GitHub.

If you do come across any problems, then feel free to mention them in the comments below.

Using the ADC with Raspberry Pi Cayenne

I will now quickly go through the steps to set up the MCP3008 with Cayenne. I will also go through how to setup the LDR.

If you haven’t already set up Cayenne, then be sure to follow my guide on how to install Raspberry Pi Cayenne. The tutorial goes through the steps to getting it installed and most the basics you need to know for creating your very own smart applications.

1. To begin first go to add new and then select device from the drop-down box.

2. Then either search or select analog converter.

3. In this list select the MCP3008

4. Now select the Raspberry Pi and then SPI Chip-Select 0

5. This selection will now bring up a screen that shows you all the values of the channels.

MCP3008 Cayenne

Now to add the LDR, the process is pretty much the same, but I will go through it anyway.

1. Go back up to add new and then select device.

2. Find or select the photoresistor (Luminosity Sensor).

3. For this one select your Raspberry Pi, your preferred widget (I went graph), then select the MCP3008 for the analog converter and finally channel 0 for the channel.

4. This sensor should now add without any issue. It will now produce a graph from the values it gets from the analog converter.

photoresistor cayenne

Now you can pretty much follow this same process for any analog device. I will cover any sensor or device that is analog in the near future. It includes things such as the tmp36 temperature sensor.

I hope this tutorial has helped you with setting up a Raspberry Pi ADC. If you come across any issues, have feedback or notice a mistake, then please feel free to leave a comment below.

14 Comments

  1. Avatar for Thomas Bulb
    Thomas Bulb on

    I always get “LDR Value: 1023”. Not sure what I did wrong, I closely followed the tutorial. Any small hints? No need to write an essay, just a small hint please. Anyone?

    1. Avatar for NK
      NK on

      Thomas,

      I had the same issue. Apparently, the voltage being fed to the ADC is 3.3V (by connecting it to Vcc according to the tutorial.) which is the max voltage and so you get the LDR value as 1023 which is the maximum. You didn’t do anything wrong. I feel we are missing out some point on using the photo resister (how the value will be fluctuating) that would alter LDR value but I’m not sure how to fix it.

  2. Avatar for Sherry
    Sherry on

    Hello,
    Thank you for the tutorial. I learned alot. After setting up though when i run the code, i get ldr value = 0. Which tells me its not really gathering any data. How can i best troubleshoot for this?

  3. Avatar for Paul Clark
    Paul Clark on

    This is a very clear and helpful tutorial which complement the You Tube video.
    The pin out diagram and the wiring diagram are a great help too.
    The code works perfectly as well.
    Many thanks Gus.

  4. Avatar for Lukas
    Lukas on

    Hi there! Congratulations on the tutorial, I found it very helpful. I see that you connect the ADC to 4 of the GPIOs in the PI (apart from ground and 5v), these are pins number 8,9,10 and 11. Is it possible to connect several MCP3008 to the same Raspberri so that we can read more analog inputs and connect the new MCP3008 to different GPIO’s?

    1. Avatar for Alex
      Alex on

      Obviously you can attach up to two ADC chips using GPIO8 and GPIO7 (CE0 and CE1). Attach them to CS pins of your ADC chips. In this way you’ll get 16 channels. As I suppose, you can have even more, but you’ll can’t use standard Python library then. For example, you could attach a binary demultiplexer to some GPIO outputs of your choice and switch up to 2^n chips, where n is the number of GPIO pins used. But Py library doesn’t support it, so you’ll need to use spi.open(0,0) and switch ADC chips by setting/resetting GPIO pins. I never tried it, but I don’t see a reason why this way couldn’t work.

  5. Avatar for plyons
    plyons on

    First, great tutorial!

    I understand that the raspberry pi can only read voltages up to 3.3V. However, since we’re using the chip to convert the voltage, does the voltage coming into the ADC still need to be between 0 and 3.3V??

    I’m assuming is that the ADC is “receiving the voltage” not the raspberry pi. Am I incorrect with this assumption?

    1. Avatar for Andrew
      Andrew on

      That’s correct. An ADC only outputs binary numbers so you are safe to supply the ADC with 5V. You will just need an external source to provide the voltage as Raspberry Pi only has the capability to provide 3.3V.

  6. Avatar for Balkrishna
    Balkrishna on

    Dear Sir
    Will you please provide tutorial for interfacing
    Mcp 3208 adc
    BMW

    1. Avatar for Gus
      Gus on
      Editor

      Hi Balkrishna,

      I will add it onto my list of things to look into!

  7. Avatar for PJ
    PJ on

    Gus,
    I noticed you hook the ADC to the 3.3V rail. If I have a sensor that outputs 0-3.6V can I just connect the MCP3008 to the 5V rail instead? Also the values that the pi was displaying in the video from the photo resistor was something like 613. What exactly is that value?

    Thanks,
    PJ

  8. Avatar for Shlomo
    Shlomo on

    Thanks for a great tutorial.

    I want to do several projects using various analog sensors – temperature, vibration, etc. I’m sure your tutorial on using the ADC converter will be a big help. But I have 2 questions:

    1 – You use the MCP3008. I’ve seen many other “similar” chips on e-bay – for example: PCF8591T or ADC0809CCN. Do you know if they could be substituted for the chip you use?

    2 – I’ve seen several sensor kits advertised, but although many of them mention the Raspberry Pi, they don’t seem to include Python code – only C++ code for the Arduino. I’m including a link to one such kit. Do you think the sensors in this kit would work with the code you’ve demonstrated?

  9. Avatar for Paul Antuar
    Paul Antuar on

    In the video, you skipped over the line
    spi.open(0, 0)
    with no explanation. Obviously, it starts things happening but what are the parameters (0, 0)?

    1. Avatar for Gus
      Gus on
      Editor

      Hi Paul,

      Sorry about that!

      spi.open(bus, device)

      Bus is the SPI bus we want to use. Since the Pi only has 1 this is 0.

      Device is the chip select/GPIO Pin we want to use. CE0 or CE1 (0 or 1)

      I hope that answers your question

Leave a Reply

Your email address will not be published. Required fields are marked *