• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Matrix keypad programming

Status
Not open for further replies.

Parth86

Member
I am trying to write program for matrix keypad. I am working with 8051 and keil

I think I can't write whole program so I have started with function's and I hope you will help me to complete program

C:
#include<reg51.h>

#define port P3           /* Data pins connected to port P1 */

sbit RS = P2^0;           /* RS pin connected to pin 0 of port P2 */
sbit RW = P2^1;           /* RW pin connected to pin 1 of port P2 */
sbit EN = P2^3;           /* EN pin connected to pin 2 of port P2 */

sbit R1   = P1^0;         /*Row 1 */
sbit R2   = P1^1;         /*Row 2 */
sbit R3   = P1^2;         /*Row 3 */
sbit R4   = P1^3;         /*Row 4 */

sbit C1   = P1^4;         /*Column 1 */
sbit C2   = P1^5;         /*Column 2 */
sbit C3   = P1^6;         /*Column 3 */
sbit C4   = P1^7;         /*Column 4 */

void DelayUs(unsigned int wait);
void DelayMs(unsigned int wait);
void LCD_Command(unsigned char cmd);
void LCD_Data(unsigned char Data);
void LCD_init();


/* functions for delay */
 void DelayUs(unsigned int wait)
   {
     wait >>= 3;
      while(wait--);
   }

 void DelayMs(unsigned int wait)
   {
      while(wait--)
      DelayUs(1000);
       }

/* Function to send command instruction to LCD */
void LCD_Command(unsigned char cmd)
{
    port = cmd;
    RS=0;
    RW=0;
    EN=1;
    DelayMs(5);
    EN=0;
}
/*Function to send display dato LCD */
void LCD_Data(unsigned char Data)
{
    port = Data;
    RS=1;
    RW=0;
    EN=1;
    DelayMs(5);
    EN=0;
}
 /* Function to prepare the LCD */
void LCD_init()
{
    LCD_Command(0x38);
    DelayMs(15);
    LCD_Command(0x0f);
    DelayMs(15);
    LCD_Command(0x01);
    DelayMs(15);
    LCD_Command(0x81);
    DelayMs(15);
}
 
    char keypad(void)
    {
    unsigned char keymask = 0xEF;
    char key = 0, row;
    for(row=0;row < 3; row++)     
        {
          P2 = keymask; 
          if(!C1) key = 1; 
          if(!C2) key = 2;
          if(!C3) key = 3; 
          if(!C4) key = 4;

                   if(key)
            {   
              key += (row*4); 
              return key;
            }
                keymask <<= 1; 
         keymask ++;     
       }         
    return key;
    }
 
void LCD_goto( char x, char y)
   {
     int addr = 0x80; 
     if(y==2) addr+=0x40;
     addr += x; 
     LCD_Command(addr);
   }
Do you think all the functions are correct? Should I write main function?
 

Pommie

Well-Known Member
Most Helpful Member
Your rows are on P1.0 to P1.3 but your mask is 0xEF which has all rows high.

Assuming you have week pullups on C1 to C4 then you can read the whole keypad into one 16 bit variable.

Code:
uint16_t keys;
    for(row=0x80;row!=0x08;row>>=1){
        keys<<=4;        //pre shift keys
        P1=255-row;      //write row mask
        keys|=P1&0x0f;   //OR in the cols
    }
The for loop goes 0x80, 0x40, 0x20 and 0x10 which is the row position.
It is subtracted from 255 to get the inverse mask.
The bottom 4 bits of P1 are ORed into (an already shifted left) keys.
keys will now contain a set bit for each key pressed.

Mike.
 
Last edited:

Parth86

Member
Your rows are on P1.0 to P1.3 but your mask is 0xEF which has all rows high.
Mike.
I have set bit for row and column on P1

What's wrong with this

P1 =oxEF [1110 1111] Making row 1,2,3 and coulomb 0,1,2,3 high and row 0 low.
 

Pommie

Well-Known Member
Most Helpful Member
Sorry, I original read the rows and columns the other way around.

Do you understand the code I posted above?

Mike.
 

Parth86

Member
Sorry, I original read the rows and columns the other way around.

