Keypads and Button Switches on the Arduino

Keypads used in the dropController
Digial keypad on the left. Analogue keypad on the right.

When I first started building the dropController and the camController I could not find suitable navigation keypads, the ones I did find were expensive or not really suitable, so I built my own. These were simple keypads and follow the normal wiring for press button switches. This means each of the push button switches is wired to a separate pin on the Arduino. This obviously means you need 5 pins. This was fine until I wanted to add extra solenoid valves and realized I didn’t have enough spare pins.

I starting looking for pre-made keypads again and came across the Keyes Keypad on Taobao. These are cheap and smaller than the keypads I made. They also use a single pin. These are analogue keypads that use a single analogue pin on the Arduino.


The main difference between the digital keypad and the analogue keypad is how the keys are read and how the returned value is used. For the digital keypad you need to check each pin/key separately. For example. If left_key is pressed, if right_key is pressed. The analogue keypad uses a single variable which has a different value depending on the key pressed. For example. if Keypress is left, or if keypress is up. I found this a little easier to work with but it can be written anyway you wish.

 

Digital Keypad

Digital Navigation Keypad - front and back

The wiring for each button switch is fairly simple. There is a GND wire with a 10K pull down resistor, a VCC/+5V wire and a data wire that goes to an Arduino digital pin. The pull down resistor gives you a reading of LOW when the button switch is not pressed. When pressed the 10K resistor is bypassed and the reading is HIGH.

BTN01 BTN02

Both diagrams are the same. Internally, the left and right sides of the switch are joined together. This can be seen from the schematic icon used for switches:

BTN03BTN04

Making a keypad is just a case of adding more buttons.

BTN06

Here is the layout I use:
digitalKeypad - layout

There are many resources on the net and the Arduino site has a good introduction: http://arduino.cc/en/tutorial/button

I use Alexander Brevig’s button library for detecting key presses. This makes the code simple. At the start of the sketch you define which buttons are on which pins and if you are using pulldown (to GND) or pullup (to +5). I have always used pulldown.

Button ok_button = Button(2,PULLDOWN);
Button rt_button = Button(3,PULLDOWN);
Button dn_button = Button(4,PULLDOWN);
Button up_button = Button(5,PULLDOWN);
Button lf_button = Button(6,PULLDOWN);

Later in the main body of the sketch you can detect key presses with a simple one line statement.

 ok_button.uniquePress();

This returns TRUE of FALSE and can be used in a variety of different ways. For example:

if ( ok_button.uniquePress() )  { Serial.Print( "OK button was pressed."); }

The library allows you to detect such things as unique key presses and the current button state (up or down) as well as others. The library can be found in the Arduino playground at http://playground.arduino.cc/Code/Button

 

Analogue Keypad

Keyes Keypad

The analogue keypad produces a different voltage or analogue value depending on which key is pressed. This can be read by a single analogue pin on the Arduino. In theory this is slower than using digital pins but I have not noticed any difference and I have found that the analogue routine I use (copied from the interweb) gives a more positive response than the one I use for the digital keypad. I still get a lot of bounce and false presses with the digital keypad (not that I really did much to fix it).

I buy the analogue keypads from Taobao in China but they are also available from ebay. It is fairly straight forward to make your own, the switches are arranged in the same way as a voltage divider (or because we have 5 switches I think it is a voltage ladder).

 

DIY Single Pin Analogue Navigation Keypad

Here is a simple keypad set up on a breadboard. The wire from the button switches goes to A0 on the Arduino.

DIY Single Wire Keypad

DIY Single Wire Keypad

I used 2.2K ohm resistors because it is what I had but other values can be used as long as they are large enough. 1K and 2K work as well.

 

Keypad tester sketch

The below sketch reads the analogue pin and outputs the value to the serial monitor.

/*
Keypad Tester 01. Created by Martyn Currey
*/

// Global Variables
const byte keypadPin     = A0;
int val = 0;

void setup() 
{
  Serial.begin(9600); 
  while (!Serial)   {  ;    }
  Serial.println(F("Start\n"));
  // set the analogue pin for input and turn on the internal pullup resistor
  pinMode(keypadPin, INPUT_PULLUP); 
}

