Wednesday, 25 March 2015

Single LED with Transistor - Flashing

Going on from my previous post of a flashing LED. Here I have introduced an NPN transistor, as in later projects I will be using them to control LED segments, namely 7 segment LED displays.

A transistor has three pins. A base, collector and emitter. A small current at the base control's the switching of current from the collector to the emitter of the transistor. 

The ingredients:
  • 1 x LED (Any colour)
  • 1 x resistor (round the 250ohm mark)
  • 1 x NPN Transistor (2N3904)
  • A few jump wires

Layout


Here we have connect 5v from GPIO 2 to the collector pin on the transistor (Red Wire). Then we connected the base pin on the transistor to GPIO 25 (Yellow Wire) to control the switching. And then from the emitter pin on the transistor, we attached a resistor and then connected that to the anode pin on the LED and in turn connected the cathode pin on the LED to the ground on the Pi (Black Wire).

The Code

Using basically the same code as in the previous project :

import RPi.GPIO as GPIO
import time

GPIO.setwarnings(False)

GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.OUT)

while True:
    GPIO.output(25, True)
    time.sleep(1)
    GPIO.output(25, False)
    time.sleep(1)

This now loops and every second gives a current to the base pin on the transistor via GPIO 25. This causes a current to flow from the collector to the base pins on the transistor intermittently every second, which in turn makes the LED flash on and off

Monday, 9 March 2015

Single LED - Flashing


In this series I am going to play around with LED's. These simple devices are just great to learn the basic's and even some advanced electronics.

This specific one is quite a simple one. Basically just making an LED switch on and off. Once again using the Rasperry Pi and its GPIO pins.

The ingredients:
  • 1 x LED (Any colour)
  • 1 x resistor (round the 250ohm mark)
  • A few jump wires

Layout


Here we connect a jump lead (Red) from one of the GPIO Pins (18 in this case) to a resistor which in turn is connected to the anode (positive) end of the LED. The Cathode (negative) end of the LED is then connected to Ground, by the black jump lead.

The Code

import RPi.GPIO as GPIO
import time

GPIO.setwarnings(False)

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)

while True:
    GPIO.output(18, True)
    time.sleep(1)
    GPIO.output(18, False)
    time.sleep(1)

Monday, 9 February 2015

Controlling an LCD Display with Python

With this Project I am going to talk about controlling an LCD display. Both the 16x2 and 20x4, as they share a common interface. They are the HD44780 chipset, and the 1602 and the 2004 models respectively. They also come in different coloured back lit options.

These are very cheap and east to come by. For about £3 and £6 on eBay you can get these quite easily. They are great if you want to have you Pi start outputting simple things to a screen of some sort and not just the console (If you are running it headless like I am)

This is what you need to get going (Ingredients):
  • 1 x Raspberry Pi
  • 1 x 10K Pot
  • 1 x LCD Screen (In this example I will mainly be using the 16x2)
  • A whole lot of Jump Wires

Pi Layout with LCD Screen


The LCD screen pin layout is from left to right (1 to 16). This is the table to explain each pin:

Pin Label Value Explanation
1 Vss 0V Ground
2 Vdd 5V Supply voltage for Logic Board - NOT 3.3V
3 Vo 0V Contrast Adjustment - Can be but on a pot but best to connect direct
to Ground for full visibility
4 RS H/L Register Select, H=Data, Low=Command
5 R/W H/L Read/Write Mode. H=Read Mode, Low=Write Mode. Connected to ground
so that it is always in Write Mode
6 E H,H->Low Chip Enable Signal / Clock Enable
7 DB0 H/L Data Bit 0 (Not Used in 4-bit operation)
8 DB1 H/L Data Bit 1 (Not Used in 4-bit operation)
9 DB2 H/L Data Bit 2 (Not Used in 4-bit operation)
10 DB3 H/L Data Bit 3 (Not Used in 4-bit operation)
11 DB4 H/L Data Bit 4
12 DB5 H/L Data Bit 5
13 DB6 H/L Data Bit 6
14 DB7 H/L Data Bit 7
15 A +V Back Light Anode
16 K -V Back Light Cathode

As you can see we connected these to the standard GPIO ports on the Pi (Though all of them can be set as GPIO ports - some have more specific uses that others and if you are connecting other things to these type of interfaces while using the LCD screen, then these ports are probably the best to use). All GPIO ports on the Pi can be set in to two states. They can be represented as these:
  • True / False
  • 1 / 0
  • High / Low (Which is what we showed in the table above)
