Arduino PCA9555 GPIO Expander Reading 4X4 Keypad

by Lewis Loflin

In this series I'll be connecting the PCA9555D 32-bit GPIO expander board to an Arduino micro-controller. First we started out simple with counting from 0 to 255 in binary on eight LEDs. See Part 1 for technical information and getting started.

Here in part two we will connect a 4X4 keypad to an 8-bit port. Using "polling" the routine getKey() we will check for a key press and return a BCD value from 0 to 16 displayed on the eight LEDs.

In part three we will learn to use the interrupt pin to jump to the key scan routine only when a key is pressed. A BCD value is output on the eight LEDs. See Part 3

Here in part four we will connect a type a Hd44780 type LCD display and learn how to enter data and manipulate character date and strings. In addition to the LCD display we will scan a keypad, use hardware interrupts, all connected through a single PCA9555 module. In addition I'll reveal some code little discussed with Arduino and we will convert/manipulate code for output to the LCD display. See Part 4




4X4 keypad used in this demo.

A 4x4 switch matrix is connected to PORT0. Bits 0-3 are programmed as input while bits 4-7 are programmed as output and programmed LOW. Bits 0-3 read HIGH because of internal pull up resistors.

Eight LEDs are connected to PORT1 to display the status of PORT0. They will display the returned value from 1 to 16 in BCD which is displayed on the eight LEDs.

A LED is connected through a 470 ohm resistor to VCC and the INT pin on the module. This displays interrupt on change which is cleared during a read of the port. That is not used in this demo.

In routine getKey() a 4x4 keypad is connected to U1 PORT0. Row is connected to bits 4-7 which are programmed as outputs and all set to zero or LOW. Column is connected to bits 0-3 programmed as inputs and are pulled HIGH by internal pullup. The pull ups are always active if the pin is programmed as an input.

The routine reads the port and does a bitwise AND with 0x0F to mask the high nibble an check to see if the result is greater than zero. If it is that means a key was pressed then it scans the matrix to determine which key was activated and return a value.

Note the electrical state of the pins is inverted when read due to value programmed into polarity register four. See spec. sheet.

The routine resetPort0() must be called after the value is returned to reset the port bits.

In this case we must constantly check getKey() to even see if a key has been pressed.

PCA9555 Demo Board


#include <Wire.h> // specify use of Wire.h library.
int i, j;
byte temp1;


void setup()

{

  Wire.begin();
  Wire.beginTransmission(0x20);  // setup out direction registers
  Wire.write(0x06);  // pointer
  Wire.write(0x0F);  // DDR Port0 bits 0-3 input 4-7 output 
  Wire.write(0x00);  // DDR Port1 all output
  Wire.endTransmission(); 

  Wire.beginTransmission(0x20);  // 
  Wire.write(0x02);  // pointer
  Wire.write(0x00);  // clear bits 4-7 PORT0
  Wire.endTransmission(); 

  Wire.beginTransmission(0x20);  // invert bit
  Wire.write(0x04);  // pointer
  Wire.write(0xFF);  // invert bits PORT0 on read
  Wire.endTransmission(); 

  // clear LEDs PORT1
  Wire.beginTransmission(0x20);  
  Wire.write(0x03); // begin here
  Wire.write(temp1); 
  Wire.endTransmission();

}

void loop() {
  // this routine using polling to scan switches.
  temp1 = getKey();  // get BCD code from keypad if ky pressed
  if ((temp1 != 0x00) && (temp1 <= 0x16))   {
    Wire.beginTransmission(0x20);  
    Wire.write(0x03); // begin here
    Wire.write(temp1); 
    Wire.endTransmission();
    temp1 = 0x00;  // clear temp1
  }  // enf if// end loop



byte getKey()  {

  Wire.beginTransmission(0x20);  
  Wire.write(0);  // set data pointer
  Wire.endTransmission();
  Wire.requestFrom(0x20, 1);
  byte c = Wire.read();
  if ((c & 0x0F) == 0) return 0x00;  // no key pressed


  Wire.beginTransmission(0x20);
  Wire.write(0x02);
  Wire.write(B11100000); // check row L1
  Wire.endTransmission();

  Wire.beginTransmission(0x20);  
  Wire.write(0);  // set data pointer
  Wire.endTransmission();
  Wire.requestFrom(0x20, 1);
  c = Wire.read();
  if ((c & 0x1F) > 0x10) {
    if (c==B00010001) c = 0x01; 
    if (c==B00010010) c = 0x02; 
    if (c==B00010100) c = 0x03; 
    if (c==B00011000) c = 0x04;
    delay(100);
    resetPort0();
    return c;
  }

  Wire.beginTransmission(0x20);
  Wire.write(0x02);
  Wire.write(B11010000); // check row L2
  Wire.endTransmission(); 

  Wire.beginTransmission(0x20);  
  Wire.write(0);  // set data pointer
  Wire.endTransmission();
  Wire.requestFrom(0x20, 1);
  c = Wire.read();
  if ((c & 0x2F) > 0x20) {
    if (c==B00100001) c = 0x05; 
    if (c==B00100010) c = 0x06; 
    if (c==B00100100) c = 0x07; 
    if (c==B00101000) c = 0x08;
    delay(100);
    resetPort0();
    return c;
  }


  Wire.beginTransmission(0x20);
  Wire.write(0x02);
  Wire.write(B10110000); // check row L3
  Wire.endTransmission(); 

  Wire.beginTransmission(0x20);  
  Wire.write(0);  // set data pointer
  Wire.endTransmission();
  Wire.requestFrom(0x20, 1);
  c = Wire.read();
  if ((c & 0x4F) > 0x40) {
    if (c==B01000001) c = 0x09; 
    if (c==B01000010) c = 0x10; 
    if (c==B01000100) c = 0x11; 
    if (c==B01001000) c = 0x12;
    delay(100);
    resetPort0();
    return c;
  }


  Wire.beginTransmission(0x20);
  Wire.write(0x02);
  Wire.write(B01110000); // check row L4
  Wire.endTransmission(); 

  Wire.beginTransmission(0x20);  
  Wire.write(0);  // set data pointer
  Wire.endTransmission();
  Wire.requestFrom(0x20, 1);
  c = Wire.read();
  if ((c & 0x8F) > 0x80) {
    if (c==B10000001) c = 0x13; 
    if (c==B10000010) c = 0x14; 
    if (c==B10000100) c = 0x15; 
    if (c==B10001000) c = 0x16;
    delay(100);
    resetPort0();
    return c;
  }



}

// reset port 0 
void  resetPort0()   {

  Wire.beginTransmission(0x20);  // 
  Wire.write(0x02);  // pointer
  Wire.write(0x00);  // clear bits 4-7 PORT0
  Wire.endTransmission(); 

}

Added June 7, 2013:

You Tube Arduino Microcontroller Video Series March 2012: