text: #!/usr/bin/python
  import RPi.GPIO as GPIO
  
  class MCP3208(object):
      '''Python driver for [MCP3208 12-bit Analog-to-Digital Converter](http://www.microchip.com/downloads/en/DeviceDoc/21298e.pdf)
       Requires:
       - The [GPIO Library](https://sourceforge.net/projects/raspberry-gpio-python/) (Already on most Raspberry Pi OS builds)
       - A [Raspberry Pi](http://www.raspberrypi.org/)
  
      '''
      def __init__(self, cs_pin, clock_pin, data_in_pin, data_out_pin, board = GPIO.BCM):
          '''Initialize Soft (Bitbang) SPI bus
  
          Parameters:
          - cs_pin:    Chip Select (CS) / Slave Select (SS) pin (Any GPIO)  
          - clock_pin: Clock (CLK / SCK) pin (Any GPIO)
          - data_in_pin:  Data input (to RPi) (DOUT(MCP3208) / MISO) pin (Any GPIO)
          - data_out_pin:  Data output (from RPi) (DIN(MCP3208) / MOSI) pin (Any GPIO)
          - board:     (optional) pin numbering method as per RPi.GPIO library (GPIO.BCM (default) | GPIO.BOARD)
  
          '''
          self.cs_pin = cs_pin
          self.clock_pin = clock_pin
          self.data_in_pin = data_in_pin
          self.data_out_pin = data_out_pin
          self.data = None
          self.board = board
  
          # Initialize needed GPIO
          GPIO.setmode(self.board)
          GPIO.setup(self.cs_pin, GPIO.OUT)
          GPIO.setup(self.clock_pin, GPIO.OUT)
          GPIO.setup(self.data_in_pin, GPIO.IN)
          GPIO.setup(self.data_out_pin, GPIO.OUT)
  
          # Pull chip select high to make chip inactive
          GPIO.output(self.cs_pin, GPIO.HIGH)
  
          # Initialise clock low and data out high
          GPIO.output(self.clock_pin, GPIO.LOW)
          GPIO.output(self.data_out_pin, GPIO.HIGH)
  
      def get(self, channel = 0):
          '''Read one value from one channel
  
          Parameters:
          - channel:    The channel to read, default 0  
  
          '''
          if channel > 7 or channel < 0:
              raise MCP3208Error('MCP3208 channel out of range: ' + str(channel))
          # Ensure data out is high
          GPIO.output(self.data_out_pin, GPIO.HIGH)
          
          # Select the chip
          GPIO.output(self.cs_pin, GPIO.LOW)        
  
          # Start bit
          GPIO.output(self.clock_pin, GPIO.LOW)
          GPIO.output(self.data_out_pin, GPIO.HIGH)
          GPIO.output(self.clock_pin, GPIO.HIGH)
  
          # Define single ended measurement
          GPIO.output(self.clock_pin, GPIO.LOW)
          GPIO.output(self.data_out_pin, GPIO.HIGH)
          GPIO.output(self.clock_pin, GPIO.HIGH)
  
          # Define the measurement channel
          # D2
          GPIO.output(self.clock_pin, GPIO.LOW)
          if (channel & 4) == 0:
              GPIO.output(self.data_out_pin, GPIO.LOW)
          else:
              GPIO.output(self.data_out_pin, GPIO.HIGH)
          GPIO.output(self.clock_pin, GPIO.HIGH)
          
          # D1
          GPIO.output(self.clock_pin, GPIO.LOW)
          if (channel & 2) == 0:
              GPIO.output(self.data_out_pin, GPIO.LOW)
          else:
              GPIO.output(self.data_out_pin, GPIO.HIGH)
          GPIO.output(self.clock_pin, GPIO.HIGH)
          
          # D0
          GPIO.output(self.clock_pin, GPIO.LOW)
          if (channel & 1) == 0:
              GPIO.output(self.data_out_pin, GPIO.LOW)
          else:
              GPIO.output(self.data_out_pin, GPIO.HIGH)
          GPIO.output(self.clock_pin, GPIO.HIGH)
         
          # Sample and hold period
          GPIO.output(self.clock_pin, GPIO.LOW)
  
          GPIO.output(self.clock_pin, GPIO.HIGH)
          
          # Null bit
          GPIO.output(self.clock_pin, GPIO.LOW)
  
          GPIO.output(self.clock_pin, GPIO.HIGH)
          
          bytesin = 0
          # Read in 12 bits
          for i in range(12):
              GPIO.output(self.clock_pin, GPIO.LOW)
              bytesin = bytesin << 1
              if (GPIO.input(self.data_in_pin)):
                  bytesin = bytesin | 1
              GPIO.output(self.clock_pin, GPIO.HIGH)
          # Unselect the chip
          GPIO.output(self.cs_pin, GPIO.HIGH)
          # Save data
          return bytesin
  
      def cleanup(self):
          '''Selective GPIO cleanup'''
          GPIO.setup(self.cs_pin, GPIO.IN)
          GPIO.setup(self.clock_pin, GPIO.IN)
          GPIO.setup(self.data_out_pin, GPIO.IN)
  
  class MCP3208Error(Exception):
       def __init__(self, value):
           self.value = value
       def __str__(self):
           return repr(self.value)
  
  