Fads to Obsessions and Beyond...




Free domain for life, exceptional technical support, website transfer

Matrix Keypad Interfaced to PIC

Interfacing a matrix keypad (4 x 4 keys) to a PIC microcontroller is demonstrated. A scanning technique is used to minimise required I/O pins. A PCF8574 port expander is alternatively used to provide 2-wire connection between the PIC and the matrix keypad.

Typical microcontroller projects generally require user input. Simple "on/off" functionality or similar can be provided by simple switches such as single-pole, single-throw (SPST) single-pole, double-throw (SPDT) etc. However, a matrix keypad is advantageous in providing a large number of keys with minimum usage of I/O pins on the microcontroller. Also, a matrix keypad obviously enables a user to easily enter alphanumeric data etc.

Matrix keypads are simply a series of tactile switch inputs arranged in a matrix (duh!). Each tactile switch (i.e., key) is located at the intersection of the matrix rows and columns. When a key is pressed, the row and column make an electrical contact. The microcontroller is connected to the rows and colums via I/O pins, and firmware then scans the rows and columns in order to determine which key (if any) has been pressed. The actual logic for the scanning process is explained on numerous internet sites, for example (1).

This rows and columns scanning technique requires N I/O pins on the microcontroller to read a keypad matrix of (N/2)2 keys (e.g., 8 I/O pins enables a (8/2)2 = 16 keys (4 x 4 keypad). A technique known as Charlieplexing (2), involving the additional use of diodes in the circuitry, enables N I/O pins on the microcontroller to read a keypad matrix of N2-2 keys (e.g., 4 I/O pins enables a 42-4 = 16 keys (4 x 4 keypad). Thus Charlieplexing a typical 4x4 keypad would only require 4 I/O pins compared to 8 I/O pins of the "scanning" technique.

A further way to decrease the required number of I/O pins to interface a matrix keypad is to use a port expander IC. The PCF8574 utilises a I2C bus that only requires two microcontroller I/O pins to control eight address pins (and hence 2 I/O pins to control a 4x4 keypad using the "scanning" technique).

See the various sections below for circuit details, schematic diagrams, software/firmware and other details.


The schematic for a 4x4 keypad with connections to a PIC18F248 is given in the Schematics Section below. The ancillary circuitry for the PIC18F248 also includes connection to a LCD to display the results of a keypress. Schematics for connecting the 4x4 keypad directly to the PIC18F248 (i.e., using 8 I/O pins and the "scanning" technique) and via the PCF8574 port expander are included.

Power Supply

A typical "wall-wart" power-supply is used (a surplus laptop charger in this case) in conjunction with a voltage regulator (LM317T) to provide the regulated 5V required by the PIC microcontroller. This is done via the DIY PIC development board.

Firmware/Software

The Testing/Experimental Results Section details the firmware (written in CSS C code) required to scan the keypad to determine key presses.

The PCF8574 provides simple digital control and a serial interface for control/retrieval of data using the I2C protocol, and the necessary firmware is detailed in the Testing/Experimental Results Section


Note: Image loading can be slow depending on server load.

  • Matrix Keyboard to PIC SchematicMatrix Keyboard to PIC Schematic

    Silver Membership registration gives access to full resolution schematic diagrams.

    Matrix Keyboard to PIC Schematic

  • Matrix Keyboard to PIC

  • Matrix Keyboard via Port ExpanderMatrix Keyboard via Port Expander Schematic

    Silver Membership registration gives access to full resolution schematic diagrams.

    Matrix Keyboard via Port Expander Schematic

  • Matrix Keyboard via Port Expander


This project did not require a PCB.

The construction was done using a DIY PIC development board. See the photographs and schematic diagram sections.

Qty Schematic Part-Reference Value Notes/Datasheet
Resistors
5R1,R4-R710K1/4W, 10% 
2R2,R34K71/4W, 10% 
1RV110K pot.potentiometer
Diodes
1D21N4002
Integrated Circuits
1U1PIC18F248PIC microcontroller datasheet
1U27805Linear Voltage Regulator  datasheet
1U3PCF8574PCF8574 datasheet
Capacitors
2C1,C222pFceramic disk
1C30.33uFaluminium or tantalum electrolytic
1C40.1uFaluminium or tantalum electrolytic
Miscellaneous
1J1CONN-H55-pin connector for ICSP
1SW1SW-SPDT 
1X110MHzCrystal Oscillator
1Z1keypad4x4 keypad
1LCD1LCDLiquid Crystal Display
Description Downloads
Matrix Keypad - Bill of Materials Text File Download

Both the rows and columns scanning technique (called "Direct Connection" below - 8 PIC I/O pins for a 4x4 keypad matrix) and the use of the PCF8574 port expander (2 PIC I/O pins for a 4x4 keypad matrix) were constructed and tested.

"Direct" Connection to I/O pins

The direct connection of the 4x4 keypad matrix to the PIC 18F248 in terms of the physical circuitry is straight forward (see the Schematics Section). The "rows" of the keypad matrix require 10k pullup resistors (although the option of using the PIC port internal pullups can be used, if the port has this option). Which sets of connection pins of the keypad matrix are defined as "rows" and "columns" is not important, and are defined using the settings in the firmware file "KBC.c" (#define statements for the I/O pins and the KEYS array).

The following code is a listing of "KBC.c" which performs the scanning of the matrix keypad to determine which key, if any, has been pressed. The function kbd_getc() is repeatly called from the main program loop to poll the keypad.


 
#define row0 PIN_C4 //Keypad I/O pins 
#define row1 PIN_C5 
#define row2 PIN_C6 
#define row3 PIN_C7 
#define col0 PIN_C0 
#define col1 PIN_C1 
#define col2 PIN_C2 
#define col3 PIN_C3 

// set the keypad layout 
char const KEYS[4][4] = 
{{'u','d','A','B'}, 
 {'7','4','1','*'}, 
 {'8','5','2','0'}, 
 {'9','6','3','#'}}; 

#define KBD_DEBOUNCE_FACTOR 33 

void kbd_init() { //if external pullups not used
    //set_tris_b(0xF0); 
    //output_b(0xF0); 
    //port_b_pullups(true);  
} 

short int ALL_ROWS (void) { 
    if(input (row0) & input (row1) & input (row2) & input (row3)) 
       return (0); 
    else 
       return (1); 
} 

char kbd_getc() { 
    static byte kbd_call_count; 
    static short int kbd_down; 
    static char last_key;     
    byte col, kchar, row; 
    
    kchar='\0';     
    if(++kbd_call_count>KBD_DEBOUNCE_FACTOR) { 
       switch (col) { 
          case 0: 
            output_low(col0); output_high(col1); output_high(col2); output_high(col3); 
            break;       
          case 1: 
            output_high(col0); output_low(col1); output_high(col2); output_high(col3); 
            break; 
          case 2: 
            output_high(col0); output_high(col1); output_low(col2); output_high(col3); 
            break; 
          case 3: 
            output_high(col0); output_high(col1); output_high(col2); output_low(col3); 
            break; 
       }     
       if(kbd_down) { 
          if(!ALL_ROWS()) { 
             kbd_down=false; 
             kchar=last_key; 
             last_key='\0'; 
          } 
       } else { 
          if(ALL_ROWS()) { 
             if(!input (row0)) row=0; 
             else if(!input (row1)) row=1; 
             else if(!input (row2)) row=2; 
             else if(!input (row3)) row=3; 
             last_key =KEYS[row][col]; 
             kbd_down = true; 
          } else { 
             ++col; 
             if(col==4) col=0; 
          } 
       } 
       kbd_call_count=0; 
   } 
   return(kchar); 
} 

The following is an example of how to use "KBC.c" to get a key press from a 4x4 keypad matrix and display the result on a LCD.



#include <PIC18F248.h>
#include <LCD.C>
#include <KBD.C>
#zero_ram //all variables automatically initialised to 0

#define LCD_ENABLE_PIN PIN_B0
#define LCD_RS_PIN PIN_B1
#define LCD_RW_PIN PIN_B2
#define LCD_DATA4  PIN_B4
#define LCD_DATA5  PIN_B5
#define LCD_DATA6  PIN_B6
#define LCD_DATA7  PIN_B7

void main() {
   int k;   
   lcd_init();
   kbd_init();      
   delay_ms(1000);
   
   lcd_putc("\fInput\n");
   lcd_putc("here:");
   output_c (0x00); //clear port C   

   do {
      k=kbd_getc();
      if(k!=0)
        if(k=='*') { //'*' = 'clear screen'
          lcd_putc("\fInput\n");
          lcd_putc("here:"); }
        else
          lcd_putc(k);
   } while (TRUE);
}

Keypad via PCF8574 port expander

The use of a "port expander" IC is a handy technique in general for minimising the number of I/O pins required from a PIC microcontroller to interface peripherals. The PCF8574 provides general purpose remote I/O expansion via the I2C protocol. The device consists of an 8-bit quasi-bidirectional port, the I2C-bus interface and three hardware address pins which allows for use of up to 8 PCF8574 devices in a circuit (i.e., it is possible to have 8 PCF8574 x 8 pins = 64 I/O pins controlled by 2 I/O pins from a PIC microcontroller).

The downside of this additional functionality is of course added complexity of the circuit (although this is not particularly onerous - see the Schematics Section) and of the firmware.

The driver code for the PCF8574 is given below in the Downloads Section. This code enables setting of I2C control pins on the PIC microcontroller and the hardware address (or addresses) of the PCF8574.

The file "KDB_I2C.c" (available in the Downloads Section) contains the revised code to utilise the PCF8574 to scan an attached keypad matrix (4x4 matrix in this case). As for the "direction connection" method, the function kbd_getc() is repeatly called from the main program loop to poll the keypad. Therefore, with the additional of the include files for the PCF8574 and "KDB_I2C.c" the main program loop/code does not require any changes.


Downloads

Description Downloads
PCF8574 port expander header file PCF8574 source code
Keypad Matrix with PCF8574/I2C KDB with I2C source code
Keypad Matrix scanning header file KBD source code

The Schematic Diagram Section contains schematics for connecting a 4x4 keypad matrix directly to a PIC microcontoller (using 8 I/O pins) and by using a PCF8574 port expander IC (which enables connection using only 2 I/O pins on the microcontoller).

If the PIC microcontroller port being used does not have internal pullups, external pullup resistors (as shown in the schematics) are required for the "rows" of the keypad matrix.

If multiple PCF8574 port expander IC's are being used (e.g. to interface a LCD as well as a matrix keypad) the SCL and SDA pins/lines to the micrcontroller only require a single set of pullup resistors (do not need pullup resistors on the SCL and SDA lines at each PCF8574).

The interface code (KBD.c and KBD_I2C.c - see the Downloads in the Testing/Experimental Results Section) contains a variable KBD_DEBOUNCE_FACTOR which provides a simple key debouncing method. The value of KBD_DEBOUNCE_FACTOR should be altered to give the desired behaviour with the particular keypad matrix being used.

Comments/Questions

No comments yet.

Add Comment/Question

Only Logged-In Members can add comments

"If we could sell our experiences for what they cost us, we'd all be millionaires".

Please donate any amount to help with hosting this web site.

If you subscribe (only $2/annum) you can view the site without advertisements and get emails abouts updates etc.

X

Sorry!

Only logged-in users with Silver Membership and above can download.


Silver Membership is only $2, so join now!