One other thing to make note of, is that there are timings involved in sending commands to the LCD. There needs to be a "pause" between certain commands (Which we will come to next) in order to allow the device to switch from one mode to another. This pause is a fraction of a second, but is needed for the LCD to operate correctly.

As you can see we also do not need to use all the DB pins to control the LCD Screen. We will utilise this ability as we don't want to use every single GPIO Port on the Pi. So using 4 GPIO ports will allow us to control the LCD. But in doing so when we send information to the LCD Screen we need to send the data in 2 separate 4 bit chunks, known as nibbles. A high nibble and a low nibble. This will be explained a little further on.

The Python bits

Now comes the fun part of controlling the LCD screen.

To make use of the GPIO ports in Python we need the RPi.GPIO module.
import RPi.GPIO as GPIO
While importing the module we instantiate the RPi.GPIO Class as GPIO. Makes for easier coding.

As there are timings involved we also need:
import time
Lets now define some of the GPIO to LCD Mappings:
LCD_RS = 22
LCD_E  = 4
LCD_D4 = 25
LCD_D5 = 24
LCD_D6 = 23
LCD_D7 = 18
Next lets define some device constants:
LCD_WIDTH = 16      # Maximum characters per line
LCD_CHR = True      # Register Select to Accept Characters
LCD_CMD = False     # Register Select to Accept Commands

LCD_LINE_1 = 0x80   # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0   # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94   # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4   # LCD RAM address for the 4th line
As you can see I have shown 4 lines, but the 16x2 and the 20x4 share the same chipset and therefore some of the settings cross over. LCD_WIDTH can be set to 20 if you are going to be doing work on the 20x4 LCD screens.

These are the Timing Constants I spoke about earlier:
E_PULSE = 0.00005
E_DELAY = 0.00005
Next are the constants for each position on the display (This comes in useful when you want to place characters directly in certain positions)
LINE_1_16x2 = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 
        0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]
LINE_2_16x2 = [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 
        0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F]

LINE_1_20x4 = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 
        0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 
        0x12, 0x13]
LINE_2_20x4 = [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 
        0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 
        0x52, 0x53]
LINE_3_20x4 = [0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 
        0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 
        0x26, 0x27]
LINE_4_20x4 = [0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5b, 0x5C, 
        0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 
        0x66, 0x67]
 In order to use the GPIO pins we need to initialize them :
def set_gpio():
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)          # Use BCM GPIO numbers
    GPIO.setup(LCD_E, GPIO.OUT)     # E
    GPIO.setup(LCD_RS, GPIO.OUT)    # RS
    GPIO.setup(LCD_D4, GPIO.OUT)    # DB4
    GPIO.setup(LCD_D5, GPIO.OUT)    # DB5
    GPIO.setup(LCD_D6, GPIO.OUT)    # DB6
    GPIO.setup(LCD_D7, GPIO.OUT)    # DB7
Let me explain a couple of things that the above procedure does.

  • GPIO.setwarnings(False) makes sure that if there were any previous GPIO settings from a previous running of the code, all warnings will be ignored.
  • GPIO.setmode(GPIO.BCM) tells the code how we will talk to the GPIO Pin Layouts. GPIO.BCM means we are going to use the specific labeling of the Pi (Not the exact locations of the pins). Not all the GPIO pin labels are in the actual board pin layout. To have the it the other way and use the specific pin number you need to use GPIO.BOARD
  • GPIO.setup(....., GPIO.OUT) sets the GPIO pins into an output mode. Therefore no data can be received by them. Of course you could have IN, but for this project all we are doing is sending data to the LCD display.
Next we can now initialize the LCD display, seeing that the GPIO ports have been set correctly, we can now send data to the LCD Display :
def lcd_init():
    send_data(0x30, LCD_CMD)    # Initialize
    send_data(0x28, LCD_CMD)    # Set 4-bit mode, 2 line, 5x7 matrix
    send_data(0x0F, LCD_CMD)    # Display On, set cursor underling and blinking
    send_data(0x06, LCD_CMD)    # Character entry increment, Display shift off
    send_data(0x01, LCD_CMD)    # Clear Screen


