Projects

Connecting Keypads

Interfacing Keypads to Microcontrollers

Andy Clark

Issue 35, June 2020

This article includes additional downloadable resources.
Please log in to access.

Log in

Build this Keypad Backpack to connect a matrix keypad to an Arduino or Raspberry Pi board using just one GPIO port.

BUILD TIME: 2 Hours
DIFFICULTY RATING: Intermediate

We needed to connect a matrix keypad to a microcontroller without using up lots of digital pins so this simple backpack adaptor board was created using an ATtiny.

THE BROAD OVERVIEW

A friend of ours, Jamie, approached us to help out with his escape room like lockbox puzzle. This lockbox involves a series of puzzles to stop the clock before the time runs out. One of Jamie’s key issues was that because there were many different devices to control, there were just not enough GPIO pins to provide all the digital inputs and outputs required from the microcontroller.

Lock Box project by Jamie De Stains

One of the prime uses for pins was the matrix keypad. This was using 7 pins in total, so this seemed a good place to reduce the pin-count.

Following a few experiments, we found a way to save six GPIO pins on Jamie’s puzzle box circuit by adding an ATtiny84.

We’ll describe the process we went through to arrive at our ATtiny circuit, and show you how to interface a keypad to an Arduino or Raspberry Pi using either a stripboard or custom circuit board.

HOW MATRIX KEYPADS WORK

A matrix keypad has a grid of simple single pole single throw push to make switches. Each switch is connected to one row and one column. When the button is pressed, one row and one column are joined together. A circuit can detect if a key is pressed by applying a signal to each row in turn and then checking which of the columns sees the same signal.

There are a number of different chips that can be used to support these matrix keypads.

74C922 is a CMOS keypad encoder that turns these 7 pins to a 4 pin parallel signal.

TCA8418 from Texas Instruments turns the keypad output into an I2C signal.

There is also a SparkFun Qwiic keypad that outputs the data as I2C. It is also possible to read the keypad directly from your microcontroller, for example, using the keypad library that comes with the Arduino IDE.

ONE WIRE EXPERIMENT

We were also intrigued by the mention of a “one wire keypad” library on the Arduino playground site. This approach uses a series of resistors and an analogue input to allow the keypad to be read using a single pin. Pressing each key completes a circuit for the resistor network effectively producing a voltage divider. For example, if switch 2 was pressed then the output would be routed through a single 1k resistor. Combined with a 1k resistor that connects to ground, this would be half the supply voltage. i.e. 2.5V.

Experiment with an analogue input and keypad.

In theory, this one wire circuit seemed to be just what was needed. However, when we experimented with this library, we found that it was not detecting key presses reliably. We suspect this is to do with the numbers in the middle having very similar values, and hence, any noise in the system causes the pad to display incorrectly. There is also a small delay on the analogue conversion so that may also have been contributing to the problems.

USING AN ARDUINO UNO/ATMEGA328P

Sourcing the specialist keypad chips were causing a problem so our next thought was to use a second smaller microcontroller to provide the keypad output in the form of serial communication. The initial prototype (shown here) was an Arduino Uno using the built-in hardware serial port that connects to the computer’s USB.

Testing the keypad with an Uno.

The keypad library from Alexander Brevig was used. This can be installed from the Arduino library manager. The “CustomKeypad” example was used with a couple of modifications. Firstly, the keys were changed to be the same as our keypad. Secondly, that example uses pins 0 and 1 which on the Arduino Uno are mapped to the serial port, which in turn, connects to the USB. So hence these could not be used.

This was a good chance to experiment with the pins and discover how the rows and columns were connected. The chip used on the Uno (ATmega328P) is quite large so a backpack made with that IC would also be large, so we looked at the ATtiny range instead. The ATtiny84 seemed to have sufficient pins so that was selected for this project.

USING AN ATTINY84

This ATtiny84 chip does not have a built-in USB port so hence there is a different technique to put your code onto the chip. Instead, the code can be uploaded using an Arduino Uno as an “In System Programmer”. This uses the Serial Peripheral Interface (SPI) connection to talk to the ATtiny.

SPI is a synchronous serial communication interface that uses a clock signal (SCLK) along with a pair of data lines, Master Output Slave Input (MOSI) and Master Input Slave Output (MISO). A 4th wire resets the ATtiny to put it into programming mode.

PROGRAMMING AN ATTINY

Out of the box, the Arduino IDE does not know how to compile ATtiny code. To add support for these chips we can use the configuration provided by David A. Mellis from https://github.com/damellis/attiny

First, select the file menu then select preferences. Press the button to the right of the Additional Boards Manager URL to open a larger box.

Note: You may already have entries here if you use a variety of boards.

Enter the following on a new line: https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json

Save the settings and return to Tools > Board > Boards Manager.

Search for ATtiny and install David’s configuration.

Wiring the programmer circuit

To wire up the ATtiny for programming you’ll need six jumper wires and a 1µF or 10µF capacitor. The capacitor stops the board from resetting when programming.

Unplug your Uno before wiring up these connections.

