Close Menu
    Facebook X (Twitter) Instagram Pinterest YouTube
    Trending
    • Disable SSH Password Login on Raspberry Pi
    • Elecrow Meteor IPS Touchscreen with RGB LEDs
    • Pi Pico Pinout Display on the Command Line
    • How to Add a Raspberry Pi Pico Reset Button
    • Pi Pico Onboard LED
    • Pi Pico W Pinout and Power Pins
    • CrowPi L Raspberry Pi Laptop and Learning Platform
    • Pi Pico W Launched
    Mastodon YouTube Facebook Instagram Pinterest RSS
    Raspberry Pi SpyRaspberry Pi Spy
    • Home
    • Categories
      • General
      • Hardware
      • Programming
      • Python
      • Software
      • Tutorials & Help
    • BerryClip
      • BerryClip Instructions
      • BerryClip Plus Instructions
      • Videos & Reviews
    • Buy
      • Buy Pi
      • Buy Pi Accessories
      • Buy Books
    • Tools
      • Ultimate Raspberry Pi Alexa Skill
      • Pi Power Estimator App
      • Pi-Lite 14×9 LED Matrix Sprite Editor
      • RPiREF Pin-out Reference App
      • Simple Ohm’s Law Calculator
      • Web Sites & Links
    • Tutorials & Help
        Featured
        November 9, 20200

        Raspberry Pi Temperature Monitoring

        Recent
        February 16, 2024

        Disable SSH Password Login on Raspberry Pi

        December 23, 2022

        How to Add a Raspberry Pi Pico Reset Button

        November 20, 2022

        Pi Pico Onboard LED

      1. Contact Us
      2. Site Map
      Raspberry Pi SpyRaspberry Pi Spy
      You are at:Home»Python»Analogue Sensors On The Raspberry Pi Using An MCP3008
      MCP3008 Example Circuit #2

      Analogue Sensors On The Raspberry Pi Using An MCP3008

      100
      By Matt on October 20, 2013 Python, Sensors, Tutorials & Help

      The Raspberry Pi has no built in analogue inputs which means it is a bit of a pain to use many of the available sensors. I wanted to update my garage security system with the ability to use more sensors so I decided to investigate an easy and cheap way to do it. The MCP3008 was the answer.

      The MCP3008 is a 10bit 8-channel Analogue-to-digital converter (ADC). It is cheap, easy to connect and doesn’t require any additional components. It uses the SPI bus protocol which is supported by the Pi’s GPIO header.

      This article explains how to use an MCP3008 device to provide 8 analogue inputs which you can use with a range of sensors. In the example circuit below I use my MCP3008 to read a temperature and light sensor.

      Here are the bits I used :

      • Raspberry Pi
      • MCP3008 8 channel ADC
      • Light dependent resistor (LDR)
      • TMP36 temperature sensor
      • 10 Kohm resistor

      The first step is enabling the SPI interface on the Pi which is usually disabled by default.

      Please follow my Enabling The SPI Interface On The Raspberry Pi article to setup SPI and install the SPI Python wrapper.

      Circuit

      MCP3008

      The following list shows how the MCP3008 can be connected. It requires 4 GPIO pins on the Pi P1 Header.

      VDD   3.3V
      VREF  3.3V
      AGND  GROUND
      CLK   GPIO11 (P1-23)
      DOUT  GPIO9  (P1-21)
      DIN   GPIO10 (P1-19)
      CS    GPIO8  (P1-24)
      DGND  GROUND

      The CH0-CH7 pins are the 8 analogue inputs.

      Here is my breadboard circuit :

      MCP3008 BreadboardIt uses CH0 for the light sensor and CH1 for the TMP36 temperature sensor. The other 6 inputs are spare.

      Here is a photo of my test circuit on a small piece of breadboard :

      MCP3008 Example Circuit #2

      LDR ExampleLight Dependent Resistor

      I chose a nice chunky LDR  (NORPS-12, datasheet). Under normal lighting its resistance is approximately 10Kohm while in the dark this increases to over 2Mohm.

      When there is lots of light the LDR has a low resistance resulting in the output voltage dropping towards 0V.

      When it is dark the LDR resistance increases resulting in the output voltage increasing towards 3.3V.

      TMP36 Temperature SensorTMP36 Temperature Sensor

      The TMP36 temperature sensor is a 3 pin device (datasheet). You can power it with 3.3V and the middle Vout pin will provide a voltage proportional to the temperature.

      A temperature of 25 degrees C will result in an output of 0.750V. Each degree results in 10mV of output voltage.

      So 0 degrees will give 0.5V and 100 degrees will give 1.5V.

      Reading The Data Using a Python Script

      The ADC is 10bit so it can report a range of numbers from 0 to 1023 (2 to the power of 10). A reading of 0 means the input is 0V and a reading of 1023 means the input is 3.3V. Our 0-3.3V range would equate to a temperature range of -50 to 280 degrees C using the TMP36.

      To read the data I used this Python script :

      #!/usr/bin/python
      
      import spidev
      import time
      import os
      
      # Open SPI bus
      spi = spidev.SpiDev()
      spi.open(0,0)
      spi.max_speed_hz=1000000
      
      # Function to read SPI data from MCP3008 chip
      # Channel must be an integer 0-7
      def ReadChannel(channel):
        adc = spi.xfer2([1,(8+channel)<<4,0])
        data = ((adc[1]&3) << 8) + adc[2]
        return data
      
      # Function to convert data to voltage level,
      # rounded to specified number of decimal places.
      def ConvertVolts(data,places):
        volts = (data * 3.3) / float(1023)
        volts = round(volts,places)
        return volts
      
      # Function to calculate temperature from
      # TMP36 data, rounded to specified
      # number of decimal places.
      def ConvertTemp(data,places):
      
        # ADC Value
        # (approx)  Temp  Volts
        #    0      -50    0.00
        #   78      -25    0.25
        #  155        0    0.50
        #  233       25    0.75
        #  310       50    1.00
        #  465      100    1.50
        #  775      200    2.50
        # 1023      280    3.30
      
        temp = ((data * 330)/float(1023))-50
        temp = round(temp,places)
        return temp
      
      # Define sensor channels
      light_channel = 0
      temp_channel  = 1
      
      # Define delay between readings
      delay = 5
      
      while True:
      
        # Read the light sensor data
        light_level = ReadChannel(light_channel)
        light_volts = ConvertVolts(light_level,2)
      
        # Read the temperature sensor data
        temp_level = ReadChannel(temp_channel)
        temp_volts = ConvertVolts(temp_level,2)
        temp       = ConvertTemp(temp_level,2)
      
        # Print out results
        print "--------------------------------------------"
        print("Light: {} ({}V)".format(light_level,light_volts))
        print("Temp : {} ({}V) {} deg C".format(temp_level,temp_volts,temp))
      
        # Wait before repeating loop
        time.sleep(delay)
      

      Here is a screen-shot of the output :

      MCP3008 Screenshot

      You can download this script directly to your Pi using :

      wget https://bitbucket.org/MattHawkinsUK/rpispy-misc/raw/master/mcp3008/mcp3008_tmp36.py

      It can then be run using :

      sudo python mcp3008_tmp36.py

      Alternatively if you are a Git fan you can clone my Raspberry Pi misc scripts repo using :

      git clone https://bitbucket.org/MattHawkinsUK/rpispy-misc.git

      Additional Explanation of spi.xfer2

      Lots of people have asked about the spi.xfer2 line. This sends 3 bytes to the device. The first byte is 1 which is equal to 00000001 in binary.

      “8+channel” is 00001000 in binary (where channel is 0). “<<4” shifts those bits to the left which gives 10000000. The last byte is 0 which is 00000000 in binary.

      So “spi.xfer2([1,(8+channel)<<4,0])” sends 00000001 10000000 00000000 to the device. The device then sends back 3 bytes in response. The “data=” line extracts 10 bits from that response and this represents the measurement.

      The exact reason why you do the above is explained in the datasheet but that is outside the scope of this article.

      More Information

      If you want more technical information about the device please take a look at the official Microchip MCP3008 datasheet. If you want to know more about the SPI bus then take a look at the Serial Peripheral Interface Bus Wikipedia page.

       

      Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
      Previous ArticleAdventures In Raspberry Pi
      Next Article Pi NoIR Infrared Camera Module For Raspberry Pi

      Related Posts

      Disable SSH Password Login on Raspberry Pi

      How to Add a Raspberry Pi Pico Reset Button

      Pi Pico Onboard LED

      100 Comments

      1. Michael Horne on October 20, 2013 1:36 pm

        Great guide – thanks for keeping it simple. 🙂

        Reply
      2. richard lines on October 25, 2013 10:18 am

        Great article that addresses one of the Pi’s main shortcomings.

        Why do people settle for 10 bits with the MCP3008 when the MCP3208 costs pennies more and does 12 bits? I believe it’s pin and code compatible as well. You might as well go for all the resolution available…admittedly it’s up to the user to analogue filter the input to really make good use of the available resolution.

        Reply
        • andycrofts on October 25, 2013 3:35 pm

          Analog filtering’d work, but cheaper to average the incoming voltage in software.
          Thinking of my days with early Nicolet spectrum analysers, we got an extra ½ bit rersolution by adding a bit’s-worth of noise to the analog input. We had to filter first (anti-aliasing – Nyquist and all that…) but in the temp. measurement aliasing isn’t an issue, so any ‘noise’ might actually be beneficial, if averaged over, say 4 samples before presentation…then adjust the resolution in the ‘places’ variable. Worth trying, YMMV.

          Reply
        • Roman on March 29, 2014 7:43 pm

          Quick question: do you know how the data= line would change for the 3208 (which has 12 bits instead of 10?)

          Reply
      3. richard lines on October 26, 2013 7:27 am

        Yes, Analogue filtering depends on your application…if all you’r doing is monitoring an essentially static voltage then software filtering is fine for removing the residual noise ….if you’re looking at a signal with a known AC content then you need to worry about Nyquist sampling rates and anti-aliasing.

        Dithering is an old trick with lower resolution converters; beyond 12 bits you generally get it for free, especially with breadboard layouts.

        I’d like to see a full-blown datalogger done with the Raspberry Pi. Adafruit sell a 16 bit 4 channel ADC assembled on to a small pcb; four of those taken with a RTC chip would make a very useful 16 channel datalogger which could be run off a 12v battery, reasonably low power and no moving parts (fans, disc drives etc), and wouldn’t tie up a PC. I keep planning to do it myself but never get around to it…..
        RL

        Reply
        • Dave Goldsmith on March 18, 2017 9:48 pm

          I know this post is pretty old, but I’m building a datalogger from a raspberry pi right now. I was using the 3008, but the COTS data logger I’m trying to knock-off had better resolution than my Pi, so I’m trying to adapt the code and switch to the 3208 right now.

          Reply
          • Matt on March 18, 2017 10:16 pm

            I try to keep this post updated as it’s quite popular. Hopefully it will still be useful in your project. Let me know if you hit any issues.

            Reply
      4. Fred Smith on October 28, 2013 12:22 pm

        If i was to follow this project, would it be recommended that i use the exact same LDR and ADC? Thanks for any help, great article!

        Reply
        • Matt on October 29, 2013 1:24 pm

          You could use any LDR. The article deals specifically with the MCP3008 ADC but you could use another … but it would need to be pin compatible and also use the SPI protocol.

          Reply
          • George on December 5, 2013 7:14 pm

            Hi Matt,

            I just tried this with a different LDR, a TEPT5700 Vishay Photodiode, and an IR photodiode.

            For each I used the same circuitry and resistor (10K Ohm) and the results were very much the same.

            The fun begins….

            Reply
      5. Schwabinger on November 10, 2013 3:51 pm

        Cool! I modified your script and now I can use a potentiometer to “tune” my RaspRadio …

        http://mightyohm.com/forum/viewtopic.php?f=2&t=3420

        Thank’s a lot!
        Schwabinger

        Reply
      6. Matt on November 26, 2013 8:39 pm

        Hey what could the problem be if the SPI is only read once in a while…

        It’s always 0 and then suddenly shows the correct value and then 0 again?

        Thanks Matt

        Reply
      7. George on November 28, 2013 10:48 am

        Hi,

        Just wanted to say thanks for posting this.
        Just been and bought one and some ir led + ir photodiodes.

        I’ve previously set up a way to pass morse code from one RPi to another so this would be an ace way to try that out with light.

        George

        Reply
      8. Schwabinger on December 14, 2013 7:23 am

        Hi,

        in my radio project I now use your solution to control two pots (volume, select station) and two push buttons (signal station number, initiate shutdown/reboot).

        http://www.flickr.com/photos/rigasw/sets/72157638612312533/

        Do you know whether it does work as well with Pi Version A?

        Schwabinger

        Reply
        • Matt on December 14, 2013 9:55 pm

          I can’t see why it wouldn’t work with the Model A. The GPIO pins are the same so should be identical to the Model B as far as the MCP3008 is concerned.

          Reply
      9. Schwabinger on December 15, 2013 8:57 am

        Hi,

        thanks for your answer. As I am trying to make my web-radio solar/battery powered, I will get an A model. They are supposed to draw only about 1/3 of energy compared to model B.

        The one existing usb-port will be used for a wlan-adapter.

        Schwabinger

        Reply
        • Matt on December 15, 2013 12:05 pm

          When I did my AA battery tests the power consumption of the Model A was indeed about 1/3 of the Model B. I usually develop on a Model B and then move the card to the Model A when I don’t need the network socket any more.

          Reply
      10. Ton on December 22, 2013 11:39 am

        Hi,

        Thank you for this extensive and very clear explanation. It’s very helpful for a newbie like me.

        Ton

        Reply
      11. Barney Ward on January 6, 2014 11:44 am

        For those of us trying to get to grips with both the Spi interface any Python, could you explain how the bits in the brackets on the two lines calling the spi.xfer2 function and organising the data actually work?:

        adc = spi.xfer2([1,(8+channel)<<4,0])
        data = ((adc[1]&3) << 8) + adc[2]

        The datasheet is pretty complex from a standing start!

        Regards,

        Barney Ward

        Reply
        • each on February 17, 2014 4:09 am

          I too could benefit from a brief breakdown of these lines.

          Reply
        • each on February 19, 2014 1:23 am

          Actually I found a great video that explains it:

          http://m.youtube.com/watch?v=oW0mTwFck_c&feature=g-high-rec

          Reply
          • Matt on February 19, 2014 8:49 am

            That video does explain the numbers quite nicely. Here is a link to the specific point where he explains the 3 bytes :
            http://youtu.be/oW0mTwFck_c?t=31m

            Reply
      12. Pedro on February 2, 2014 10:33 am

        Hi,
        thanks for this post, it’s really interesting!
        But I have one doubt.

        Is it possible to use the MCP3008 and the RPi to monitor a 12V battery voltage?
        And use, for example, a temperature sensor / LDR along with the monitoring of the 12V battery voltage within the same MCP3008?

        How the connections would be for this?
        I would like to manage some renewable energy with the pi (I’m doing it now with a 12F675 ), but in this case I don’ know how, as I need the ground and positive from the battery, and read the MCP with the Pi :/

        Thanks in advance.

        Reply
        • Matt on February 4, 2014 11:36 pm

          I’m sure you could monitor a 0-12V level but you would need to scale the 12V maximum to 3.3V. Perhaps using a simple resistor divider? The MCP3008 has got 8 input channels so you could monitor voltage and a light sensor at the same time.

          Reply
      13. George on February 6, 2014 4:58 am

        I’m following this tutorial and only using a photocell. I’ve eliminated the temperature sensor.

        When I run the python code in idle I always get the same data back
        adc [0 , 3, 255]
        volt 3.3v
        Light 1023

        No matter what I do, I can’t seem to figure out what my problem is.
        The photocell I have has been tested and it works.
        I’ve tried different channels on the mcp3008 and give the same readings.

        My next test is going to be with a potentiometer to see if I can get readings from it.

        Any help would be greatly appreciated.

        Thanks,
        George

        Reply
        • Matt on February 7, 2014 11:59 am

          I would use a potentiometer to feed 0V – 3.3V to an input and see what result that gives.

          Reply
          • George on February 7, 2014 10:49 pm

            I just tried this and the voltage stays at 3.3v

            When I test the Ohms on the pot it comes back with varying resistance like it should.

            This however is not reflected when it is hooked up to the pi.

            Any other thoughts?

            Reply
            • NK on August 4, 2017 4:50 pm

              Hi George,

              I have a similar issue with my setup. 1023 is the constant value I get , don’t know why doesn’t it change. Could you help me do the troubleshooting if you know how to solve the issue now?? Thanks in advance.

              Reply
      14. Michael Horne on February 8, 2014 6:47 am

        Thanks once again for the tutorial. im using it to re-tool the Picorder. 🙂

        Reply
      15. George on February 8, 2014 6:21 pm

        My Full Sized breadboard is actually split in two. I was running 3v on one half and not the other. So the chip was never getting power.

        Rookie mistake….

        Reply
      16. Steve on March 6, 2014 9:41 pm

        Hi. An excelllent tutorial.

        I am only using the temperature part, so have commented out the lines for the light sensor. Everything works fine, but I have two issues:
        1 – The temperature only ever reads in full degrees, even though it’s presented to one decimal place. Am I missing something really obvious? I’d really like to get a more detailed temperature reading.
        2 – I have the tmp36 on about 1m of cable (spare piece of cat5). It seems to be reading 4 to 5 degrees below the known temperature. Presumably the length of cable could be the issue here (I’ve tried two different types of cable with roughly the same result). How would I go about some kind of correction for this?

        I’m hoping these are really simple things that a noob like me has just not seen. I’d really, really appreciate any pointers in the right direction.

        Thanks,
        Steve.

        Reply
        • Matt on March 7, 2014 10:47 am

          Hi Steve,

          You spotted a bug. When dividing by an integer (1023) it forces the output to be an integer. So it loses the decimal points in the calculation. I have wrapped the 1023 value in “float” which now retains the decimal places. These are then rounded to 2 decimal places.

          As for the accuracy I’m not sure as I haven’t used the sensor on a long cable. It could be due to interference on the wire? What if you try a shorter length?

          Reply
          • Dave on September 5, 2014 11:52 pm

            Excellent and well written tutorial, thanks Matt for your time and effort in making this an easy task for the rest of us. I’ve played with the temperature sensor and also have a similar offset. Yet when checking the output from the sensor the voltage is correct to the temperature. A quick bit of googling has lead me to believe that this may be due to the input impedance of the MCP3008 and that some other simple circuitry may be needed to boost the signal from the sensor.

            Reply
            • Ulf on October 6, 2014 8:35 am

              Me to, a capacitor between Vin and Vout on TMP36 solved the offset problem for me.

              Reply
              • Clive on February 10, 2015 9:53 pm

                Hi Ulf. Thanks for this suggestion. I was slowly coming to the conclusion that there might be interference due to length of wire, in my case about 5m. With zero wire length I was, even then, reading about 5C out. With this long wire it is -25C out! If interference is the factor what value of capacitor across Vin and Vout do you suggest? (Do Vin and Vout equate to Din and Dout?)Thanks, Clive.

      17. Steve on March 8, 2014 12:14 pm

        Hi Matt,

        Thanks for the quick reply.

        That all makes sense. I have wrapped the 1023 division with float and now it returns the temperature to two decimal places (just like I’d hope it would). That’s brilliant!

        I’ll experiment with putting the tmp36 directly into the breadboard vs using a length of wire. Annoyingly, I’ve sealed the tmp36 in multiple layers of heat-shrink to make it waterproof. I know I could have used a DS18B20 (which I have one of), but I’ve got another project running on GPIO4 which the 1-wire interface needs to use. Plus I wanted to learn how to use the mcp3008.

        Slowly but surely, it’s all coming together nicely 🙂

        Thanks,
        Steve.

        Reply
      18. Roman on March 27, 2014 10:46 pm

        Hi there,

        I just have a quick question. I am trying to figure out how to amend the “xfer2” and “data =” if I am using the 8-channel 12-bit MCP3208?

        Thank you for your help!

        Roman

        Reply
        • Matt on March 30, 2014 8:51 pm

          I think the data line would become :

          data = ((adc[1]&15) << 8) + adc[2]If your received data is : XXXXXXXX XXXXDDDD ddddddddIt grabs the first 4 bits of the second byte (DDDD), shifts them 8 to the left (to give (DDDD0000). It then adds on the third byte to give DDDDdddddddd. That's your 12 bits.In the calculation to convert the data value into volts you should use 4095 (2^12) rather than 1023 (2^10).I haven't tried this as I don't have an MCP3208 but I think it looks right 🙂

          Reply
      19. Michael Horne on April 14, 2014 1:51 pm

        Found out what happens if you wire it up wrong. Chip = Radiator 😀

        Reply
        • Matt on April 14, 2014 2:19 pm

          I’ve got a few I keep spare in case my central heating breaks down.

          Reply
      20. Simon R on April 17, 2014 3:40 pm

        Hey

        I’m a newbie to raspberry pi and python but I would like to create a project with analog inputs, but I would like them to display real-time in a graph, could anyone give me some help with the code/ other examples of this?

        Thanks a lot

        PS: You created a really good guide that already helped me a lot 😀

        Simon

        Reply
      21. Richard on April 19, 2014 1:36 am

        Hi Matt,
        Wonderful post. I am trying to do the very same thing on my Beaglebone Black. Yes I know that the Black has endless Analog IOs but I’m using the MCP3008 as protection, seeing that the BBB could only take 1.8 volt.
        This is my code so far:

        import Adafruit_BBIO.SPI, time, os
        spi = Adafruit_BBIO.SPI.SPI()
        spi.open (0,0)

        def ReadChannel(channel):
        adc = spi.xfer2([1,(8+channel)<<4,0]) #
        data = ((adc[1]&3) << 8) + adc[2]
        return data

        the rest is the same as yours from here on.

        The problem is I keep getting this error message when I run my program.

        *** glibc detected *** python: double free or corruption (fasttop): 0x0008fbb0 ***

        Can you shed some light? Thanks in advance.

        Reply
        • Terry on May 24, 2015 2:43 pm

          Richard, did you ever get this to work? Trying to do same thing on BeagleBone Black with MCP3008.

          Reply
      22. andrea on May 29, 2014 9:34 pm

        Hi, i’m tryng to misure light but, how could R impact over V in that circuit? V is always 3.3V, because resistance is changing with current so… V is the same 3.3V. Am i wrong?

        Reply
        • Matt on May 29, 2014 11:58 pm

          It forms a voltage divider. If the LDR is 10K then the voltage at the ADC input is 1.65V. If the LDR is a large resistance the voltage is closer to 3.3V. If the LDR is very small the voltage will tend to 0V. So as the resistance changes the voltage will vary between 3.3V and 0V.

          Reply
      23. Jon Seddon on July 24, 2014 9:55 pm

        A few people have asked about the code changes for an MCP3208. You have to change four lines. The first is to send the data earlier to allow time for the greater number of bits in the response:

        adc = spi.xfer2([6+((4&channel)>>2),(3&channel)<<6,0])

        You then have to include the extra bits when calculating the output:

        data = ((adc[1]&15) << 8) + adc[2]

        Finally you have to cope with the extra bits when converting to voltages and temperatures:

        volts = (data * 3.3) / float(4095)
        temp = ((data * 330)/float(4095))-50

        My complete code is available at http://www.jseddon.co.uk/mcp3208_jon.py

        Thanks for a great tutorial – that saved me loads of time.

        Reply
      24. Rich on January 29, 2015 7:04 pm

        Hi, great post, I’ve eventually got mine working thanks to this guide!! :0)

        Just now want to link this to a GUI, ie Glade or WebIOPi.

        Do you, or anyone have any examples of doing this?? I’ve been trying for ages but getting no where. Just basically see a value – temperature in a text box……..??

        Reply
      25. Sopwith on February 1, 2015 8:02 am

        Matt,

        This is a very well written and useful post. I needed to create the exact circuit and your guide helped me get it right.

        Thanks for taking the time to publish this so others like me can really understand what is going on when requiring ADC tools.

        Sopwith

        Reply
      26. Max on February 3, 2015 8:07 pm

        This has stopped working after an RPi firmware update. (It installed today as part of a Raspbian Jessie aptitude update; aptitude upgrade.) Something is wrong with the /dev/spidevx.x devices after that upgrade.
        My solution was to go back to an older kernel/firmware.
        The last working one can be installed by using this:
        rpi-update f74b92120e0d469fc5c2dc85b2b5718d877e1cbb
        gives me: uname -a
        Linux raspberrypi 3.12.36+ #737 PREEMPT Wed Jan 14 19:40:07 GMT 2015 armv6l GNU/Linux
        If anyone knows how this can be made to work in a recent (Raspberry Pi 2 -Ready) Raspbian, please post here and/or amend the blog.
        Cheers,
        Max

        Reply
        • Matt on February 10, 2015 9:56 pm

          I’ve just updated my SPI setup article and appears to work ok now with the latest version of Raspbian. the SPI Python wrapper has been updated and there is a new technique for enabling the SPI kernel module.

          Reply
      27. Olivier on February 5, 2015 3:40 pm

        Hi,

        Here is an comparison between a temperature sensor using the MCP3008 with a TMP36 and the DS18B20 using the A-wire bus : http://www.magdiblog.fr/gpio/gpio-capteurs-de-temperature/

        Reply
      28. Lorik on February 7, 2015 3:35 am

        Nice tutorial, though when I run this code on my pi, the spi.xfer2 line gives me an ‘invalid syntax’ error. Could someone please tell me what I’m doing wrong?
        PS- It seems like I have the spidev module installed
        Thanks in advance

        Reply
      29. Gerrelt on February 7, 2015 10:31 am

        Hi!

        Great tutorial, very clear explanation!

        I want to measure temperature sensors in a car. These sensors ground to the car, so they have only one connector. And they are normally used with 12V.
        Could I use this chip to measure these sensors with a Raspberry Pi?

        Greetings,
        Gerrelt.

        Reply
      30. roberto on February 27, 2015 5:17 pm

        excuse me this SyntaxError: Non-ASCII character ‘\xf3’Error appears not know how to fix

        Reply
        • Matt on February 27, 2015 6:34 pm

          Did you use wget to grab the text file from Bitbucket or did you copy and paste from the webpage? If you copy and paste it sometimes converts spaces into strange ASCII characters.

          Reply
      31. Jack on March 14, 2015 4:29 am

        Could you please explain why you have connected Vdd and Vref to the same input? I am using an AD22100. It takes a 5V input. Does that mean that I will have to use 5V for Vref in the circuit instead of the 3.3 V? And mainly, can I use 2 different rails for dictating 3.3V in the A/D converter and 5 V for the sensor and the Vref?
        Thanks.

        Reply
        • Matt on March 17, 2015 7:24 pm

          Vref sets the voltage range of the inputs so I connected to 3.3V. Vdd is the supply voltage and the MCP3008 runs off 3.3V so I connected it to the same pin. If you are using a Pi you do not want to ever put 5V on the Pi’s GPIO pins. If you power it from 5V and use 5V for Vref I think that would result in 5V outputs. Which is bad. So I would run it off 3.3V. You could assume that if you aren’t going to exceed 85 degrees your sensor will never exceed 3.3V anyway.

          Reply
          • ibuki on April 10, 2015 5:06 pm

            Not sure if this is safe but I was playing with an analog feedback servo which (I think) returns a voltage between 0 and 5V (since I was driving the servo with a 5 V power supply). The feedback voltage gives you the position of the servo. I simply connected the feedback lead to the MCP3008. Since I wasn’t sure what to do with the Vref, I kept it on the 3.3V rail (same as Vdd). It seemed to work just fine. I had two feedback servos hooked up and I calibrated the MCP3008 reading to the position of one of them. Then I could use that reading and mirror the position onto the second servo. I thought it was pretty slick. I’m a newbie so take that fact as a disclaimer.

            Reply
      32. Francisco Saravia on March 26, 2015 2:16 am

        I am just getting started. Could you post a video on how to wire the raspberry pi to the MCP3008. I am a newbie on this.

        Reply
        • Francisco S. on April 4, 2015 3:21 pm

          Disregard my last comment. it worked. I was using an IDE cable. but went for the straight connectors. Perfect thank you !

          Reply
      33. frafri on April 4, 2015 4:30 pm

        How can I output this to a google docs sheet ?
        Thanks !

        Reply
      34. ibuki on April 10, 2015 4:20 pm

        I want to use the MCP3008 but I’m having trouble installing SPI for python 3 onto a Raspberry A+. I’ve gone through the raspi-config and SPI appears to be enabled but after I install the SPI wrapper, my python program does not seem to be able of find it.

        I am using idle3 because I like the interface. Since the GPIO operations need to be done w/ root privileges, I use the terminal and “sudo idle3” to launch idle3. That’s been working well for me until now.

        I found another tutorial that shows how to use the MCP3008 on the generic GPIO pins and got it working just fine. But I would like to learn more about SPI so came here.

        Any help would be much appreciated. Thanks.

        Reply
        • ibuki on April 11, 2015 2:52 pm

          I figured it out…..

          On a whim (and out of frustration), I changed:

          sudo apt-get install python2.7-dev
          to
          sudo apt-get install python3.2-dev

          and

          sudo python setup.py install
          to
          sudo python3 setup.py install

          Now it’s working. So if anyone else has this problem, try that.

          Reply
      35. john on May 12, 2015 6:35 pm

        what if i want to use raspberry pi to display an analog signal with a frequency higher than 1Mhz , mcp3008 can do that job ? or it will be very slow display . what is the best alternatives to use , i mean the ADC .

        Reply
        • Matt on May 22, 2015 8:00 pm

          To be honest the Pi probably isn’t the best choice to measure such a signal. You would have to take accurate measurements at 2MHz+.

          Reply
      36. Yannick on July 7, 2015 6:34 am

        Hi,
        thanks for this nice tutorial.
        For my current application I need to read out two ADCs simultaneously, so I got two MCP3008, one connected to CE0 the other to CE1. Using the spi.open(0,x) command I can address either of them. But how can I read out both of them?
        Checking out the xfer-protocol, it seems there is no address included. Does that mean I have to open and close the spi-connection after reading out either MCP in order to switch to the other one? That seems rather stupid for a bus protocol but I couldn’t come with a working solution yet.
        Any suggestions on how to do that?

        Reply
      37. Mat on July 14, 2015 10:24 am

        Hello,

        When I try to use your code, I ve got this error meassage :

        TypeError: Argument must be a list of at least one, but not more than 4096

        I don’t understand why?

        Do you know how to correct this error ?

        Thanks,
        Mat

        Reply
        • Matt on July 14, 2015 8:09 pm

          What line of the code is the error appearing on?

          Reply
      38. Aysenur on July 23, 2015 12:44 pm

        Hello I am also getting the same error with MAT. Everythin is the same with you bu getting TypeError: Argument must be a list of at least one, but not more than 4096 in the line adc=spi.xfer2([1,(8 + channel)<<4,0]). Read channel function does not work. How can we fix it? Thank you

        Reply
      39. Jay on September 19, 2015 4:39 pm

        Want to say “thank you” for posting this explanation and example. Helped me a lot on my project.

        Reply
      40. Jay on September 19, 2015 8:01 pm

        I’m using MCP3008 to interface to the Raspberry Pi. The MCP Vdd is 3.3V and from the same source as Raspberry Pi. One of the analog inputs to the MCP is from a instrumentation amp (opamp) AD620. I’ve found for my circuit, operating the AD620 (using to interface to load cell) from a 5V works better than from a 3.3V. The analog input swing from the AD620 to the input of MCP3008 is 3.6V max. So to summarize, I’m operating the MCP3008 from 3.3V and one of the analog can reach a max of 3.6V.

        Question:
        1 – Its is safe and going to damage my MCP3008. I’ve gone thru the data sheet and believe it should be safe as MCP3008 operating voltage ranges from 2.7V – 5.0V
        2- I’m interfacing the MCP3008 to Raspberry using SPI’s DIN and DOUT pins. Assuming the circuitry inside of the MCP3008 is separate between analog and digital, I would think the DOUT pin on the MCP will not exceed the max of the Raspberry and damage it.

        Any help would be appreciated.

        Reply
        • Matt on September 21, 2015 4:15 pm

          I think although the voltage range is 2.7-5.0V that is only if it powered with 5V. Even if it worked I suspect it wouldn’t be able to correctly deal with the 3.6V as it would be above the supply voltage. I would add a basic resistor divider to scale the incominbg 3.6V to 3.3V.

          Reply
      41. theresa on November 27, 2015 11:53 am

        hi,
        how can you make the program read more than one channel of the mcp3008??

        Reply
      42. ninad on January 1, 2016 9:14 am

        thanks for guide. I am using LM35 temperature sensor and mcp3008 . I am getting continuous value as 3.3 volts and temp 280 C. Can you please help might be the problem.

        Reply
        • Matt on January 12, 2016 11:44 pm

          Disconnect the sensor and double-check the MCP3008 is working and giving sensible values when you apply 0V and 3.3V to the inputs.

          Reply
      43. Ben on January 27, 2016 10:29 pm

        Hi Matt

        I have replicated this project but it is not working for me. I have followed every instruction and after I compile from the terminal it shows nothing…

        Reply
      44. Mohamed Ali on February 24, 2016 7:46 am

        thankx o lot for this article it help me

        Reply
      45. Jimmy on March 24, 2016 4:22 pm

        why are you dividing by 1023 instead of 1024? check this out: http://www.mathworks.com/help/supportpkg/raspberrypiio/examples/analog-input-using-spi.html?requestedDomain=www.mathworks.com

        Reply
        • Matt on March 24, 2016 4:56 pm

          I think that Mathworks page is wrong. By their own admission 0=0V and 1023=3.3V. So each unit is equal to 3.3/1023.

          A reading of 0000 (lowest) is 0x(3.3/1023)=0V
          A reading of 1023 (highest) is 1023x(3.3/1023)=3.3V

          Using their code when get the maximum reading of 1023 the voltage is calculated as 1023x(3.3/1024)=3.297V.

          Imagine the range is 0-3 rather than the MCP’s 0-1023. 0000=0V and 0003=3.3V. You would divide by 3. Each unit would represent 1.1.
          0000=0x1.1=0V
          0001=1×1.1=1.1V
          0002=2×1.1=2.2V
          0003=2×1.1=3.3V
          You divide your maximum voltage by the maximum value not the total number of values.

          Reply
          • Jimmy on March 24, 2016 7:08 pm

            Thanks for your reply. That make sense 🙂

            Reply
      46. Jonas Ljungberg on March 25, 2016 10:41 pm

        This is great im working on a data logger for my Brothers racecar, was, how would i add a second 3208? using both spi channels to this code?

        Reply
      47. Yosuva on April 26, 2016 4:35 am

        How to check MCP 3008 working or not.because all the time i am getting ldr value as 0

        Reply
        • Matt on July 20, 2016 12:31 pm

          Apply 3.3V to one of the inputs and see if that gives you a reading on the MCP3008.

          Reply
      48. Godbid 張言彬 on April 28, 2016 6:57 am

        The “Additional Explanation of spi.xfer2” part guide me to the MCP3008 datasheet, and I could clearly know what’s going on in the “ReadChannel” function after I saw the FIGURE 6-1 in the datasheet.

        This article is the most approachable tutorial that I’ve searched on Google.

        Thanks a lot !

        Reply
      49. Juan on May 18, 2016 4:35 pm

        Thank you for this very detailed and clear tutorial. I tried with a raspberry pi 3, and it works perfectly.

        Reply
      50. Ernie on July 29, 2016 6:59 am

        How do I save the data to a file?

        Reply
      51. Ezgi on August 22, 2016 5:33 pm

        Hi Matt thanks for your tutorial.
        I am using MCP3008 with Raspberry pi and an analog vibration sensor. i wire up all the cables as you depict in your project but when i run the code i am just getting the values in the range of 500-550. Interesting thing is: when i touch the sensor, the voltage should increase, but it doesnt. I mean it remains same, whether i touch or not. I am using CH0 for getting the voltage, but , when i play with the sensor, the CH1 values are changing ? Is it weird ? Is it possible to get the values from CH1, while the sensor is wired CHO ?

        Reply
        • Matt on August 23, 2016 9:22 pm

          It depends on what voltage range the vibration sensor outputs. The MCP3008 will measure a 0-3.3V range. What is the range from the sensor? If you have nothing connected to the other channels ignore them. They will just be measuring random noise/interference. Tie them to ground and they will read 0.

          Reply
      52. Husen on September 4, 2016 10:34 am

        Hai Matt thanks for the tutorial
        how to use mcp3008 and & LDR to get the value light intensity in lux ?

        Reply
        • Wayne on November 22, 2016 6:45 pm

          This works relatively well for me. its probly not 100% accurate but for my purpose its fine.

          # Function to approx LUX with 10k ldr & 10k pull up @ 3.3v
          # data is the value from the mcp3008
          def ConvertLux(data,places):
          result = data
          vin = 3.3
          vout = float(result)/1023 * vin
          resOut = 10000/((vin/vout)-1)
          resOut = float(5e9) * (math.log10(resOut)**-12.78)
          resOut = float(“%.2f” % resOut)
          return resOut

          Reply
        • Miguel on April 2, 2017 2:19 pm

          Hi Husen! Could you find out how to get the value light intensity in lux? I’m working on a project that has a lot to do with this one and it would be very useful for me to show it in lux, thanks!!

          Reply
          • Matt on April 8, 2017 9:14 pm

            I think the only way to get a reading in LUX is to a) use a sensor that has been calibrated to give a known value for a known LUX level or b) use a light meter to measure what values your sensor gives at set LUX levels.

            Reply
      53. CRJ Charles on October 21, 2016 7:48 pm

        Thank you very much for this post. Ive just made one using a Pi3 for logging voltage on a piece of equipment in our lab, to check for drift over many days. I modified the code to save data as a txt file as it acquires — a trivial python add-on. Also modified the Pi3 to bootup and start the script directly, so no need for a keyboard or monitor. Your build as described here worked perfectly on the first try, and gave a high level of detail that was easily replicated. Again, thank you for this very helpful project tip.

        Reply
      54. Edgar on November 10, 2016 7:16 pm

        Hi! Great tutorial, thx for that!

        There’s a little error in the calculation, though: You’d need to divide by 1024, not by 1023 (resp. 4096 if using a MCP3208)

        Reply
        • Matt on November 21, 2016 8:07 pm

          There is a debate over this. I think it is be 1023. 0V gives a reading of 0. 5V gives a reading of 1023. When feed in a pure 5V you get a reading of 1023. You would then multiplying by (5/1024) which gives you a voltage of 4.995 not 5V. Dividing by 1023 gives you 5V.

          Reply
      55. Raj Gandhi on June 18, 2017 4:26 pm

        what is the input given to the CLK pin of the IC
        It was never mentioned in the code

        Reply
        • Matt on June 30, 2017 10:27 pm

          The CLK pin is part of the SPI interface. So it is controlled by the SPI library so you won’t see any reference to it in my code.

          Reply
      56. Matthew Najmon on February 18, 2018 8:45 pm

        I tried to follow along on my own Pi, but when I started entering your python code into IDLE, I got as far as “import spidev”, and got an error stating that no such library was available to be imported. How do I get that library and add it to my Pi so that I can resume learning what this tutorial has to teach?

        Reply
        • Matt on February 19, 2018 10:43 am

          You need to follow the link at the beginning to the “Enable SPI interface” tutorial. This includes a step on installing the spidev library.

          Reply
      57. Walter Phipps on February 26, 2018 12:07 pm

        Thank you. After many attempts with other websites over a few years your line for the Python Spi wrapper in the “Enable SPI interface” tutorial finally allowed me to install “spidev” correctly:
        sudo apt-get install python3-spidev python-spidev
        Without it “import spidev” always caused a fault! I have no idea yet where the 2 modules are stored but, with that line & your Python code on this page, the Spi & Mcp3008 are communicating.

        Reply
      Leave A Reply Cancel Reply

      This site uses Akismet to reduce spam. Learn how your comment data is processed.

      Recent Posts
      February 16, 2024

      Disable SSH Password Login on Raspberry Pi

      March 13, 2023

      Elecrow Meteor IPS Touchscreen with RGB LEDs

      December 26, 2022

      Pi Pico Pinout Display on the Command Line

      December 23, 2022

      How to Add a Raspberry Pi Pico Reset Button

      November 20, 2022

      Pi Pico Onboard LED

      Categories
      • 1-wire
      • 3D Printing
      • Add-ons
      • BBC Micro:bit
      • BerryClip
      • Books
      • Camera Module
      • Cases
      • Events
      • General
      • Hardware
      • I2C
      • Infographics
      • Interfaces
      • Minecraft
      • Model A+
      • Model B+
      • News
      • Pi Models
      • Pi Pico
      • Pi Zero
      • Power
      • Programming
      • Python
      • Raspberry Pi OS
      • Raspbian
      • RetroGaming
      • Robotics
      • Sensors
      • Software
      • SPI
      • Tutorials & Help
      Tags
      Arduino audio battery berryclip Birthday bluetooth cambridge camera CamJam DigiMakers display games GPIO I2C interface Kickstarter Kodi LCD LED Linux media Minecraft Model A motionEyeOS PCB photography photos Pi-Lite Pi Pico power python Raspberry Jam Raspberry Pi Bootcamp raspbian Retrogaming retroPie screen SD card security sensor SPI SSH temperature ultrasonic video
      Raspberry PI Related
      • Adafruit Blog
      • Average Maker
      • Official RaspBerry Pi Site
      • Raspberry Pi Pod
      • RasPi.tv
      • RaspTut
      • Stuff About Code
      Tech Resources
      • MattsBits – Pi Resources
      • Microbit Spy
      • Technology Spy
      Archives

      Entries RSS | Comments RSS

      This site is not associated with the official Raspberrypi.org site or the Raspberry Pi Foundation. Raspberry Pi is a trademark of the Raspberry Pi Foundation.

      Copyright © 2025 - All Rights Reserved - Matt Hawkins

      About

      Unofficial site devoted to the Raspberry Pi credit card sized computer offering tutorials, guides, resources,scripts and downloads. We hope to help everyone get the most out of their Pi by providing clear, simple articles on configuring, programming and operating it.

      Popular Posts
      September 19, 2014

      Top 5 Reasons The Raspberry Pi Sucks

      July 27, 2012

      16×2 LCD Module Control Using Python

      October 20, 2013

      Analogue Sensors On The Raspberry Pi Using An MCP3008

      Latest Posts
      February 16, 2024

      Disable SSH Password Login on Raspberry Pi

      March 13, 2023

      Elecrow Meteor IPS Touchscreen with RGB LEDs

      December 26, 2022

      Pi Pico Pinout Display on the Command Line

      Mastodon YouTube Instagram Facebook Pinterest RSS

      Entries RSS | Comments RSS

      This site is not associated with the official Raspberrypi.org site or the Raspberry Pi Foundation. Raspberry Pi is a trademark of the Raspberry Pi Foundation.

      Copyright © 2025 - All Rights Reserved - Matt Hawkins

      mastodon.social@RPiSpy

      Type above and press Enter to search. Press Esc to cancel.