def send_data(instr, rs_mode):
    # Send byte to data pins
    # instr = data set to send
    # rs_mode = Register Select :
    #               True  for character
    #               False for command

    GPIO.output(LCD_RS, rs_mode)

    set_data_pins()             # Reset pins to False
    send_data_to_pins('high', instr)
    commit_data()
    set_data_pins()             # Reset pins to False
    send_data_to_pins('low', instr)
    commit_data()


def set_data_pins():
    GPIO.output(LCD_D4, False)
    GPIO.output(LCD_D5, False)
    GPIO.output(LCD_D6, False)
    GPIO.output(LCD_D7, False)


def send_data_to_pins(state, nibble):
    if state == 'high':
        if nibble & 0x10 == 0x10:
            GPIO.output(LCD_D4, True)
        if nibble & 0x20 == 0x20:
            GPIO.output(LCD_D5, True)
        if nibble & 0x40 == 0x40:
            GPIO.output(LCD_D6, True)
        if nibble & 0x80 == 0x80:
            GPIO.output(LCD_D7, True)
    elif state == 'low':
        if nibble & 0x01 == 0x01:
            GPIO.output(LCD_D4, True)
        if nibble & 0x02 == 0x02:
            GPIO.output(LCD_D5, True)
        if nibble & 0x04 == 0x04:
            GPIO.output(LCD_D6, True)
        if nibble & 0x08 == 0x08:
            GPIO.output(LCD_D7, True)


def commit_data():
    time.sleep(E_DELAY)
    GPIO.output(LCD_E, True)
    time.sleep(E_PULSE)
    GPIO.output(LCD_E, False)
    time.sleep(E_DELAY)
Lets look at the following table to see why we have used the Hex Codes that we see above. Afterwards I will try and explain the ins and out of the code:


Command Binary Hex
D7 D6 D5 D4 D3 D2 D1 D0
Clear Display 0 0 0 0 0 0 0 1 01
Display & Cursor Home 0 0 0 0 0 0 1 x 02 or 03
Character Entry Mode 0 0 0 0 0 1 I/D S 04 to 07
Display On/Off & Cursor 0 0 0 0 1 D U B 08 to 0F
Display/Cursor Shift 0 0 0 1 D/C R/L x x 10 to 1F
Function Set 0 0 1 8/4 2/1 10/7 x x 20 to 3F
Set CGRAM Address 0 1 A A A A A A 40 to 7F
Set Display Address 1 A A A A A A A 80 to FF
I/D: 1 =Increment*, 0=Decrement
S: 1=Display shift on, 0=Display shift off*
D: 1=Display On, 0=Display off*
U: 1=Cursor Underline on, 0=Underline off*
B: 1=Cursor blink on, 0=Cursor blink off
D/C: 1=Display shift, 0=Cursor move
R/L: 1=Right shift, 0=Left shift
8/4: 1=8 bit interface*, 0=4 bit interface
2/1: 1=2 line mode, 0=1 line mode*
10/7: 1=5x10 dot format, 0=5x7 dot format*

x = Don't care * = Initialisation settings

In my Python code I have created 5 separate procedures to cater for the different processes needed to talk to the LCD screen:


  • lcd_init() - This is used to initialise the LCD screen. Get it into a state where it is ready to accept inputs in the format we are going to send to it.
  • send_data(instr, rs_mode) - This basically sends data to the pins. That data can be either commands for the device itself or characters to be displayed. 
    • By setting rs_mode True, for sending a character, and False, for sending a command, on the RS GPIO pin you can can set the LCD to that specific mode.
    • instr is the hex code for the specific commands or characters to be sent
    • As you can see in there we reset the pins by calling set_data_pins(). This must be done before each transfer of data
    • Because we are running in 4 bit mode we call send_data_to_pins twice for each 4 bit nibble. high for the first 4 bits, and low for the next 4 bits. 
    • commit_data is called to then commit the data set on the pins
  • set_data_pins() - As just previously mentioned, sets all the data pins to a False, or Low state (not to be confussed with the low nibble that gets sent). This makes sure the the GPIO pins are cleared and hold no residual state from a previous execution.
  • send_data_to_pins(state, nibble) - This procedure takes the state of the 8 bit (Hex Code) to determine which part of this 8 bit block it should work with (The nibble). The conditional statements use bitwise operators to determine which bits are valid for that specific nibble and therefore set the corresponding GPIO pin to its correct state.
  • commit_data() - This is the last part of the code that then tells the LCD display that there the data pins have been set and to take their states as part of the command or character that is being sent. Delays are needed to give the LCD enough time to make sure these states are read correctly. the E pin is set to High, this tells the LCD to read the Pin states, then it is set back to Low so it can wait for the next piece of the command.