Connect the capacitor between the reset and GND pins of the Arduino Uno. If you are using a polarised capacitor, ensure that the negative lead is connected to GND. Connect up the pins as per this table and Fritzing diagram:

Parts Required: JaycarAltronicsCore Electronics
1 x Arduino Uno or Compatible BoardXC4410Z6280 or Z6240A000066 or CE05629
1 x ATtiny84--COM-11232
1 × 10μF Electrolytic CapacitorRE6066R5065CE05274
1 × 5mm Red LED* (For Testing)ZD0150Z0800CE05104
1 x 100Ω 1/4W Resistor* (For Testing)RR0548R7534CE05092

Parts Required:

* Quantity shown, may be sold in packs. You’ll also need a breadboard and prototyping hardware.

PROGRAMMING THE ATTINY84

The first step for programming is to configure the IDE for the specific model of ATtiny you are using. From the Tools > Board menu select “ATtiny24/44/84”.

Select the processor, ATtiny84.

Finally, select the clock, Internal 8 MHz.

These chips support multiple clock configurations and selecting them here will configure the internal “fuses” of the ATtiny. Slower clock modes will conserve power so should be considered if running from battery. Faster clock speeds will allow more processing to be done per second.

WARNING: Don’t set the external clock modes unless you have the components to support this. It could be hard to reverse.

To set the fuses and configure the ATtiny to use this clock, choose the Tools > Burn Bootloader. If you miss this step you will find that the ATtiny blinks at the wrong speed, which will be critical when it is doing serial communication later.

To test the programmer was working, we added an LED and resistor between pin 6 and ground, and a modified version of the Blink sketch.

From the Tools menu, select Programmer and pick Arduino as ISP.

Now open the blink sketch and upload using the programmer.

Your LED should now flash.

The Fundamental Build:

Breadboard Prototype

Now that we could code with the ATtiny, we needed to port a simple test program. There are two key changes needed. The first was to change the pin numbers to match those of the ATtiny. The second change needed was because the ATtiny does not support a hardware serial interface so a software serial library needs to be installed instead. Only the transmit (TX) pin is used so the receive (RX) pin was mapped but not connected.

Parts Required:JaycarAltronicsCore Electronics
1 x Arduino Uno or Compatible BoardXC4410Z6280 or Z6240A000066 or CE05629
1 x ATtiny84--COM-11232

Parts Required:

Keypad Options: JaycarAltronicsCore Electronics
3 x 4 Membrane Keypad-Z6341ADA419
4 x 4 Membrane Keypad--FIT0129
3 x 4 Numeric KeypadSP0770S5381ADA3845
4 x 4 Numeric Keypad-S5383ADA3844

Keypad Options:

* Quantity shown, may be sold in packs. You’ll also need a breadboard and prototyping hardware.

# Our project example uses a 4x4 Membrane keypad. Keypads described in the prototype parts list are also suitable.

THE CODE

The code (available in resources) was adapted from the example that Alexander Brevig provided with the keypad library. The first part of the code contains the libraries that we need for the project. The keypad and the software serial library. It then follows a series of variables that define the shape of the keyboard, which letters are present and the pins that are used by the keypad and the serial port.

