Digital I/O Expansion

Increase the number of pins in your microcontroller designs

By Philip Kane

If your project requires more digital I/O pins than are available on your microcontroller or microprocessor, here is one possible solution. It’s an external digital I/O circuit that has a total of 16 pins. Access is relatively fast because you can directly address each pin. The circuit interface requires 6 of your existing microcontroller pins for a net gain of ten extra pins.

The block diagram in figure 1 shows the general organization of the circuit. It has 8 input pins (I0 – I7) and 8 output pins (O0 – O7). The pin directions are fixed, you can’t re-configure an output pin to be an input pin or vice versa.

External Digital I/O Block Diagram Figure 1: External Digital I/O Block Diagram

The Circuit Interface Consists of:

Select inputs (A2, A1, A0) – used to select an input or output pin. Each select input can be set to HIGH (1) or LOW (0). The combination of select inputs forms the address (in binary) of the desired pin.

Select Inputs PIN
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1

Data input (Din) – used to read the value (HIGH or LOW) of the selected input pin.
Data output (Dout) – used to set the value (HIGH or LOW) of the selected output pin.
Data output latch (Dlatch) – latches the value to the selected output pin.

To read an input pin:
1. Send the address of the pin to Select inputs (A2, A1, A0)
2. Read Data input (Din) for the value at the addressed pin

To set an output pin:
1. Send the address of the pin to Select inputs (A2, A1, A0)
2. Set Data output (Dout) to the desired value (HIGH or LOW)
3. Momentarily set output Data output latch (-Dlatch) to LOW, which causes the addressed output pin to change to and remain in the desired state

External Digital I/O circuit

One way to implement the circuit is shown in figure 2.

External I/O Circuit Implementation
Figure 2: External I/O Circuit Implementation


The output portion of the circuit consists of an 8 bit addressable latch (IC1). It has 8 digital output pins (Q0 - Q7). Data at the D input pin of IC1 will appear at a desired output when its address is placed on Select pins (A2, A1, and A0) and the -E pin is set momentarily to LOW. Note that IC1’s D input is connected to the external digital I/O circuit’s Dout pin.

I included IC3 to provide increased drive current for the CD4099 output. It’s not needed if you replace IC1 with a chip that has higher output drive capability, such as the 74HC259.


IC2 is an 8 bit data selector/multiplexer. One of the 8 inputs (D0 – D7) is selected by placing its address on Select inputs (C, B, and A). The value at the addressed input pin (D0 – D7) appears at output Y of IC2, which is connected to the external digital I/O circuit’s Din pin. IC2’s W output, which is not used in this circuit, is the inverse of it’s Y output.

Arduino Uno Test Circuit

As shown in figure 3, I used an Arduino Uno SBC to test the external digital I/O circuit. The pull-up resistors R9-R16 ensure that the inputs will be normally HIGH and all LEDs will be on. Pressing a pushbutton (S1-S8) will turn off the corresponding LED until the pushbutton is released.

Arduino Test Circuit Click to Enlarge Image
Figure 3: Arduino Test Circuit

Digital I/O Circuit Pin Arduino Port B Pin#

Arduino C Test Application

The code in listing 1 (below) is an Arduino C test application. It reads the value from each input pin in turn and writes the value to the corresponding output pin.

The application defines the functions (below) that initialize and access the external pins. Note that these functions do not use the Arduino Digital I/O commands. They access the port B pins through the port’s DDRB, PORTB, and PINB registers.

exPinInit() - Initializes the Arduino input and output pins

1. Initialize Arduino input pin (sets pin13 to input)
2. Initialize Arduino output pins (sets pins 8-12 to output)

exIPinRead(pinAddrs) – Returns the value (HIGH or LOW) of the addressed input pin

1. Send pinAdrs to digital I/O circuit (A2, A1, A0)
2. Get pin value from digital I/O circuit (Din)

3. Return pin value exOPinWrite(pinAdrs, pinValue) – Sets the addressed output pin to the specified value (HIGH or LOW) and records the new value

1. Send pinAdrs to digital I/O circuit A2, A1, A0)
2. Send pinValue to digital I/O circuit (Dout)
3. Strobe (-Dlatch)
 1. Set -Dlatch LOW
 2. Delay
 3. Set -Dlatch HIGH
4. Store new pin value

exOPinState(pinAdrs) - Returns the value to which the addressed output pin was most recently set

1. Use pinAdrs to access stored pin value
2. Return pin value

Listing 1

Philip Kane, a technical writer for over 20 years, has had a life-long interest in science, technology and space exploration. He enjoys designing and building electronic gadgets