Do you understand the code I posted above?

Mike.
No. Do you understand keypad function in program. I have tested it on PC by making simple c program it return 16 numbers
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Do you think all the functions are correct? Should I write main function?
No! I had the keypad on P2 not P1... That's me being lazy P2 should be defined "KEY_PORT" to make it more transferable...

EDIT!! You also need to "map" the return values to a known state..

Ie.. 1 may not return 1..
 

Parth86

Member
I Know... But the example is for a 3 x 4 keypad...
OK I will follow your example for 3 x 4 keypad and try to implement

C:
#include<reg51.h>

#define port P1          /* Data pins connected to port P1 */

sbit RS = P3^0;           /* RS pin connected to pin 0 of port P2 */
sbit RW = P3^1;           /* RW pin connected to pin 1 of port P2 */
sbit EN = P3^3;           /* EN pin connected to pin 2 of port P2 */

sbit R1   = P2^0;         /*Row 1 */
sbit R2   = P2^1;         /*Row 2 */
sbit R3   = P2^2;         /*Row 3 */
sbit R4   = P2^3;         /*Row 4 */

sbit C1   = P2^4;         /*Column 1 */
sbit C2   = P2^5;         /*Column 2 */
sbit C3   = P2^6;         /*Column 3 */

/* functions for delay */
 void DelayUs(unsigned int wait)
   {
     wait >>= 3;
      while(wait--);
   }

 void DelayMs(unsigned int wait)
   {
      while(wait--)
      DelayUs(1000);
       }

/* Function to send command instruction to LCD */
void LCD_Command(unsigned char cmd)
{
    port = cmd;
    RS=0;
    RW=0;
    EN=1;
    DelayMs(5);
    EN=0;
}
/*Function to send display dato LCD */
void LCD_Data(unsigned char Data)
{
    port = Data;
    RS=1;
    RW=0;
    EN=1;
    DelayMs(5);
    EN=0;
}
 /* Function to prepare the LCD */
void LCD_init()
{
    LCD_Command(0x38);
    DelayMs(15);
    LCD_Command(0x0f);
    DelayMs(15);
    LCD_Command(0x01);
    DelayMs(15);
    LCD_Command(0x81);
    DelayMs(15);
}

void LCD_goto( char x, char y)
   {
     int addr = 0x80;
     if(y==2) addr+=0x40;
     addr += x;
     LCD_Command(addr);
   }
 
 char keypad(void)
 {
    unsigned char keymask = 0xEF;
    char key = 0, row;
    for(row=0;row < 3; row++) 
        {
          P2 = keymask;
          if(!C1) key = 1;
          if(!C2) key = 2;
          if(!C3) key = 3;

                   if(key)
            {
              key += (row*4);
              return key;
            }
                keymask <<= 1;
         keymask ++; 
       }     
    return key;
    }
 
Last edited:

be80be

Well-Known Member
I posted code that works you just change it for your chip ports
This work really good
Code:
#define row1port LATDbits.LATD0
#define row2port LATDbits.LATD1
#define row3port LATDbits.LATD2
#define row4port LATDbits.LATD3
#define col1port PORTDbits.RD4
#define col2port PORTDbits.RD5
#define col3port PORTDbits.RD6
#define col4port PORTDbits.RD7   //if a 4x4 keypad is used
#define row1tris TRISDbits.TRISD0
#define row2tris TRISDbits.TRISD1
#define row3tris TRISDbits.TRISD2
#define row4tris TRISDbits.TRISD3
#define col1tris TRISDbits.TRISD4
#define col2tris TRISDbits.TRISD5
#define col3tris TRISDbits.TRISD6
#define col4tris TRISDbits.TRISD7 
#include <xc.h> // include processor files - each processor file is guarded. 
char const keyPadMatrix[] = 
{ 
    '1','2','3','4',
    '5','6','7','8',
    '9','0','A','B',
    'C','D','E','F',
    0xFF
};
void ScanKeyMatrixInit()
{
    // we scan the keypad by turning on the row outputs and 
    // reading the columns 
    row1tris = 0;
    row2tris = 0;
    row3tris = 0;
    row4tris = 0;
    col1tris = 1;
    col2tris = 1;
    col3tris = 1;
    col4tris = 1;
}
char ScanKeyMatrix()
{
    // This routine returns the first key found to be
    // pressed during the scan.
    char key = 0, row;
   
    for( row = 0b00000001; row < 0b00010000; row <<= 1 )
    {       
        {   // turn on row output
            row1port = (row & 0x0001)>>0;
            row2port = (row & 0x0002)>>1;
            row3port = (row & 0x0004)>>2;
            row4port = (row & 0x0008)>>3;
            __delay_ms(1);
        }
       
        // read colums - break when key press detected
        if( col1port )
            break;
        key++;
        if( col2port )
            break;
        key++;
        if( col3port )
            break;
        key++;
        if( col4port )
            break;
        key++;
    }
    row1port = 0;
    row2port = 0;
    row3port = 0;
    row4port = 0;
       
    return keyPadMatrix[ key ]; 
}
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
I have spent lot of time to make my program but still I am struggling
please help me Ian Rogers
I try... But you don't seem to do what I suggest.

