Let's look at interfacing a Hex keypad, the one with 16 switches; arranged in 4 columns and 4 rows. The interesting challenge is to interface 16 switches on 8 pins. So how does this work? The simple answer is the MCU is faster than the your fingers.

Basics

Code

#include "keypad.h"
#include "lcd.h"
int main() 
{
    uint8_t key;
 
    /*Connect RS->PB0, RW->PB1, EN->PB2 and data bus PORTB.4 to PORTB.7*/
    LCD_SetUp(PB_0,PB_1,PB_2,P_NC,P_NC,P_NC,P_NC,PB_4,PB_5,PB_6,PB_7);
    LCD_Init(2,16);
 
	/*Connect R1->PD0, R2->PD1, R3->PD2 R4->PD3, C1->PD4, C2->PD5 C3->PD6, C4->PD7 */
    KEYPAD_Init(PD_0,PD_1,PD_2,PD_3,PD_4,PD_5,PD_6,PD_7);
 
    LCD_Printf("Key Pressed:");
    while (1) 
    {
        key = KEYPAD_GetKey();
        LCD_GoToLine(1);
        LCD_DisplayChar(key);
 
    }
 
    return (0);
}

Let's look at the most important function in the code in a little more details

      key = KEYPAD_GetKey();

As you can guess, the function return the ASCII value of the key being pressed. It is defined in keypad.c as below:

uint8_t KEYPAD_GetKey(void)
{
    uint8_t i,j,v_KeyPressed_u8 = 0;
 
 
    keypad_WaitForKeyRelease();
    keypad_WaitForKeyPress();
 
    for (i=0;i<C_MaxRows_U8;i++)
    {
        GPIO_PinWrite(A_RowsPins_U8[i],HIGH); 
    }
 
    for (i=0;(i<C_MaxRows_U8);i++)
    {
        GPIO_PinWrite(A_RowsPins_U8[i],LOW);
 
        for(j=0; (j<C_MaxCols_U8); j++)
        {
            if(GPIO_PinRead(A_ColsPins_U8[j]) == 0)
            {
                v_KeyPressed_u8 = 1;
                break;
            }
        } 
 
        if(v_KeyPressed_u8 ==1)
        {
            break;
        }
 
        GPIO_PinWrite(A_RowsPins_U8[i],HIGH);
    }
 
    if(i<C_MaxRows_U8)
        v_KeyPressed_u8 = A_KeyLookUptable_U8[i][j];
    else
        v_KeyPressed_u8 = C_DefaultKey_U8;
 
 
    return v_KeyPressed_u8;
}