Making Text appear

Now all this is out of the way we can now write things to the screen:
def set_line(line_number):
    if line_number == 1:
        send_data(LCD_LINE_1, LCD_CMD)
    elif line_number == 2:
        send_data(LCD_LINE_2, LCD_CMD)
    elif line_number == 3:
        send_data(LCD_LINE_3, LCD_CMD)
    elif line_number == 4:
        send_data(LCD_LINE_4, LCD_CMD)


def lcd_string(message, line_number):
    set_line(line_number)

    message = message.ljust(LCD_WIDTH, " ")

    for i in range(LCD_WIDTH):
        send_data(ord(message[i]), LCD_CHR)

#################################################################
set_gpio()
lcd_init()
scroll_text()

lcd_string("Hello", 1)
lcd_string("World", 2)

  • set_line(line_number) procedure takes the line number you wish to write on and send the command to the LCD Screen telling it that what ever we send next must be written to that line using the send_data procedure.
  • lcd_string(message, line_number) procedure takes the string to be displayed loops through the string, one character at a time. This is necessary as each character needs to be sent to the display individually. the ord function turns the character into its equivalent hex code, which is what is needed for the LCD display. The table below shows all the characters with their corresponding 4 bit (high / low) nibbles.

Conclusion

I hope this post has been helpful to you. There are more advanced things you can do, like creating your own characters and placing them in the CGRAM section, but that is for another post.

Here is a great reference that I gleaned a lot of information out of :

Tuesday, 3 February 2015

MCP3008 with a 10K Pot on Raspberry Pi using SPI GPIO Pins and Python

As mentioned in my previous post, on the MCP3002 (2 Channel - Analogue to Digital Converter), here is the setup for the MCP3008 (8 Channel - Analogue to Digital Converter). Much of it is a repeat of what I have posted in there, but to help you from bouncing to and fro trying to get it all out, I have put it altogether here.


The board layout

This is what you will need (ingredients):
  • 1 x Rasperry Pi
  • 1 x Breadboard
  • 1 x 10K Pot
  • 1 x 10uf Capacitor
  • And a few jump cables
Here is the setup I have :




  • GPIO 1 (3.3v) -> + Breadboard (3.3v)
  • GPIO 6 (Ground) -> - Breadboard (Ground)
  • 10uf Capacitor -> One pin in line with MCP3008 Pin 16, Other Pin to Ground
  • MCP3008 Pin 16 (Vdd) -> + Breadboard (3.3v)
  • MCP3008 Pin 15 (Vref) -> + Breadboard (3.3v)
  • MCP3008 Pin 14 (AGND) -> - Breadboard (Ground)
  • MCP3008 Pin 13 (CLK) -> GPIO 11 (SPIO_SCLK)
  • MCP3008 Pin 12 (Dout) -> GPIO 9 (SPIO_MISO)
  • MCP3008 Pin 11 (Din) -> GPIO 10 (SPIO_MOSI)
  • MCP3008 Pin 10 (CS) -> GPIO 8 (SPIO_CE0_N)
  • MCP3008 Pin 9 (DGND) -> - Breadboard (Ground)
  • MCP3008 Pin 1 (CH0) -> Center pin of 10K Pot
  • MCP3008 Pin 2-7 (CH1-8) -> Not connected
  • 10K Pot Pin 1 -> + Breadboard (3.3v)
  • 10K Pot Pin 3 -> - Breadboard (Ground)

The Python Code

Now here is the cool part. The python code needed to get all the information out :
import spidev
import time

channel = 0
spi = spidev.SpiDev()
spi.open(0, 0)

while True:
    result = spi.xfer2([1, (8 + channel) << 4, 0])
    digital_code = int(((result[1] & 3) << 8) + result[2])
    voltage = round(((digital_code * 3.33) / 1024), 2)
    print voltage
    time.sleep(0.5)
And this is where things need a little explaining. Why do we use the values we do in the function's list to communicate with the MCP3002 ? What and why we use the bit manipultion ?

spidev is the module needed to allow python to talk through the SPIO pins. From a console run the following :
sudo apt-get install spidev

Initialization

