SX1509 I/O Expander Breakout Hookup Guide

Contributors: jimblom
Favorited Favorite 12

Example: Button Matrices

Blinking and breathing LEDs can be fun, but the SX1509's real power lies in its keypad engine. By wiring up buttons in a row/column matrix, you can connect up to 64 buttons to the SX1509.

Keypad matrices are very common -- they allow you to save immensely on GPIO. You could monitor a 16-button, 4x4 keypad pad with 8 I/O, or four of those keypads (a 64-button/8x8 matrix) with just 16 I/O.

In this example, we'll use seven SX1509 I/O to monitor a 12-button Keypad -- which is a matrix of four rows and three columns. We'll also use the SX1509's interrupt output, so we don't constantly have to poll the I/O expander. Here's the circuit:

Keypad fritzing example

There isn't a lot of flexibility in the SX1509's keypad engine. The rows of you matrix have to be connected, sequentially, to pins 0-7, and the columns wire up to pins 8-15. Our four row buses must route to pins 0-3, and the three columns are connected to 8-10. That still leaves plenty of pins for LED driving!

Here's the example code:

#include <Wire.h> // Include the I2C library (required)
#include <SparkFunSX1509.h> // Include SX1509 library

const byte SX1509_ADDRESS = 0x3E;  // SX1509 I2C address (00)
SX1509 io; // Create an SX1509 object

#define KEY_ROWS 4
#define KEY_COLS 3

// Handy array we'll use to map row/column pairs to 
// character values:
char keyMap[KEY_ROWS][KEY_COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}};

// ARDUINO pin 2 connected to SX1509 interrupt

void setup() 
  Serial.begin(9600); // Use serial to print output
  if (!io.begin(SX1509_ADDRESS))
    Serial.println("Failed to communicate.");
    while (1)
  // To initialize the keypad engine, you at least need
  // to tell it how many rows and columns are in the matrix.
  // io.keypad(KEY_ROWS, KEY_COLS);
  // You can customize the keypad behavior further, by
  // defining scan time, debounce time, and sleep time:
  // Sleep time range: 128 ms - 8192 ms (powers of 2) 0=OFF
  unsigned int sleepTime = 0;
  // Scan time range: 1-128 ms, powers of 2
  byte scanTime = 16; // Scan time per row, in ms
  // Debounce time range: 0.5 - 64 ms (powers of 2)
  byte debounceTime = 8; // Debounce time
  io.keypad(KEY_ROWS, KEY_COLS, sleepTime, scanTime, debounceTime);

  // Set the ARDUINO pin as an input, to monitor the interrupt
  Serial.println("Row | Col | Key");

void loop() 
  // If the interrupt pin goes active-low, a keypad button
  // is begin pressed:
  if (!digitalRead(INTERRUPT_PIN))
    // Use readKeypad() to get a binary representation for
    // which row and column are pressed
    unsigned int keyData = io.readKeypad();

    // Use the getRow, and getCol helper functions to find
    // which row and column keyData says are active.
    byte row = io.getRow(keyData);
    byte col = io.getCol(keyData);
    char key = keyMap[row][col];
    Serial.print(String(row) + " | " + String(col) + " | ");

After uploading the code, open the serial monitor and press some keys!

Example serial monitor output

Now just hook up a cellular shield and go make some prank calls!

Keep in mind any of these SX1509 features can be combined, as long as you don't run out of I/O (then just cascade another expander!). Check out the library's examples for demonstrations of other features -- like the clock output, or input debouncing.