Which version of proteus are you using.. I will send My file that works.. THEN!! we can talk about why / when once you digest..

The trouble is, the file is at home so you have to wait a few hours..
 

be80be

Well-Known Member
It came from came from 8051 I been messing with this for 2 days I ported it to a 16f15376 and 16f 876
Only problem I have is the uart it can show the keys tho
Code:
#define row1port LATDbits.LATD0
#define row2port LATDbits.LATD1
#define row3port LATDbits.LATD2
#define row4port LATDbits.LATD3
#define col1port PORTDbits.RD4
#define col2port PORTDbits.RD5
#define col3port PORTDbits.RD6
#define col4port PORTDbits.RD7   //if a 4x4 keypad is used
#define row1tris TRISDbits.TRISD0
#define row2tris TRISDbits.TRISD1
#define row3tris TRISDbits.TRISD2
#define row4tris TRISDbits.TRISD3
#define col1tris TRISDbits.TRISD4
#define col2tris TRISDbits.TRISD5
#define col3tris TRISDbits.TRISD6
#define col4tris TRISDbits.TRISD7
That part used setbit row1port

Code:
#include<reg52.h> //including sfr registers for ports of the controller
#include<lcd.h>

//LCD Module Connections
sbit RS = P0^0;
sbit EN = P0^1;
sbit D0 = P2^0;
sbit D1 = P2^1;
sbit D2 = P2^2;
sbit D3 = P2^3;
sbit D4 = P2^4;
sbit D5 = P2^5;
sbit D6 = P2^6;
sbit D7 = P2^7;
//End LCD Module Connections

//Keypad Connections
sbit R1 = P1^0;
sbit R2 = P1^1;
sbit R3 = P1^2;
sbit R4 = P1^3;
sbit C1 = P1^4;
sbit C2 = P1^5;
sbit C3 = P1^6;
sbit C4 = P1^7;
//End Keypad Connections

void Delay(int a)
{
  int j;
  int i;
  for(i=0;i<a;i++)
  {
   for(j=0;j<100;j++)
   {
   }
  }
}

char Read_Keypad()
{
  C1=1;
  C2=1;
  C3=1;
  C4=1;
  R1=0;
  R2=1;
  R3=1;
  R4=1;
  if(C1==0){Delay(100);while(C1==0);return '7';}
  if(C2==0){Delay(100);while(C2==0);return '8';}
  if(C3==0){Delay(100);while(C3==0);return '9';}
  if(C4==0){Delay(100);while(C4==0);return '/';}
  R1=1;
  R2=0;
  R3=1;
  R4=1;
  if(C1==0){Delay(100);while(C1==0);return '4';}
  if(C2==0){Delay(100);while(C2==0);return '5';}
  if(C3==0){Delay(100);while(C3==0);return '6';}
  if(C4==0){Delay(100);while(C4==0);return 'X';}
  R1=1;
  R2=1;
  R3=0;
  R4=1;
  if(C1==0){Delay(100);while(C1==0);return '1';}
  if(C2==0){Delay(100);while(C2==0);return '2';}
  if(C3==0){Delay(100);while(C3==0);return '3';}
  if(C4==0){Delay(100);while(C4==0);return '-';}
  R1=1;
  R2=1;
  R3=1;
  R4=0;
  if(C1==0){Delay(100);while(C1==0);return 'C';}
  if(C2==0){Delay(100);while(C2==0);return '0';}
  if(C3==0){Delay(100);while(C3==0);return '=';}
  if(C4==0){Delay(100);while(C4==0);return '+';}
  return 0;
}