spi.open(0, 0) -> Open SPIO Port 0 with CS 0. Basic initialization of the SPIO Pins on the Raspberry Pi. This tells the Pi to communicate down SPIO Port 0, which is attached to the CS (Channel Select) pin on the MCP3002. This tells the MCP3002 it needs to return information from CH0 (Channel 0) pin. If you had the pot on CH1 and connected to GPIO 7 (SPIO_CE1_H) then you would have code - spi.open(1, 1). And so if you wanted to get info from any other channel from 2 to 7 the second digit in the list correspond to that channel number.


Transmitting Data

spi.xfer2([..., ..., ...]) -> Now this is an interesting function that had me trying to understand what was being put in that list. Many sites I looked at had different values, but none really explained how they got these values, but through a little bit of maths and base conversions I found it out. With an MCP3008 you need to put in 3 list values to get a result. Have a look at this taken from the MCP3008 Datasheet :



Let me try and explain it the best I can in which made me figure out the workings of the IC. Don't worry too much about falling and rising of edge of clock. We are more looking at the bits that need to be transferred/received to/from the device. This IC works with 8 bit blocks (a byte if you wish). From this we can see that what needs to transferred to the device to get a response is three sets of 8 bits. In the first block of 8 bits (MCU Transmitted Data) we need to send a start bit. This is just a value of 1. The next (second) block of 8 bits is some information to tell the IC how it should work for us. The MCP3008 is a little simpler than the MCP3002. This table shows what is needed :


Bit Value Explanation
SGL/DIFF
1/0
1 - To select Single Ended Mode (This is the mode we will use)
0 - To select Pseudo Differential Mode
D2/D1/D0
0/1
Channel Selection. Each of these bits put together gives the equivalent decimal channel number once converted

To decide on the channel we need to do a little binary conversion. This Table should Help you out with that :


D2 D1 D0 Channel
0
0
0
CH0
0
0
1
CH1
0
1
0
CH2
0
1
1
CH3
1
0
0
CH4
1
0
1
CH5
1
1
0
CH6
1
1
1
CH7


So the bits, in order, that we need are a four bit value that needs to shifted to the left by 4 to make it 8 bits. The first bit in 4 bit number is going to be 1 (SGL/DIFF). And therefore being the first bit in the four bits needed it will be 1000 which is converted to a decimal value of 8. No we need to add onto that the channel we decided to use. So using CH0 in my example it would be still be 1000. If say for example it was CH3 the four bit digit would be 1011. Now we shift it over to the left by 4 using the bit operator  <<. We get the function 
       (8 + channel) << 4

On the third set of 8 bits that get sent. Looking at the same excerpt above we can see that what ever is put in there is ignored. So we just send a Decimal value of 0 (00000000 - in binary).

So now you see how we get 1, (8 + channel) << 4, 0 

Receiving Data

As you can see result receives the information that spi.xfer2[(1, (8 + channel) << 4, 0]) sends.

This is also returned as a list. The reason for this can once again be seen in the excerpt above (MCU Received Data). Three blocks of 8 bits. The first block is ignored and is not relevant to the calculation even if it has anything in it. The second block holds 2 bits of the final code and the third block holds the last 8 bits of the code. The total final resulting code is actually a 10bit number. These two blocks of 8 bits are returned as to values in a list (result) which we need to bung together to produce the digital_code.

How we do this requires a little Bit Manipulation. Which we just saw in sending data to the device.

Lets look at the code to do this conversion. int(((result[1] & 3) << 8) + result[2])

The second block we see that only the last 2 bits are needed, though the device could send back more. This is position 1 in the list of result. Therefore result[1]. Using the Bitwise operator & with the decimal value of 3 which has a binary of 11 to make sure that we only get the last 2 bits. Here is a few examples to show what the & operator does:


  • 1010 & 0011 = 0010
  • 1001 & 0011 = 0001
  • 0111 & 0011 = 0011
