Many projects do not actually require much knowledge about electricity. Despite what is learned in places like physics classes, it is almost never necessary to use Ohm's law to calculate voltage, resistance, and current in a circuit. Many of the components that you will use are really self-contained and just need to be hooked up properly. Really, it often boils down to reading specification sheets and documentation. The devices will say what voltage they need and how much current they will draw and all you have to do is make sure it is getting what it needs.

IO Port Expander (MCP23017 and MCP23008)

The MCP23017 and MCP23008 integrated circuits are a great way to add more I/O pins to a microcontroller. They use the i2c standard, so they can share the same serial line with 254 other sensors and even up to 8 other chips of the same exact type.  They are particularly good for a Raspberry Pi because they have higher current capabilities than the Raspberry Pi's GPIO pins. The MCP can supply 25mA per pin and the Raspberry Pi can only do less than 16mA per pin. 20mA is enough to fully power a strong LED, so 16mA may not be enough in some cases. More importantly, through the use of a relatively cheap logic level shifter, many 5V I/O pins can be added to a single serial channel despite the fact that the Raspbery Pi uses 3.3V GPIO and serial.

MCP23017 (16 I/O pin)
GPB0 • 1 28 GPA7
GPB1 2 The MCP23017 I/O port expander adds input and output pins over i2c serial. 27 GPA6
GPB2 3 26 GPA5
GPB3 4 25 GPA4
GPB4 5 24 GPA3
GPB5 6 23 GPA2
GPB6 7 22 GPA1
GPB7 8 21 GPA0
GND 10 19 INTB
    11 18 RESET
SCL 12 17 ADDR2
SDA 13 16 ADDR1
    14 15 ADDR0



MCP23008 (8 I/O pin)
SCL • 1 18 VIN
SDA 2               17 GP7
ADDR2 3 16 GP6
ADDR1 4 15 GP5
ADDR0 5 14 GP4
RESET 6 13 GP3
    7 12 GP2
INT 8 11 GP1
GND 9 10 GP0

*The bold pins are required. In particular, it is important to set the RESET pin to high.

GPA#, GPB#, GP# are the GPIO pins. On the 16 pin version, there are two ports denoted by the A and B (PORTA, PORTB).

INTA, INTB, INT are the interrupt outputs that can be monitored by the microcontroller to notify it when inputs change. On the 16 pin variant, there is one for each GPIO port.

i2c Address
0 1 0 0 ADDR2 ADDR1 ADDR0 Hex Addr. Dec. Addr.
0 1 0 0 0 0 0 0x20 32
0 1 0 0 0 0 1 0x21 33
0 1 0 0 0 1 0 0x22 34
0 1 0 0 0 1 1 0x23 35
0 1 0 0 1 0 0 0x24 36
0 1 0 0 1 0 1 0x25 37
0 1 0 0 1 1 0 0x26 38
0 1 0 0 1 1 1 0x27 39

The ADDR# pins can be set to high or low to change the address by 1 or 0 in the style in the address table allowing for a possible total of 8 different addresses, and therefore allowing up to 8 chips total. Both the 16 GPIO and 8 GPIO pin variants start at 0x20, so mixing the type will not help get more. If you are using more than 128 pins, you might want to consider alternatives like shift registers.

The RESET pin can be used to clear the registers and set it back to its power-on state, but really that isn't very useful since you can always use serail commands. So, usually you will just wire it directly to HIGH (3.3v or 5v) so that it always stay on.


There is an Arduino library made available by adafruit on GitHub. Usage is very simple:

#include <Wire.h>
#include "Adafruit_MCP23017.h"

Adafruit_MCP23017 mcp;
# define BLINKPIN 0
# define INPUTPIN 1
# define ECHOPIN 13