void main()
{
  int i=0;
  char c,p;
  Lcd8_Init();
  while(1)
  {
   Lcd8_Set_Cursor(1,1);
   Lcd8_Write_String("Keys Pressed:");
   Lcd8_Set_Cursor(2,1);
   Lcd8_Write_String("Times:");
   while(!(c = Read_Keypad()));
   p=c;
   while(p==c)
   {
     i++;
     Lcd8_Set_Cursor(1,14);
     Lcd8_Write_Char(c);
     Lcd8_Set_Cursor(2,7);
     Lcd8_Write_Char(i+48);
     Delay(100);
     while(!(c = Read_Keypad()));
   }
   i=0;
   Lcd8_Clear();
  }
}
 

Parth86

Member
I posted code that works you just change it for your chip ports
This work really good
There are many code available on internet and that work's but I am looking for efficient and good. previously I posted some code but Ian told me that this is not good way for keypad programming. so I was following his tutorial but couldn't get success.
Which version of proteus are you using.. digest...
I have proteus 8.1 I amworking on AT89c51 and keil.
 

Pommie

Well-Known Member
Most Helpful Member
I'm pretty sure the code I posted in post #2 will work with a little tweaking. All 5 lines of it.

Mike.
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
I posted some code but Ian told me that this is not good way for keypad programming. so I was following his tutorial but couldn't get success.
That was only about the delays.... I only criticised your naming of identifiers..
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Here's my rendition!!!
C:
/* Main.c file generated by Ian Rogers
 *
 * Created:   Wed Jan 24 2018
 * Processor: AT89C51
 * Compiler:  SDCC for 8051
 */
#include <mcs51reg.h>
#include <stdio.h>
#define LCDport P1   /* Data pins connected to port P1 */
#define RS  P3_5   /* RS pin connected to pin 5 of port P3 */
#define RW  P3_6  /* RW pin connected to pin 6 of port P3 */
#define EN  P3_7   /* EN pin connected to pin 7 of port P3 */
#define KEYport P0 /* Key pad connected to port P0*/
#define C1  P0_0  /* Col 0 pin connected to pin 0 of port P0*/
#define C2  P0_1  /* Col 1 pin connected to pin 1 of port P0 */
#define C3  P0_2  /* Col 2 pin connected to pin 2 of port P0 */
#define C4  P0_3  /* Col 3 pin connected to pin 3 of port P0 */
/* functions for delay */
 void delayUs(unsigned int wait)
   {
     wait >>= 3; 
      while(wait--); 
   }
   
 void delayMs(unsigned int wait)
   {
      while(wait--)
  delayUs(1000);
   }
/* Function to send command to LCD */
void LCD_Command(unsigned char cmd)
   {
    LCDport = cmd;
    RS = 0;
    RW = 0;
    EN = 1;
    delayMs(5);
    EN = 0;
   }
   
/*Function to send data to LCD */
void LCD_Data(unsigned char data)
   {
    LCDport = data;
    RS = 1;
    RW = 0;
    EN = 1;
    delayMs(5);
    EN = 0;
   }
/* Function to prepare the LCD */
void LCD_init(void)
   {
    delayMs(20); 
    LCD_Command(0x33);  // Init 8 it
    delayMs(15);
    LCD_Command(0x38);  // Function set
    delayMs(15);
    LCD_Command(0x0C);  // display on
    delayMs(10);
    LCD_Command(0x06);  // direction
    delayMs(5);
    LCD_Command(0x01);  // home...
    delayMs(5);
   }
   
  /* Function to position cursor on the LCD */
