Back to www.micro-examples.com

A Universal Advanced Keypad Library

PIC Keypad Library source code

Getting an input from a user may seem trivial, but in real word it will lead to resolve some problems like switch bounce, input correction, input validation, polling function in each major loop of the program, and so on...

Here is a very convenient way to solve them : this interrupt-based keypad library will do it for you.

Page index :


Why another PIC Keypad LIBRARY ?

There are already tons of keypad PIC libraries on the web, but I think this one will be the most universal and versatile, featuring :

Learn more below :


Library Functions

PROTOTYPE void    kp_init()
PARAMETERS

none

RETURNS nothing
DESCRIPTION

prepare the PIC keypad and button library.
this function must be called before enabling timer interrupt.

REQUIRES

the file keypad_cfg.h must be set accordingly to user's hardware (see below)

EXAMPLE kp_init() ;

PROTOTYPE unsigned char    kp_full()
PARAMETERS

none

RETURNS

return > 0 if the buffer is full, 0 otherwise

DESCRIPTION

check for buffer full

REQUIRES

kp_init() must have been called and timer interrupt must be enabled

EXAMPLE

if(kp_full()) return ; // return if buffer full

PROTOTYPE unsigned char    kp_hit()
PARAMETERS

none

RETURNS

return > 0 if a key is being pressed, 0 otherwise (pseudo function)

DESCRIPTION

check for a key hit

REQUIRES

kp_init() must have been called and timer interrupt must be enabled

EXAMPLE

while(kp_hit()) ; // wait for key to be released

PROTOTYPE unsigned char    kp_enter()
PARAMETERS

none

RETURNS

return > 0 if enter key has been pressed, 0 otherwise (pseudo function)

DESCRIPTION

check for enter key

REQUIRES

kp_init() must have been called and timer interrupt must be enabled

EXAMPLE

if(kp_enter()) { ... } // do input treatment on enter key

PROTOTYPE unsigned char    kp_erase()
PARAMETERS

none

RETURNS

return > 0 if last key was erase , 0 otherwise (pseudo function)

DESCRIPTION

check for erase key

REQUIRES

kp_init() must have been called and timer interrupt must be enabled

EXAMPLE

if(kp_erase()) { ... } // do input treatment on erase key

PROTOTYPE unsigned char    kp_last()
PARAMETERS

none

RETURNS

return last key pressed

DESCRIPTION

get last key

REQUIRES

kp_init() must have been called and timer interrupt must be enabled

EXAMPLE

switch(kp_last()) { ... } // process keys

PROTOTYPE void    kp_setCircular()
PARAMETERS

none

RETURNS nothing
DESCRIPTION

switch on circular mode on input buffer :
when buffer is full, new entry will cause the buffer to be left shifted (character at first position will be lost)
new entry is then added to the end of the buffer.

REQUIRES

kp_init() must have been called and timer interrupt must be enabled

EXAMPLE

kp_setCircular() ;

PROTOTYPE void    kp_setLinear()
PARAMETERS

none

RETURNS nothing
DESCRIPTION

switch on linear mode on input buffer :
when buffer is full, new entry will be ignored.

REQUIRES

kp_init() must have been called and timer interrupt must be enabled

EXAMPLE

kp_setLinear() ;

PROTOTYPE unsigned char    kp_circular()
PARAMETERS

none

RETURNS

return > 0 if input buffer is in circular mode, 0 otherwise.

DESCRIPTION

check for buffer circular mode, default is linear mode.

REQUIRES

kp_init() must have been called and timer interrupt must be enabled

EXAMPLE

if(kp_circular()) kp_setLinear() ;

PROTOTYPE void    kp_setTypematic()
PARAMETERS

none

RETURNS nothing
DESCRIPTION

switch on typematic (auto-repeat) mode

REQUIRES

kp_init() must have been called and timer interrupt must be enabled

EXAMPLE

kp_setTypematic() ;

PROTOTYPE void    kp_unsetTypematic()
PARAMETERS

none

RETURNS nothing
DESCRIPTION

switch off typematic (auto-repeat) mode

REQUIRES

kp_init() must have been called and timer interrupt must be enabled

EXAMPLE

kp_unsetTypematic() ;

PROTOTYPE unsigned char    kp_typematic()
PARAMETERS

none

RETURNS

return > 0 if typematic (auto-repeat) in enable, 0 otherwise.

DESCRIPTION

return typematic state, default is not enabled.

REQUIRES

kp_init() must have been called and timer interrupt must be enabled

EXAMPLE

if(kp_typematic()) kp_unsetTypematic() ;

PROTOTYPE void    kp_flush()
PARAMETERS

none

RETURNS nothing
DESCRIPTION

flush input, buffer is cleared

REQUIRES

kp_init() must have been called and timer interrupt must be enabled

EXAMPLE

kp_flush() ;

PROTOTYPE void    kp_isr()
PARAMETERS

none

RETURNS nothing
DESCRIPTION

this function must not be called directly by user, but must be placed in the timer interrupt() function.

the input is stored in buffer kp_buf, defined as a pointer to char.

REQUIRES

kp_init() must have been called

EXAMPLE

void    interrupt(void)
        {
        if(INTCON.T0IF)                         // timer 0 overflow ?
                {
                kp_isr() ;                      // call keypad service routine

                INTCON.T0IF = 0 ;               // done
                }
        }

Configuration

Keypad configuration is defined in file keypad_cfg.h, you can change it depending on your hardware and preferences :

SYMBOL USAGE EXAMPLE
KEYPAD_MODE define this symbol if you are using a keypad (rows and colums)
do not define this symbol if you are using buttons (colums only)
#define KEYPAD_MODE
KP_ROW_PORT

PORT where rows are connected to
(only if KEYPAD_MODE is defined)

#define KP_ROW_PORT     PORTB
KP_ROW_TRIS TRIS direction register corresponding to KP_ROW_PORT
(only if KEYPAD_MODE is defined)
#define KP_ROW_TRIS     TRISB  
KP_ROW_BITNUM

bit number of the first row in the PORT, other bits must be next and contiguous
(only if KEYPAD_MODE is defined)

#define KP_ROW_BITNUM   0
KP_ROW_NUMBER number of rows
(only if KEYPAD_MODE is defined)
#define KP_ROW_NUMBER   3
KP_COL_PORT PORT where columns are connected to.
Each column input must be pulled down with a 10 K resistor.
#define KP_COL_PORT     PORTB
KP_COL_TRIS TRIS direction register corresponding to KP_COL_PORT #define KP_COL_TRIS     TRISB
KP_COL_BITNUM bit number of the first row in the PORT, other bits must be next and contiguous #define KP_COL_BITNUM   3
KP_COL_NUMBER number of columns #define KP_COL_NUMBER   4
KP_SCAN_CODES

scan codes lookup table
keypad must be considered this way :
keypad orientation

the top left key is the first one, the bottom right key is the last one.
you have to read from top to bottom and from left to right : * 7 4 1 0 8 5 2 # 9 6 3

#define KP_SCAN_CODES   "*7410852#963"
KP_ERASE

erase key, must be one in KP_SCAN_CODES string
don't define it if you don't need an erase key

#define KP_ERASE        '*'
KP_ENTER enter key, must be one in KP_SCAN_CODES string
don't define it if you don't need an enter key
#define KP_ENTER        '#'
KP_MAX_LENGTH maximum input length #define KP_MAX_LENGTH   16
KP_TMR_REPEAT

typematic rate, must be set depending on timer overflow period and user's preferences.
you can use this formula :
KP_TMR_REPEAT = (Fosc / 4 / TMR_PRESCALER / (2 ^ TMR_BITS)) * DELAY_REPEAT
where :
Fosc is the frequency of the oscillator in Herz. For example if you are using a 8 Mhz crystal with HS clock mode, then Fosc = 8000000
TMR_PRESCALER is the prescaler (or postscaler if any) value of your timer. For example if you are using a 1:1 prescaler then TMR_PRESCALER = 1
TMR_BITS is the number of bits of your timer, it is either 8 or 16
DELAY_REPEAT is the delay in second before the next auto repeat.