// blinks MCP pin 0 on and off
// turns MCP pin 13 on when MCP pin 1 is high or unplugged
void setup() { mcp.begin(); // use default address 0x20 (0,0,0) mcp.pinMode(BLINKPIN, OUTPUT);

mcp.pinMode(INPUTPIN, INPUT); mcp.pullUp(INPUTPIN, HIGH); // turn on a 100K pullup internally }

void loop() { delay(100); mcp.digitalWrite(BLINKPIN, HIGH); delay(100); mcp.digitalWrite(BLINKPIN, LOW);

// ECHO only updates every 200 ms
digitalWrite(ECHOPIN, mcp.digitalRead(INPUTPIN)); }

The major problem with the above code is that the ECHO is not updated until the delays are done. To get by that limitation, something like Metro or Kernel could be used, or simply checking the time yourself. This example was built just to show the bare minimum of how to interface with the MCP, not to show a practical application though.

Raspberry Pi

Adafruit also provies a Python library for the Raspberry Pi, which is also easy to use. 

from Adafruit_MCP230XX import *

# Use busnum = 0 for older Raspberry Pi's (256MB) # Use busnum = 1 for new Raspberry Pi's (512MB with mounting holes) mcp = Adafruit_MCP230XX(busnum = 1, address = 0x20, num_gpios = 16)
# Set pins 0, 1 and 2 to output (you can set pins 0..15 this way) mcp.config(0, mcp.OUTPUT) mcp.config(1, mcp.OUTPUT) mcp.config(2, mcp.OUTPUT) # Set pin 3 to input with the pullup resistor enabled mcp.pullup(3, 1) # Read pin 3 and display the results
#bitshift output, third bit is the output print "%d: %x" % (3, mcp.input(3) >> 3) # Python speed test on output 0 toggling at max speed while (True): mcp.output(0, 1) # Pin 0 High mcp.output(0, 0) # Pin 1 Low

NPN and PNP Transistors


Transistors are incredibly useful devices. My favorite use for bipolar junction transistors (BJTs) is switches. By either applying a high (1) or low (0) voltage to them, the transistors switch from on to off or vice versa. These transistors also can be used for current amplification. They can also be used along side diodes to create logic gates. However, this will focus on the difference between the NPN and PNP transistors.

How to choose between the NPN and PNP transistors

The two transistors can be used to perform the same thing, such as switching, but how to use them differs. Below I explain how both the NPN and PNP function and then depending on your application, you can choose whichever transistor is more applicable.

NPN Transistor

NPN transistors flow current from the collector to the emitter. Generally, the emitter is grounded and the circuit that will be powered on and off is put on the powered collector side of the transistor. It should be noted that although the top part of the circuit may be connected to a voltage, no current actual runs through the circuit until it is connected to ground, which is separated from the circuit by the NPN transistor. The NPN transistor is on when there is a high voltage (1) connected to the base and off when there is a low voltage (0 - generally ground) connected to the base. It is also important to know that the voltage on the base pin is connected to how the transistor is connected in the circuit. The base pin voltage in this configuration is ground, which is likely due to the grounded emitter pin. This is why when the NPN transistor's base pin is then connected to a high voltage, such as 5V, current flows into the transistor and connects the emitter and collector. 

PNP Transistor

PNP transistors flow current from the emitter to the collector. Generally, the emitter is powered and the circuit that will be powered on and off is put on the collector side of the transistor connected to ground. It should be noted that the circuit will once again not be powered unless the transistor is in the on position. The PNP transistor is on when there is a low voltage (0 - generally ground) connected to the base and off when there is a high voltage (1) connected to the base. In the case of the PNP transistor, the voltage on the base pin is approximately what the Vcc voltage is. When I tested this with a 5V Vcc, the base pin voltage was approximately 4.6V. This is why when the PNP base pin is connected to ground, current will flow to the transistor, which connects the emitter to the collector.


When working with transistors as with all components in circuits, care has to be taken to analyze how the current flows through the circuit. With transistors, it is a little trickier since there are three pins rather than two like with resistors and capacitors. However, as stated previously, they are very useful components. If something is not working the way you expect, I have found that there is generally current flowing into or from a base pin unintentionally.


For a more thorough discussion visit here.