void loop()
{
    val = getKeyValue();
    Serial.println( val );
    delay(100);
} 


int getKeyValue()
{
    int pinVal;
    pinVal = analogRead(keypadPin);
    return pinVal;
}

Using 2.2KΩ resistors I get the following values:.
– No button pressed = 1021 to 1023
– First button = 14 or 15
– Second button = 72 or 73
– Third = 124
– Forth = 170
– Fifth = 212 or 213

Due to tolerances in the components you are very likely to get slightly different values.
Setting the pullup resistor on the analogue pin means it is putting a +5v (in reality is is slightly lower) on the pin which means when no button is pressed the pin reads about 1023.

You may notice that the first button switch causes a direct short from A0 to GND. The pullup resistor on the pin protects the Arduino from a short and the actual current flowing is only around 1 milliamp.

Moving the GND connection to the other end of the circuit simple reverses the values each button switch gives. i.e. pin one now gives 212 and pin 5 gives 14.
DIY Single Wire Keypad

 
In the sketch we could just use the value returned from the analogread() but a better way would be to use direction labels. This allows you to write things like if (buttonPress==LEFT) {}, or if (buttonPress==DOWN) {}.

/*
Keypad Tester 02. Created by Martyn Currey
*/

// Global Variables
const byte NONE = 0;
const byte LEFT = 1;
const byte UP = 2;
const byte RIGHT = 3;
const byte DOWN = 4;
const byte SELECT = 5;

const byte keypadPin = A0;
byte key = 0;

void setup() 
{
  Serial.begin(9600); 
  while (!Serial)   {  ;    }
  Serial.println(F("Start\n"));
  pinMode(keypadPin, INPUT_PULLUP); // sets analog pin for input 
}

void loop()
{
    key = getKey();
    if (key==LEFT)    { Serial.println("LEFT"); }
    if (key==RIGHT)   { Serial.println("RIGHT"); }
    if (key==UP)      { Serial.println("UP"); }
    if (key==DOWN)    { Serial.println("DOWN"); }
    if (key==SELECT)  { Serial.println("SELECT"); }
    if (key==NONE)    { Serial.println("NO KEY PRESSED"); }
    delay(100);
} 


/*
Key Values
Left / First button = 15
Up / Second button = 72
Down / Third = 124
Right / Forth = 170
Select / Fifth = 212
No button pressed = 1021

Because the values change depending on the actual components and even the temperature we need to test for a range of values. 
I tend to use +/- 20. This gives:
Left - 0 to 35
Up - 52 to 92
Down - 104 to 144
Right - 150 to 190
Select - 192 to 232
*/
byte getKey()
{
    int val = 0;
    byte button = 0;
    val = analogRead(keypadPin);

    button = NONE; // use NONE as the default value
    if ( val <= 35)  {  button = LEFT; }                                // left
    else if ( (val >= 52)  &&  (val <=92)    )   {  button = UP;  }     // up
    else if ( (val >= 104) &&  (val <= 144 ) )   {  button = DOWN;  }   // down
    else if ( (val >= 150) &&  (val <= 190)  )   {  button = RIGHT;  }  // right
    else if ( (val >= 192) &&  ( val <=232)  )   {  button = SELECT;  } // select
    return button; 
}  

Run the sketch, open the serial monitor and you should now see something similar to:
DIY Single Wire Keypad Serial Monitor

Further Resources

There is another fairly simple example on the tronixstuff website Using analog input for multiple buttons. This is very similar to mine.
An example that uses different value resistors can be found at http://arduino-info.wikispaces.com/Keyboards-MultipleButtons. I believe this is how the pre-made keypads I buy are configured. Different value resistors spread out the range of key press values more evenly.

2 thoughts on “Keypads and Button Switches on the Arduino

  1. Very useful thanks! Do you know a good expansion board that works with this code? I need to connect about 25 switches and all of them need to be readout upon start for the actual status.

Leave a Reply

Your email address will not be published. Required fields are marked *


4 + four =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>