So with the final value of result[1] & 3 we now need to shift it 8 places to the left to make space for the next 8 bits that need to be added to it (Basically add 8 zero's to the end of the binary number). That is what << 8 does. Here are a few examples to explain this :
  • 11 << 8 = 1100000000
  • 01 << 8 = 0100000000
  • 10 << 8 = 1000000000

Now that we have taken the two bits out, and shifted it over by 8 we now add the final number in the list, result[2], to it. This gives us a final decimal number that is the digital_code.


Calculating the voltage

Once we have the digital_code we now need to do a simple calculation to convert that number into the voltage that is being returned by the pot. This is taken from the MCP3008 documentation :

So what we need to find is Vin. We know Vdd is 3.33v (Tested on a volt meter). And we know what the digital_code is. Then, with a little manipulation of the algorithm, we get (digital_code * 3.33) / 1024). using the round function we round it off to two decimal places and therefore get the final calculation of  round(((digital_code * 3.33) / 1024), 2).

Conclusion

At the end of all this we a voltage that is returned by the pot. This comes in useful for things like temperature sensors that produces a resistance relevant to the temperature. Producing this resistance lowers the voltage. This final voltage can be used to calculate what the temperature is actually being sensed by the sensor.

I hope this has help you as much as possible. If you have any questions feel free to post it and I will endeavour to answer it the best I can.




Monday, 2 February 2015

MCP3002 with a 10K Pot on Raspberry Pi using SPI GPIO Pins and Python

This project I decided to work with the SPI GPIO ports on the Pi. Part of the kit I had bought for the Pi had an MCP3002 IC . This is a very common ADC (2 Channel - Analogue to Digital Converter). This is a very useful IC to connect to temperature sensors (or anything that change the voltage), which can output a voltage that is related to the temperature (a conversion needs to be done, but we will get to that later)

I sat for weeks trying to understand how this device works and for the life of me a I could not find a site that explained what their code was actually doing. Till one day I sat down with a pen and paper and a Binary to Hex and Decimal converter. I finally figured it out and thought I would right this blog to help anyone else out there that may be in the boat and almost give up with dispair.


The board layout

This is what you will need (ingredients):
  • 1 x Rasperry Pi
  • 1 x Breadboard
  • 1 x 10K Pot
  • 1 x 10uf Capacitor
  • And a few jump cables
Here is the setup I have :




  • GPIO 1 (3.3v) -> + Breadboard (3.3v)
  • GPIO 6 (Ground) -> - Breadboard (Ground)
  • 10uf Capacitor -> One pin in line with MCP3002 Pin 8, Other Pin to Ground
  • MCP3002 Pin 8 (Vdd/Vref) -> + Breadboard (3.3v)
  • MCP3002 Pin 7 (CLK) -> GPIO 11 (SPIO_SCLK)
  • MCP3002 Pin 6 (Dout) -> GPIO 9 (SPIO_MISO)
  • MCP3002 Pin 5 (Din) -> GPIO 10 (SPIO_MOSI)
  • MCP3002 Pin 4 (Vss) -> - Breadboard (Ground)
  • MCP3002 Pin 3 (CH1) -> Not connected
  • MCP3002 Pin 2 (CH0) -> Center pin of 10K Pot
  • MCP3002 Pin 1 (CS) -> GPIO 8 (SPIO_CE0_N)
  • 10K Pot Pin 1 -> - Breadboard (Ground)
  • 10K Pot Pin 3 -> + Breadboard (3.3v)

The Python Code

Now here is the cool part. The python code needed to get all the information out :
import spidev

import time

spi = spidev.SpiDev()
spi.open(0, 0)

while True:
    result = spi.xfer2([104, 0])
    digital_code = int(((result[0] & 3) << 8) + result[1])
    voltage = round(((digital_code * 3.33) / 1024), 2)
    print voltage
    time.sleep(0.5)
 And this is where things need a little explaining. Why do we use the values we do in the function's list to communicate with the MCP3002 ? What and why we use the bit manipultion ?

spidev is the module needed to allow python to talk through the SPIO pins. From a console run the following :
sudo apt-get install spidev

Initialization

spi.open(0, 0) -> Open SPIO Port 0 with CS 0. Basic initialization of the SPIO Pins. This tells the Pi to communicate down SPIO Port 0, which is attached to the CS (Channel Select) pin on the MCP3002. This tells the MCP3002 it needs to return information from CH0 (Channel 0) pin. If you had the pot on CH1 and connected to GPIO 7 (SPIO_CE1_H) then you would have code - spi.open(1, 1)


Transmitting Data

spi.xfer2([..., ...]) -> Now this is an interesting function that had me trying to understand what was being put in that list. Many sites I looked at had different values, but none really explained how they got these values, but through a little bit of maths and base conversions I found it out. With an MCP3002 you need only put in 2 list values to get a result. MCP3004/8 use 3 list values (I will get to that later). Have a look at this taken from the MCP3002 DeviceDoc :