when using a PIC16F877A @ 8 Mhz with 8 bit TMR0 and no prescaler, if you want an auto repeat rate of 300 ms, use :
KP_TMR_REPEAT = (8000000 / 4 / 1 / (2 ^ 8)) * .3 = 2343

#define KP_TMR_REPEAT   2343
KP_TMR_DEBOUNCE

debounce time, must be set depending on timer overflow period and user's preferences.
you can use this formula :
KP_TMR_DEBOUNCE = (Fosc / 4 / TMR_PRESCALER / (2 ^ TMR_BITS)) * DEBOUNCE_DELAY
where :
Fosc is the frequency of the oscillator in Herz. For example if you are using a 8 Mhz crystal with HS clock mode, then Fosc = 8000000
TMR_PRESCALER is the prescaler (or postscaler if any) value of your timer. For example if you are using a 1:1 prescaler then TMR_PRESCALER = 1
TMR_BITS is the number of bits of your timer, it is either 8 or 16
DEBOUNCE_DELAY is the delay in second before the keyboard to be read again.

when using a PIC16F877A @ 8 Mhz with 8 bit TMR0 and no prescaler, if you want a debounce time of 30 ms, use :
KP_TMR_DEBOUNCE  = (8000000 / 4 / 1 / (2 ^ 8)) * .03 = 234

#define KP_TMR_DEBOUNCE   234
KP_MAX_LENGTH maximum input length #define KP_MAX_LENGTH   16


CIRCUIT EXAMPLE

Click on the picture to enlarge

Keypad library schematic example

Columns must be pulled down, use resistors from 4K7 to 22K.

Don't forget that columns are from bottom to top, and rows for left to right. This arrangement is due to code simplification, because library can work with buttons too.

If you use buttons only instead of keypad, they must also be pulled down.
In this case, there is no row but only columns.

 


MIKROC SOURCE CODE EXAMPLE

Here is the mikroC source code of the program example. You have to use the zipped mikroC project to build it.

/*
 *******************************************************************************
 * PIC ADVANCED UNIVERSAL KEYPAD LIBRARY
 *******************************************************************************
 *
 * source code example for mikro C compiler
 * feel free to use this code at your own risks
 *
 * target : PIC16F877A, 8 Mhz crystal
 * HS clock, no watchdog.
 *
 * Author : Bruno Gavand, October 2007
 * see more details on http://www.micro-examples.com/
 *
 * This program shows how to use the library :
 *  4 bit LCD is connected to PORTD (EasyPIC4 board)
 *  edit keypad_cfg.h header file to configure your own keypad
 *
 * LCD Line 1 : welcome message and keypad status symbols
 * LCD Line 2 : string as keyed in by user
 *
 * type 123 + enter to toggle circular/linear buffer mode
 * type 321 + enter to toggle typematic mode on/off
 *
 *******************************************************************************
 */
#include        "keypad_lib.h"          // keypad library header, includes also user's settings

/*
 * LCD custom characters
 */
const char erase_char[] = {2,6,14,31,14,6,2,0} ;        // erase key typed
const char enter_char[] = {1,1,5,13,31,12,4,0} ;        // enter key typed
const char full_char[] = {0,10,21,10,21,10,0,0} ;       // buffer is full
const char hit_char[] = {0,4,4,4,31,14,4,0} ;           // a key is pressed
const char circ_char[] = {16,24,28,25,19,7,3,1} ;       // buffer is in circular mode
const char type_char[] = {31,21,21,4,4,4,4,14} ;        // typematic enabled

/*
 * print custom character pointed to by def at line pos_row column pos_char on LCD
 */
void CustomChar(const char *def, unsigned char n, char pos_row, char pos_char)
        {
        char    i ;

        LCD_Cmd(64 + n * 8) ;
        for(i = 0 ; i <= 7 ; i++)
                {
                LCD_Chr_Cp(def[i]) ;
                }
        LCD_Cmd(LCD_RETURN_HOME) ;
        LCD_Chr(pos_row, pos_char, n) ;
        }

