Search SpikenzieLabs:

A 64 button matrix

Project 64 / 64 Buttons

What does it do:

Gets a single unique button press value from a matrix of 8x8 (64) push buttons.

Coding Priority:

If we think of each of the 64 buttons as a bit and if your hands were big enough (or you had help from a few friends) you could press a total of 18446744073709551615 different combinations of the 64 buttons!

The intention of this project is not to decode that many choices, but rather just 64. The way the Arduino sketch does this is by checking one column at a time. It starts with the left-most column and works it’s way right. Then as soon as it sense a button press it stops. This is a form of priority encoding because the buttons on the left side (if more then one column are being pressed) will be decoded and the buttons pressed more to the right would be ignored.

If on the other hand more then one button is pressed in two or more rows, the sketch considers that an error and ignores the input, and continues through the program loop.


The MCP23S17 port expander uses the Serial Peripheral Interface (SPI) a form of synchronous serial data standard. It is synchronous because there is a clock line that controls the data transmission. SPI uses four wires to communicate in two directions.

If we use the this project as an example, the Arduino running the Button64 sketch is called the SPI Master and the button matrix is called the SPI Slave. The master device always controls the communications and the the clock line.

The four SPI signals:

  1. SCLK = Serial clock

  2. MOSI = Master Output Slave Input

  3. MISO = Master Input Slave Output

  4. CS = Slave Select

Extra signal:

  1. INT A = Interrupt on Port A (This is only for the button matrix, and is not a normal SPI signal)

Making It:

The type of buttons used to make this button matrix are push style SPST-NO (Single position single throw). This means that there is only one circuit going through the button, and when the button is not being pressed it is normally open (the circuit does not conduct).

If your buttons have two or four pins coming out the bottom it does not matter, just make sure that as you solder your rows and columns that they are common all the way up or across.

The pins on port A are pulled high using the internal weak pull-up resistors. This means that if a button is not being pressed, and port A were to be read, all the eight pins would be high. Rather then continually reading port A to see if there is a button press, we configuring the MCP23S17 to cause an interrupt any time pins on port A changes from the pulled-up high value.

In order to cause a pin on port A to go low (and cause an interrupt) two conditions must be meet, 1. A button must be pressed and 2. The output of the Port B column must be cleared to low.


Here are two ways to initiate button press sensing;

Method A: "Wait for an interrupt and then decode Method": If your Micro has the ability to sense and handle (IOCs) pin interrupts on changes then all you have to do is clear (set to low) all of the pins of Port B and wait for a change on port A to cause an interrupt. Once an interrupt is sensed, your Micro would then need to cycle through the port B pins one at a time to see which column caused the interrupt. The result is the row and column value that can easily be decoded.

Method B: "Once a loop, cycle through the columns": This is the method that is used in the Arduino Sketch "Button64v4.pde". Here once every program loop, a call is made to a function that changes each of the columns (port B) pins to a logic low, one at a time. If an interrupt is sensed (the interrupt pin on the MCP23S17 goes high) the column is already know since the sketch controls the columns, port A is read to get the row. Then with just a bit of code, a unique button value is achieved.


Decoding a button press is done with the help of a MCP23S17 port expander from Microchip. This chip has 16 general purpose I/O pins (GPIOs). Eight I/Os are used for the columns and other eight for the rows, forming a 64 button matrix. The columns (port B of the MCP23S17) are set-up as outputs and the rows (port A) inputs.

One of the great features of this project is that there are no diodes! Unlike many button matrices, it’s just the buttons and the MCP23S17.

Once you have all the buttons connected in rows and columns, make 16 extra wires and solder one end of each to every row and column. It does not matter where along each row and column that you solder them, so just pick the spot that you like the best; top, bottom, middle etc.

You should end up with 16 wire ends. If you haven’t already, pick which orientation is going to be the columns and rows.

Hardware Interface board:

Using the free ends of the wires in the last step; connect the wires from the columns to port B of the MCP23S17. Starting with column “1” connected to GPB0 (Pin 1), continue with column “2” to GPB1 (pin 2) and so on until all the columns are wired to the MCP23S17.

The rows are wired in a similar manner starting with row “1” being wired to GPA0 (pin 21) all the way to row “8” going to GPA7 (pin 28).

Connect pin 9 to +5 volts and pin 10 to ground. You should also connect pin 15, 16 and 17 (Address A0, A1 and A2) to ground. The Button64 sketch does not use these addresses.

Pin 18 (reset) should be connected to +5v though a 10K ohm resistor.

Connecting the hardware interface to an Arduino;

SIGNAL                MCP23S17                    ARDUINO

Slave Select         CS (pin 11)                   Digital 5

Serial Clock          SCK (pin 12)                Digital 3

MOSI                     SI (pin 13)                     Digital 2

MISO                     SO (pin 14)                   Digital 4

Interrupt                INTA(pin 20)                Digital 6                       

Using it:

  1. I.Make a button panel following the wiring instructions above.

  2. II.Wire-up the MCP23S17.

  3. III.Hook it all to your Arduino.

  4. IV.Download the Arduino sketch Button64v4.pde, compile it and then upload it to your Arduino.

  5. V.Click on the open Serial Monitor icon.
    Make sure that it is set to 9600 baud (Look near the lower part of the Arduino window)
  6. VI.If everything is good, after a moment, you should see the word “Ready” printed in the bottom part of the Arduino IDE (white text on black). Then, if you press some buttons you will see the button numbers, followed by “OK” after you release the button.


What’s next:

After you get your button board working with the Serial Monitor, you can comment out “//” the lines of code that send the serial messages for testing.

The Button64 sketch will return the last pressed button value in the variable called “buttonPress”. With this you can build your own sketch / project and use the button value to make music, light LEDS, turn on motors, make a sequencer  ...

Do you think that 64 buttons has too many buttons, or would be too long to wire-up? You can always make a smaller button panel! If you use the same construction techniques for the rows and columns, it will work with-out changing the sketch! (Note: if your rows are less then 8 buttons wide the button value returned will still jump by 8 for each row.) Unused port pins on the MCP23S17 may be left floating (not connected).

Make something cool and send us an e-mail !

Quick and dirty - Hardware interface for the button panel.

Video of the long process of soldering all 64 buttons. It took 1h 35min.

Animation demonstrating the scanning of the buttons.

Pin out of the MCP23S17 port expander used to interface with the button panel.

Want to make your own?

Here is the drawing file used to cut out the plastic parts.

Project 64 Drawing.pdf






How To + Info