Let me try and explain it the best I can in which made me figure out the workings of the IC. Don't worry too much about falling and rising of edge of clock. We are more looking at the bits that need to be transferred/received to/from the device. This IC works with 8 bit blocks (a byte if you wish). From this we can see that what needs to transferred to the device to get a response is two sets of 8 bits. In the first block of 8 bits (MCU Transmitted Data) we need to send some information to tell the IC how it should work for us. 


Bit Value Explanation
Start Bit 1 To initialize the IC to receive data
SGL/DIFF 1/0 1 - To select Single Ended Mode (This is the mode we will use)
0 - To select Pseudo Differential Mode
ODD/SIGN 0/1 Channel Selection. CH0 or CH1
MSBF 1/0 1 - To select MSBF - Most Signification Bit First
     Bits returned in normal order with first bit starting on the left
0 - To select LSBF - Last Signification Bit First
     Bits returned in reverse order with first bit starting from the right

As you can see this is the order of the bits and how they are needed:

  1. Ignored
  2. Set to 1 (Start Bit)
  3. Set to 1 (To select Single Ended Mode)
  4. Set to 0 (To talk to Channel 0)
  5. Set to 1 (To have the returned bits in the right order to process)
  6. Ignored
  7. Ignored
  8. Ignored
So the bits, in order, that we need are 1101. But that's only 4 bits you say. So we need to shift these over by 3 bits to give us a binary value of 1101000 (Remember the 1st bit is ignored). We will pretend there is a 0 there as the first bit, so for completeness we can look at it as 01101000. That is the 8 bits we need to send. If you convert that to a Decimal value it will give you the number 104. This is the first value in the list.

On the second set of 8 bits that get sent. Looking at the same excerpt above we can see that what ever is put in there is ignored. So we just send a Decimal value of 0 (00000000 - in binary).

So now you see how we get 104, 0 

Receiving Data

As you can see result receives the information that spi.xfer2[(104, 0]) sends.

This is also returned as a list. The reason for this can once again be seen in the excerpt above (MCU Received Data). Two blocks of 8 bits. The first block holds 2 bits of the final code and the second block holds the last 8 bits of the code. The total final resulting code is actually a 10bit number. These two blocks of 8 bits are returned as to values in a list (result) which we need to bung together to produce the digital_code.

How we do this requires a little Bit Manipulation.

Lets look at the code to do this conversion. int(((result[0] & 3) << 8) + result[1])

The first block we see that only the last 2 bits are needed, though the device could send back more. This is position 0 in the list of result. Therefore result[0]. Using the Bitwise operator & with the decimal value of 3 which has a binary of 11 to make sure that we only get the last 2 bits. Here is a few examples to show what the & operator does:

  • 1010 & 0011 = 0010
  • 1001 & 0011 = 0001
  • 0111 & 0011 = 0011
So with the final value of result[0] & 3 we now need to shift it 8 places to the left to make space for the next 8 bits that need to be added to it (Basically add 8 zero's to the end of the binary number). That is what << 8 does. Here are a few examples to explain this :
  • 11 << 8 = 1100000000
  • 01 << 8 = 0100000000
  • 10 << 8 = 1000000000

Now that we have taken the two bits out, and shifted it over by 8 we now add the final number in the list, result[1], to it. This gives us a final decimal number that is the digital_code.

Calculating the voltage

Once we have the digital_code we now need to do a simple calculation to convert that number into the voltage that is being returned by the pot. This is taken from the MCP3002 documentation :

So what we need to find is Vin. We know Vdd is 3.33v (Tested on a volt meter). And we know what the digital_code is. Then, with a little manipulation of the algorithm, we get (digital_code * 3.33) / 1024). using the round function we round it off to two decimal places and therefore get the final calculation of  round(((digital_code * 3.33) / 1024), 2).

Conclusion

At the end of all this we a voltage that is returned by the pot. This comes in useful for things like temperature sensors that produces a resistance relevant to the temperature. Producing this resistance lowers the voltage. This final voltage can be used to calculate what the temperature is actually being sensed by the sensor.

I hope this has help you as much as possible. If you have any questions feel free to post it and I will endeavour to answer it the best I can.

Look out for my follow on post on the MCP3004/8 IC coming soon.