/*
 * interrupt routine, called on each timer0 overflow
 */
void    interrupt(void)
        {
        if(INTCON.T0IF)                         // timer 0 overflow ?
                {
                kp_isr() ;                      // call keypad service routine

                INTCON.T0IF = 0 ;               // done
                }
        }

/*
 * program entry
 */
void    main()
        {
        /*
         * init LCD
         */
        LCD_Init(&PORTD) ;
        LCD_Cmd(LCD_CLEAR) ;
        LCD_Out(1, 1, "KeypadLib") ;
        LCD_Cmd(LCD_SECOND_ROW) ;

        /*
         * init keypad and library
         */
        kp_init() ;

        /*
         * configure timer0 rollover interrupt
         * period is Fosc / 4 / 256
         */
        OPTION_REG = 0x80 ;                     // start timer 0, no prescaler
        INTCON = 0xA0 ;                         // allow timer 0 interrupt

        for(;;)                                 // forever
                {
                if(kp_hit())                    // if a key is pressed
                        {
                        LCD_Cmd(LCD_CURSOR_OFF) ;                       // no cursor
                        CustomChar(hit_char, 1, 1, 12) ;                // display hit symbol

                        if(kp_enter())                                  // if enter key is pressed
                                {
                         	CustomChar(enter_char, 2, 1, 13) ;

                                if(strcmp(kp_buf, "123") == 0)          // if entry is 123
                                        {
                                        if(kp_circular())               // toggle buffer circular/linear mode
                                                {
                                                kp_setLinear() ;
                                                }
                                        else
                                                {
                                                kp_setCircular() ;
                                                }
                                        }
                                else if(strcmp(kp_buf, "321") == 0)          // if entry is 321
                                        {
                                        if(kp_typematic())               // toggle typematic (auto-repeat) mode
                                                {
                                                kp_unsetTypematic() ;
                                                }
                                        else
                                                {
                                                kp_setTypematic() ;
                                                }
                                        }
                                kp_flush() ;                            // clear entry buffer
                                }
                        else
                                {
                                LCD_Chr(1, 13, ' ') ;
                                }

                        /*
                         * buffer full symbol
                         */
                        if(kp_full())
                                {
                         	CustomChar(full_char, 0, 1, 11) ;
                                }
                        else
                                {
                                LCD_Chr(1, 11, ' ') ;
                                }

                        /*
                         * erase key symbol
                         */
                        if(kp_erase())
                                {
                         	CustomChar(erase_char, 3, 1, 14) ;
                                }
                        else
                                {
                                LCD_Chr(1, 14, ' ') ;
                                }

                        /*
                         * circular mode symbol
                         */
                        if(kp_circular())
                                {
                         	CustomChar(circ_char, 4, 1, 15) ;
                                }
                        else
                                {
                                LCD_Chr(1, 15, ' ') ;
                                }

                        /*
                         * typematic mode symbol
                         */
                        if(kp_typematic())
                                {
                         	CustomChar(type_char, 5, 1, 10) ;
                                }
                        else
                                {
                                LCD_Chr(1, 10, ' ') ;
                                }

                        LCD_Chr(1, 16, kp_last()) ;                     // display last char keyed in
                        LCD_Chr(1, 12, ' ') ;                           // clear hit symbol

                        LCD_Out(2, 1, "                ") ;             // clear old buffer display
                        LCD_Out(2, 1, kp_buf) ;                         // display current buffer

                        LCD_Cmd(LCD_BLINK_CURSOR_ON) ;                  // blink cursor
                        }
                }
        }

PROJECT DOWNLOAD

You can use this software as you wish, if you accept to do it at your own risks.

Download PIC Keypad Library C source code with demo example for mikroC : zipped file, 6 Ko 

content of the archive :

You can get mikroC from here : http://www.mikroe.com/en/compilers/mikroc/pic/


Please report any bug, comment or suggestion in my forums. Thanks !