Notes About Working with Various Arduino & Netduino Microcontroller Boards

Thursday, January 24, 2013

I2C Version of Using the 4x4 Universal 16 Key Keypad for Arduino

A while back I posted about using the 4x4 Universal 16 Key Keypad for Arduino. One drawback to the parallel connection is that it requires 8 digital pins for the connections. There is an alternative approach that uses an PCF8574(P) I/O expander (datasheet) that connects to the Arduino Uno via I2C using just 2 data lines.

This example uses Joe Young's Keypad_I2C library (which, in turn, requires the Keypad library from the Arduino Playground).  

Pins A0 - A2 on the I/O expander determine the I2C address. This example uses 0x20. See this post for information on using other addresses. 

Connections:


The pin to the left of the "dot" on the PCF8574P is pin 1 (assuming the dot is in the 12 o'clock position). The other pins are numbered down the left side and up the right (counterclockwise). The lines on the keypad are numbered left to right with the keypad face up with the wires pointing downward.

PCF8574P  Pin 1 (A0)  -->  GND  
          Pin 2 (A1)       GND
          Pin 3 (A2)       GND
          Pin 4 (P0)       Keypad line 1
          Pin 5 (P1)       Keypad line 2
          Pin 6 (P2)       Keypad line 3
          Pin 7 (P3)       Keypad line 4
          Pin 8 (VSS)      GND
          Pin 9 (P4)       Keypad line 5
          Pin 10 (P5)      Keypad line 6
          Pin 11 (P6)      Keypad line 7
          Pin 12 (P7)      Keypad line 8
          Pin 13 (/INT)    --Not Used--
          Pin 14 (SCL)     Arduino SCL
          Pin 15 (SDA)     Arduino SDA
          Pin 16 (VDD)     5V
          

Code:



#include <Wire.h>
#include <Keypad_I2C.h>
#include <Keypad.h>

const byte ROWS = 4; 
const byte COLS = 4; 

char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};

byte rowPins[ROWS] = {0,1,2,3}; 
byte colPins[COLS] = {4,5,6,7};

int i2caddress = 0x20;

Keypad_I2C kpd = Keypad_I2C( makeKeymap(keys), rowPins, colPins, ROWS, COLS, i2caddress );

void setup(){
  Serial.begin(9600);
  kpd.begin();
}

void loop(){
  char key = kpd.getKey();
  if (key){
    Serial.println(key);
  }
}


Note: This code does not work with the Arduino Due.   


26 comments:

  1. great article.. found this very useful! thanks

    ReplyDelete
    Replies
    1. Hi Cygnetuk -

      I'm glad you found it helpful. The keypad posts get many more pageviews each day than I ever would have guessed.



      Delete
  2. Really really helpful Brad, thanks a ton!!

    ReplyDelete
  3. Great help Brad!

    Unfortunately does not like to run with Adafruit's and/or also the same issue with SD card librarys. I have to figure out how to solve.

    ReplyDelete
    Replies
    1. Hi Jorge -

      Are you using the Adafruit 3 x 4 keypad (http://www.adafruit.com/products/419), or is it a different one that is causing you problems?

      --Brad

      Delete
    2. Hi Brad,

      I do not know how it happened but I guess I've made a typo. I mean it doesn't run with Adafruit's "Adafruit_PCD8544.h" or "Adafruit_GFX.h" LCD libraries. It reboots over and over.
      I'm also getting the same problem if I would use SD card library "SD.h" library in the same sketch.
      I'm using 4x4 keypad. Running "Joe Young's Keypad_I2C library" it's own works fine.

      -Jorge-

      Delete
    3. Hi Jorge -

      Hmmm... I'm not sure why the Adafruit libraries would cause a problem. I know that it is not the same setup as you have, but in testing this mode of keypad input with the SainSmart 12864 Graphic LCD Display and u8glib library, I found that the pause in the draw() loop made the program unresponsive to key presses. Removing the delay resolved the problem and did not impact the display. Does your code have such a delay() call that could be getting in the way?

      Delete
    4. Hi Brad,

      Thank you for your idea.
      I don't have any delay() instruction on my code and inside the LCD library also.
      I have learned from other guys in some google searches I've made for this particular phenomena that in some way it might crush because of SPI speed for the LCD should not go beyond 4Mhz and the SPI speed usually is 16MHz (internally on the core).
      Also Adafruit's _PCD8544 library might not withstand SPI hardware communication so good at the same time as software SPI communication which is the one is using...
      Anyhow, I've used just a quarter speed on hadware SPI and no good. I'm also trying to find a solution changing all my code and do several tests.
      If I come up with a solution I will post it.

      Delete
  4. Replies
    1. Hi Grumpf -

      I'm glad to hear that you found this useful, and that it worked for your purposes.

      Delete
  5. Hi! Great article! I have one question. I'm amateur in writing programs.I have Arduino Uno, 3 expanders PCF8574AP and one of them I want use for keypad (like in your example) and another like Outputs with library PCF8574.h .How to write it, because when I try write I still get errors. Can you help me?

    ReplyDelete
    Replies
    1. Hi Marcin -

      Have you set the 3 expanders to different I2C addresses (as noted in the post)? Can you tell me more about the error you are seeing?

      Delete
    2. Ofcourse I gave three diffrent adresses. Error is: 'expected unqualified-id before numeric constant'
      Probably i have to big mess in this program:P If you want I can send you my code and i will describe all my project on mail, but please send me your e-mail.

      Delete
    3. Hi Marcin -

      Okay, so I was hoping it would be the obvious mistake and would therefore be easier to fix! It may just be a problem of too many (or too few) semicolons or unmatched comment delimiters. You can use my Gmail address to send your code: bbberkland(*at*)gmail.com. I'll see if I can spot the problem.

      Delete
  6. Hi Brad! Did you get my message?

    ReplyDelete
  7. Dont we need Pullup Resistors on SDL and SDA..?

    ReplyDelete
  8. Do I need pull down resistors in the columns P0-P4?

    ReplyDelete
    Replies
    1. Hi Carlos -

      No need need for pull-ups or pull-downs. The The IC must have the required pull-ups built in.

      --Brad

      Delete
    2. Looking at the data sheet for the PCF8574, it looks like it has weak internal pull-ups that must be enough for this application. I've used this setup without any external resistors and never had a problem.

      --Brad

      Delete
  9. does not work for me on arduino 1.6.5. .(

    ReplyDelete
    Replies
    1. I don't remember what version of the IDE I used with this the last time. I'll have to get the latest and give it a try. Which Arduino board are you using?

      Delete
  10. Worked like a charm, thanks for tip!

    ReplyDelete
  11. I did everything and copied the code too but mine isn't working. I am using I2C PCF8574AT converter.

    ReplyDelete
  12. Hello, thank you very much for the information
    Simple and effective
    I only have to adjust the num. From rows
    And works at 100%
    Thank you

    ReplyDelete