#include <Keypad.h>
#include <SoftwareSerial.h>
const byte ROWS = 4; 
//Shape of the keyboard
const byte COLS = 4;
char hexaKeys[ROWS][COLS] = {   
//Keys on the keyboard
  {‘1’,’2’,’3’,’A’},
  {‘4’,’5’,’6’,’B’},
  {‘7’,’8’,’9’,’C’},
  {‘*’,’0’,’#’,’D’}
};
byte rowPins[ROWS] = {0, 1, 2, 3}; 
//connect to the row pinouts of the keypad
byte colPins[COLS] = {4, 5, 6, 7}; 
//connect to the column pinouts of the keypad
const int tx = 8;  
const int rx = 9;

The following code defines the complex variables that represent the software serial port and the keypad. The last part of the initialisation is to tell the serial port the speed of communication.

SoftwareSerial sserial(rx,tx);  
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 
void setup(){
  sserial.begin(9600);
}

The main loop of the software checks to see if there was a keypress and then if one is detected, passes that to the serial port to send to the host MCU.

void loop(){
  char customKey = customKeypad.getKey();
  
  if (customKey){
    sserial.print(customKey);
  }
}

Keypad Pinouts

The membrane keypad pinouts are quite logical, simply rows followed by columns. When testing with Jamie's smaller push-button style keypad we found that columns and rows were not so straightforward. To test the pinout we held down one button and used a continuity tester to check which contacts were connected together.

Here are some common pinouts for membrane and push-button keypads.

Jamie's prototype using a 4 x 3 keypad.

Build 1:

Solderable Stripboard Version

To test out the board, a prototype was designed and assembled on a solderable stripboard. We added a Schottky diode to provide polarity protection on the power supply and an LED to provide an indication that it was powered up. The resistor for the LED was selected so that it would glow brightly for both a 5V supply and a 3.3V supply. A small capacitor ensures that the power is smooth and does not vary with a load such as when the device is communicating on the serial line.

When assembling the stripboard, the first step is to make the breaks in the tracks, as you can see in the following diagram.

Next up, add the components starting with the smallest. So for this board, it would be the wires followed by the diode and resistor. Note the orientation of the diode or the circuit won’t work. The LED also has an orientation, the negative lead is typically noted by a flat on the side of the LED. The socket and the headers can then be added and finally the capacitor. Note that the capacitor will be slightly offset hence it is important to add this after the socket. Again, the capacitor is polarised so the negative lead goes to the right as you look from the top of the board.

It is worth checking the board before plugging in the ATtiny. Make sure that the pins are connected to the sockets you would expect based on the schematic. Make sure that the sockets are not shorted to each other.

Connect the power and TX pin to an Arduino Uno and run the TestSerial sketch from the resources. Open the serial monitor to see the keypad responses. If your keypad is producing the wrong characters for the buttons then check to see if you have your columns and rows swapped over.

Parts Required: JaycarAltronicsCore Electronics
1 x Vero/Stripboard (Minimum 21 x 13 holes)HP9540H0714FIT0099^
1 x 1N5819 1A Schottky Diode (D1)ZR1020Z0040COM-10926
1 × 5mm Red LED* (D2)ZD0150Z0800COM-12062
1 × 10µF Electrolytic Capacitor (C1)RE6066R5065CE05274
1 x 100Ω 1/4W Resistor* (R1)RR0548R0034COM-10969
1 x ATtiny84 (U1)--COM-11232
1 x 4 x 4 Membrane Keypad (Key1)#-Z6341FIT0129
1 x 2.54mm Headers (Headers)HM3212P5430FIT0084

Parts Required:

* Quantity shown, may be sold in packs. You will also need some general purpose hook-up wire, and a knife or drill bit to cut the tracks on the circuit board

^ The ProtoBoard from Core Electronics is individual pads that you will need to solder together.

# Our project example uses a 4x4 Membrane keypad. Keypads described in the prototype parts list are also suitable.

Build 2:

PCB Version

Once I was happy with the prototype, I moved onto creating a PCB as that would allow for a smaller module. To make it as small a PCB as possible, the LED was reduced from 5mm to 3mm and the programming header was swapped for a 2x3 version which is designed to be compatible with the Arduino SPI header.

The board is designed to be double-sided, but as there are only two tracks on the top, you could make it single sided and add those two tracks using wires.

Assembly of the PCB is similar to the stripboard version. Add the diode and resistor first, then the two taller components and the connectors. Finally, add in the ATtiny. If you are not certain about soldering this directly then you can use a socket as was done on the prototype. Optionally, add a set of pins or header for the programming header.

PROGRAMMING

To program the board, you can use an Arduino Uno with the programming sketch as detailed previously. We recommend that the Uno is disconnected as you wire up the connectors to the backpack. The wiring to the SPI header is as follows.

Reconnect the Uno to your computer and the LED should light up. If it does not, unplug and check your connections.

Upload the sketch as described earlier, and test using the test serial.

Plug the keypad into the 8 pin header, ensuring you have the orientation correct so that the columns are on the left and the rows on the right.

Note: If you have a 4x3 keypad then just use the first 7 pins starting from the end nearest the resistor.

Parts Required:JaycarAltronicsCore Electronics
1 x PCB (Files available on our website)---
1 x 1N5819 1A Schottky Diode (D1)ZR1020Z0040COM-10926
1 × 3mm Red LED (D2)ZD0100Z0700POLOLU-1070
1 × 10µF Electrolytic Capacitor (C1)RE6066R5065CE05274
1 x 100Ω 1/4W Resistor* (R1)RR0548R0034COM-10969
1 x ATtiny84 (U1)--COM-11232
1 x 4 x 4 Membrane Keypad (Key1)#-Z6341FIT0129
1 x 2.54mm Headers (Headers)HM3212P5430FIT0084

Parts Required:

* Quantity shown, may be sold in packs.

# Our project example uses a 4x4 Membrane keypad. Keypads described in the prototype parts list are also suitable.

USING WITH AN ARDUINO

To use the backpack with an Arduino, wire up as per the serial test and use the software serial library to read the data from the backpack.

USING WITH A RASPBERRY PI

IMPORTANT: To use the backpack with a Raspberry Pi, you must power it from the 3.3V pin on the GPIO header.

Your Pi may also need to be configured to enable the serial port and disconnect it from the console. Open the Raspi Config tool, either from the menu or via the command line:

sudo raspi-config

From the tool, enable Serial Port and Disable Serial Console. You will need to reboot your Pi following this change.

Once the Pi is configured, the port can be accessed by your favourite programming language. There is a Python example in the resources.

WHERE TO FROM HERE?

Adapt this project as a keypad for a lockbox, security system, or remote control. You could also use the technique to have multiple pushbuttons or microswitches connected to one I/O pin to simplify a wiring loom in a more complex project.

Andy Clark

Andy Clark

Staff Writer