I bought one of these keypads off ebay few days ago, and decided to try it out.
These work pretty straight-forward, you have 8 pins – 4 for rows and 4 for columns. When you press a button, it creates contact between the respective row and column. Still, you need 8 pins to drive it, so I decided to use an Attiny84 to do the reading and output the result to a serial output @ 9600 baud. This way I can use the keypad with only one pin (RX) and of course VCC and GND. Further more, for low power applications, I wanted the ATtiny84 to sleep and only wake upon key press. This will make this solution viable for battery operated nodes, I use pin change interrupts to trap keys. The ATtiny84 provides a feedback pin that goes HIGH for 100ms when a button is pressed, this can be used for visual confirmation via a LED, or a piezo buzzer or to wake up a sleeping host system so it can read the key.
Power consumption when waiting for a key press cannot be measured with multimer as it is below any scale, the datasheets states the ATtiny84 consumes 0.1 µA in Power-Down Mode, so you can run it for ages.
My code is simple:
#include < avr / sleep.h > #include <Keypad.h> // http://playground.arduino.cc/code/Keypad #include <PinChangeInterrupt.h> // http://code.google.com/p/arduino-tiny/downloads/list /* Edit PinChangeInterrupt.h to allow 4 PinChange handlers: #if defined( __AVR_ATtinyX4__ ) #define NUMBER_PIN_CHANGE_INTERRUPT_HANDLERS (4) #define NUMBER_PIN_CHANGE_INTERRUPT_PORTS 2 #endif */ #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif /* +-\/-+ VCC 1| |14 GND TX (D0) PB0 2| |13 AREF (D10) (D1) PB1 3| |12 PA1 (D9) RESET 4| |11 PA2 (D8) INT0 PWM (D2) PB2 5| |10 PA3 (D7) PWM (D3) PA7 6| |9 PA4 (D6) PWM (D4) PA6 7| |8 PA5 (D5) PWM +----+ */ const byte ROWS = 4; //four rows const byte COLS = 4; //four columns char keys[ROWS][COLS] = { {'1','2','3','A'}, {'4','5','6','B'}, {'7','8','9','C'}, {'*','0','#','D'} }; byte rowPins[ROWS] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad byte colPins[COLS] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); void wakeUp() {} void setup(){ Serial.begin(9600); pinMode(10,OUTPUT); digitalWrite(10,LOW); PRR = bit(PRTIM1); // only keep timer 0 going ADCSRA &= ~ bit(ADEN); bitSet(PRR, PRADC); // Disable the ADC to save power } void loop(){ pinMode(9,INPUT); digitalWrite(9,HIGH); //Internal pull-up attachPcInterrupt(9,wakeUp,FALLING); // attach a PinChange Interrupt on the falling edge pinMode(8,INPUT); digitalWrite(8,HIGH); //Internal pull-up attachPcInterrupt(8,wakeUp,FALLING); // attach a PinChange Interrupt on the falling edge pinMode(7,INPUT); digitalWrite(7,HIGH); //Internal pull-up attachPcInterrupt(7,wakeUp,FALLING); // attach a PinChange Interrupt on the falling edge pinMode(6,INPUT); digitalWrite(6,HIGH); //Internal pull-up attachPcInterrupt(6,wakeUp,FALLING); // attach a PinChange Interrupt on the falling edge pinMode(5,OUTPUT); digitalWrite(5,LOW); pinMode(4,OUTPUT); digitalWrite(4,LOW); pinMode(3,OUTPUT); digitalWrite(3,LOW); pinMode(2,OUTPUT); digitalWrite(2,LOW); set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode sleep_mode(); // Sleep now sleep_disable(); detachPcInterrupt(9); detachPcInterrupt(8); detachPcInterrupt(7); detachPcInterrupt(6); pinMode(5,INPUT); pinMode(4,INPUT); pinMode(3,INPUT); pinMode(2,INPUT); pinMode(9,INPUT); pinMode(8,INPUT); pinMode(7,INPUT); pinMode(6,INPUT); unsigned long ctime=millis(); while(millis()-ctime<1000) { char key = keypad.getKey(); if (key){ digitalWrite(10,HIGH); delay(100); //Wait for the host to wake/become ready Serial.print(key); Serial.flush(); digitalWrite(10,LOW); ctime=millis(); } } }
See it in action, this is a test with a FTDI cable and PuTTY terminal program capturing the output.
So, it is really easy to use on Arduino, Raspeberry PI’s UART and so forth.
I can see how this will end up as a product in the shop 🙂
Very nice idea on setting a Attiny84 in between the keypad and the Arduino.
I think I will apply it to a keypad I have around.
I see there is no XTAL on the pcb, could you explain how you are doing this? I guess using the internal clock? I would like to know if you could explain the code lines for this.
Thanks and great work !
Yes, it is running off the internal oscillator. That by itself also contributes to cutting down the power consumption, plus simplifies the whole setup. It is enabled by setting the fuses
low_fuse=0x62
high_fuse=0xD7
extended_fuse=0xFF
using an ISP programmer
Pingback: Logging manualy entered values to emonCMS using keypad | Martin's corner on the web
Pingback: Keypad as USB keyboard | Martin's corner on the web