void LCD_goto(int x, int y)
   {
      unsigned char addr = 0x80;      // default line
       if (y ==2 ) addr = 0xC0;  // 2nd line
      if (y ==3 ) addr = 0x90;     // 3rd line
      if (y ==4 ) addr = 0xD0;  // 4th line
      addr+=x;     // Column required
      LCD_Command(addr);
    }
    
  /* Function to print on the LCD */   
 void LCD_print(int x, int y, char* str)
      {
  LCD_goto(x,y);
  while(*str!=0)      // this is a ponter  This means... 
     LCD_Data(*str++); // While the character pointed to isn't 0 print to LCD then increment..
      }
    
  /* Function to pset up Uart */      
void UART_Init()
   {
    TMOD = 0x20; /* Timer 1, 8-bit auto reload mode */
    TH1 = 0xFD; /* Load value for 9600 baud rate */
    SCON = 0x50; /* Mode 1, reception enable */
    TR1 = 1;  /* Start timer 1 */
   }
    
  /* Function to send a character */   
void  putchar(char tx_data)
   {
    SBUF = tx_data;  /* Load char in SBUF register */
    while (TI == 0); /* Wait until stop bit transmit */
    TI = 0;    /* Clear TI flag */
   } 
   /* Function to fetch a character */   
char getchar(void)
   {
    while(!RI);        // Wait here until SBUF clear
    RI = 0;
    return SBUF;      
    }
   
  /* Function to send a line of characters untill a null*/   
   
char keypad(void)
    {
    unsigned char keymask = 0xEF;
    char key = 0, row;
     char act_key[]  = {0,1,4,7,11,2,5,8,10,3,6,9,12} ;
    for(row=0;row < 4; row++)     
        {
          KEYport = keymask; 
          if(!C1) key = 1; 
          if(!C2) key = 2;
          if(!C3) key = 3; 
          if(!C4) key = 4;
                   if(key)
            {   
              key += (row*4); 
              return act_key[key];
            }
                keymask <<= 1; 
         keymask ++;     
       }         
    return key;
    }
    
void main(void)
   {
    char  key;  // receive variable
      char buff[20];
    int pos = 0;  // where we are on screen
    UART_Init();        /* UART initialize function */
    LCD_init();  // set up LCD
    puts("Press some keys\n\r");        /* Transmit 'test' */
    while(1)
      {
  key = keypad();
  if (key)
     {
      sprintf(buff,"Key Pressed %d ", key) ;
     LCD_print(0,0,buff);
     }
 }
   }
 

be80be

Well-Known Member
Like this should work
Code:
#include <mcs51reg.h>
#include <stdio.h>
sbit row1port = P1^0;
sbit row2port = P1^1;
sbit row3port = P1^2;
sbi trow4port = P1^3;
sbit col1port = P1^4;
sbit col2port = P1^5;
sbit col3port = P1^6
sbit col4port = P1^7;   // a 4x4 keypad is used
char const keyPadMatrix[] =
{
    '1','2','3','4',
    '5','6','7','8',
    '9','0','A','B',
    'C','D','E','F',
    0xFF
};
void ScanKeyMatrixInit()
{
    // we scan the keypad by turning on the row outputs and
    // reading the columns
   row1port = 0;
   row2port = 0;
   row3port = 0;
   row4port = 0;
   col1port = 1;
   col2port = 1;
   col3port = 1;
   col4port = 1;
}
char ScanKeyMatrix()
{
    // This routine returns the first key found to be
    // pressed during the scan.
    char key = 0, row;
  
    for( row = 0b00000001; row < 0b00010000; row <<= 1 )
    {      
        {   // turn on row output
            row1port = (row & 0x0001)>>0;
            row2port = (row & 0x0002)>>1;
            row3port = (row & 0x0004)>>2;
            row4port = (row & 0x0008)>>3;
            __delay_ms(1);
        }
      
        // read colums - break when key press detected
        if( col1port )
            break;
        key++;
        if( col2port )
            break;
        key++;
        if( col3port )
            break;
        key++;
        if( col4port )
            break;
        key++;
    }
    row1port = 0;
    row2port = 0;
    row3port = 0;
    row4port = 0;
      
    return keyPadMatrix[ key ];
}
 
Last edited:
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top