In an attempt to reduce the amount of code I needed to process keypad inputs, I decided to extend Angel's code library to accommodate a 74C922 keypad decoder.
Why?
1) Because the decoder gives me a keypad value between 0x00 and 0x0F I don't need to write any code to pulse the keypad rows and identify the input keystroke
2) The 74C922 has a very handy "Data Available" signal that let's you know when there's been a "press-and-release" event, so no more mucking about to figure out if the value you're getting from the keypad is a new keypress of just a long keypress from the user
Everything you'll need to get this one working is here, including circuits, PCB designs and source code for the library.
Here's the schematic for the keypad port expander.
The capacitors can be left out, but the stability of the circuit suffers as you're no longer debouncing the keystrokes.
Power and ground to the the IC's is not indicated in the schematic, so don't forget them :)
The 8 pin header runs off to your keypad - the circuit as it's designed assumes a keypad with this pinout:
Getting this wrong isn't fatal, but you won't get the right output. All the keypads I've used have this pinout, but I've seen talk of other posibilities.
The 4 pin header runs back to your arduino, with the following pinout:
Also note that I've tied the address lines of the 8574 to Vcc. This locks the 3 bit address of the device to be 0x7. If you want to change this for any reason, just cut the tracks on the circuit board to leave those address lines floating.
I've assumed that there is a buzzer connected to pin 13 of the Arduino for audible prompts. The software library (below) uses this to generate keyclicks (a single keyclick for most keys, and a double click for the # key which I use as an "Enter" key).
The constructor for the class takes two arguments, one of which tells it where to find the buzzer. If you put in -1, it will turn sound off and never try to write to that pin.
Here is the circuit board design for those wanting to cut one at home:
Here's a pdf of the pcb you can use to print onto film to photoetch the board.
And lastly some images of the finished board...
I'vce written a small library to manage the board. The interface is as follows.
Constructor
I2CDecodedKeypad(int kbdAddr, int buzzAddr);
init()
void I2CDecodedKeypad::init(void)
getKeyStroke()
char I2CDecodedKeypad::getKeyStroke(void)
beep()
void I2CDecodedKeypad::beep(int on, int off, int reps)
beepOn()
void I2CDecodedKeypad::beepOn(void)
beepOff()
void I2CDecodedKeypad::beepOff(void)
#ifndef i2cdeckpd_h #define i2cdeckpd_h /* I2C DecodedKeypad * * Library for interfacing to keypad using an I2C bus and a 74C922 * keypad decoder * * Copyright (c) 2009, A. Davison (software@davison-family.com) * All rights reserved. * * Source contributions from i2ckeypad by Angel Sancho (angelitodeb@gmail.com) * * * * LICENSE * ------- * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * * * EXPLANATION * ----------- * This library interfaces to a 4x4 keypad which has been decoded using * a 74C922 keypad decoder, and then serialised using the PCF8574 I2C bus * expander. * * Wiring diagrams for for the circuit can be found under the "hardware" * folder, along with a PDF circuit board design. * * IMPORTANT! You have to call Wire.begin() before init() in your code * */ class I2CDecodedKeypad { private: int decoderDataAvailable; int useBeep; static char charSet[17]; char keypadAddr; char buzzAddr; public: I2CDecodedKeypad(int,int); char getKeyStroke(); void init(void); void beepOn(void); void beepOff(void); void beep(int,int,int); private: void i2cWrite(int data); int i2cRead(); }; #endif #endif |
/* I2C DecodedKeypad * * Library for interfacing to keypad using an I2C bus and a 74C922 * keypad decoder * * Copyright (c) 2009, A. Davison (software@davison-family.com) * All rights reserved. * * Source contributions from i2ckeypad by Angel Sancho (angelitodeb@gmail.com) * * * * LICENSE * ------- * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * * * EXPLANATION * ----------- * This library interfaces to a 4x4 keypad which has been decoded using * a 74C922 keypad decoder, and then serialised using the PCF8574 I2C bus * expander. * * Wiring diagrams for for the circuit can be found under the "hardware" * folder, along with a PDF circuit board design. * * IMPORTANT! You have to call Wire.begin() before init() in your code * */ #include "i2cdeckpd.h" #include <Wire.h> extern "C" { #include "WConstants.h" } #define KBDADDR (0x4<<3|0x7) char I2CDecodedKeypad::getKeyStroke() { int tmpKey; tmpKey = i2cRead(); if ((decoderDataAvailable == 1)&&((tmpKey&0x10)==0)) { // OK. A key has been pressed and released, so return the value. tmpKey&=0x0F; if (tmpKey==14) { beep(25,25,2); } else { beep(25,00,1); } decoderDataAvailable=0; return charSet[tmpKey]; } else if ((tmpKey&0x10)>0) { decoderDataAvailable=1; } // Otherwise nothing happened... return 0; } char I2CDecodedKeypad::charSet[17]="123A456B789C*0#D"; void I2CDecodedKeypad::beep(int on, int off, int reps) { if (useBeep>0) { while(reps>0) { digitalWrite(buzzAddr,HIGH); delay(on); digitalWrite(buzzAddr,LOW); delay(off); reps--; } } } void I2CDecodedKeypad::init(void) { i2cWrite(0xff); if (buzzAddr >=0) { pinMode(buzzAddr,OUTPUT); } } I2CDecodedKeypad::I2CDecodedKeypad(int kAddr, int bAddr) { keypadAddr=kAddr; buzzAddr = bAddr; decoderDataAvailable=0; useBeep=1; if (buzzAddr==-1) { useBeep = 0; } } void I2CDecodedKeypad::i2cWrite(int data) { Wire.beginTransmission(keypadAddr); Wire.send(data); Wire.endTransmission(); } int I2CDecodedKeypad::i2cRead() { Wire.requestFrom(keypadAddr,1); return Wire.receive(); } void I2CDecodedKeypad::beepOn(void) { useBeep=1; } void I2CDecodedKeypad::beepOff(void) { useBeep=0; } |
// Code that uses the i2sdeckpd library to get keystrokes from a 4x4 // matrix keypad. // // My original source output the keystrokes on an LCD display. I've // crudely hacked that around so that you just get a stream on the // serial output. // // Thanks to Angel Sancho (angelitodeb@gmail.com) for posting code that got // me started with i2c comms. // // Copyright (c) 2009, Andrew Davison (software@davison-family.com) // #include <Wire.h> #include <i2cdeckpd.h> //I2C Address for devices is 0 1 0 0 A2 A1 A0 #define KBDADDR (0x4<<3|0x7) #define buzzerPin 13 I2CDecodedKeypad kpd(KBDADDR,buzzerPin); void setup() { Wire.begin(); kpd.init(); } int keyStrokes=0; void loop() { int key; key = kpd.getKeyStroke(); if (key>0) { keyStrokes++; Serial.print (keyStrokes); Serial.print(" keys pressed.?n"); Serial.print("keyval: "); Serial.print(key,BYTE); Serial.print(" ?n"); } delay(50); } |