Matrix Keypad & 16*2 LCD interfacing with PIC

MrChips

Joined Oct 2, 2009
24,175
Let's try one thing at a time.

Code:
void main(void)
{
   LCD_Begin();
   uint8_t t = 0;
   char Duration[]="123456789";
   char Key = 'n';
   InitKeypad();
   LCD_Goto(1, 1);
   LCD_Print("Enter Duration");
   LCD_Goto(1, 2);
   LCD_Print(Duration);
}
 

Thread Starter

swsean

Joined Jul 8, 2019
22
Let's try one thing at a time.

Code:
void main(void)
{
   LCD_Begin();
   uint8_t t = 0;
   char Duration[]="123456789";
   char Key = 'n';
   InitKeypad();
   LCD_Goto(1, 1);
   LCD_Print("Enter Duration");
   LCD_Goto(1, 2);
   LCD_Print(Duration);
}
Works fine
96099764_612960949321943_6416698375927758848_n.jpg
 

MrChips

Joined Oct 2, 2009
24,175
Ok. Try this:
Code:
void main(void)
{
    LCD_Begin();
    char Key;
    char EndKey = 'n';
    InitKeypad();
    LCD_Goto(1, 1);
    LCD_Print("Enter Duration"); 
    LCD_Goto(1, 2);
    do
    {
        Key = switch_press_scan();
        if (Key != EndKey) LCD_PutC(Key);
      } while(Key != EndKey );
}
 

Thread Starter

swsean

Joined Jul 8, 2019
22
Ok. Try this:
Code:
void main(void)
{
    LCD_Begin();
    char Key;
    char EndKey = 'n';
    InitKeypad();
    LCD_Goto(1, 1);
    LCD_Print("Enter Duration");
    LCD_Goto(1, 2);
    do
    {
        Key = switch_press_scan();
        if (Key != EndKey) LCD_PutC(Key);
      } while(Key != EndKey );
}
96076198_263294941461472_4556141671699447808_n.jpgSome buttons prints some numbers and letters but not the one asssigned to it
 

MrChips

Joined Oct 2, 2009
24,175
Make a list of all 16 buttons and what appears on the screen when each button is pressed.
You probable have something wrong in your keypad_scanner(void) code.
 

MrChips

Joined Oct 2, 2009
24,175
Instead of fixing your keypad_scanner(void) code I would suggest that you rewrite it completely.
Start with drawing a flowchart or pseudocode.
 

Thread Starter

swsean

Joined Jul 8, 2019
22
Make a list of all 16 buttons and what appears on the screen when each button is pressed.
You probable have something wrong in your keypad_scanner(void) code.
Its quite hard to make a list as the button may be able to print a digit but after pressing it a few times it stops working
S1(-)S2(3)S3(-)S4(-)
S5(-)S6(3/A)S7(A)S8(3)
S9(-)S10(-)S11(3/A)S12(3)
S13(-)S14(-)S15(3/A)S16(3)
As for other digits or alphabets its mostly when i pressed 2 or more buttons
 

MrChips

Joined Oct 2, 2009
24,175
Here is new pseudo code.

Notes: X1-X4 are output, Y1-Y4 are inputs.
It is easier to do this if X and Y were single 4-bit or 8-bit values instead of single bits.

1) begin with all X1-X4 = 0
2) read back all Y1-Y4, easier to do this is Y is single 4-bit or 8-bit value
3) if all Y1-Y4 are 1, go back to 1)

4) Set all X1-X4 = 1
5) select one X-output at a time = 0
6) read back Y1-Y4 one at a time, easier to do this if Y is 4-bit register.
7) if no 0 found, go back to 1)
8) if 0 is found, record this key

9) delay

10) repeat from 4) to 8)
11) if not same key go back to 1)
12) else key found, exit.

Try to write the code as nested loops. For example, there should be only one occurrence of step 9) in the entire code.
 

MrChips

Joined Oct 2, 2009
24,175
You can try changing your keypad_scanner(void) code.

Code:
char keypad_scanner(void)   
{   
    X_1 = 0; X_2 = 1; X_3 = 1; X_4 = 1;     

    if (Y_1 == 0) { __delay_ms(100); if (Y_1==0) return '1'; }
    if (Y_2 == 0) { __delay_ms(100); if (Y_2==0) return '2'; }
    if (Y_3 == 0) { __delay_ms(100); if (Y_3==0) return '3'; }
    if (Y_4 == 0) { __delay_ms(100); if (Y_4==0) return 'A'; }

    X_1 = 1; X_2 = 0; X_3 = 1; X_4 = 1;     

    if (Y_1 == 0) { __delay_ms(100); if (Y_1==0) return '4'; }
    if (Y_2 == 0) { __delay_ms(100); if (Y_2==0) return '5'; }
    if (Y_3 == 0) { __delay_ms(100); if (Y_3==0) return '6'; }
    if (Y_4 == 0) { __delay_ms(100); if (Y_4==0) return 'B'; }
    
    X_1 = 1; X_2 = 1; X_3 = 0; X_4 = 1;     

    if (Y_1 == 0) { __delay_ms(100); if (Y_1==0) return '7'; }
    if (Y_2 == 0) { __delay_ms(100); if (Y_2==0) return '8'; }
    if (Y_3 == 0) { __delay_ms(100); if (Y_3==0) return '9'; }
    if (Y_4 == 0) { __delay_ms(100); if (Y_4==0) return 'C'; }
    
    X_1 = 1; X_2 = 1; X_3 = 1; X_4 = 0;     

    if (Y_1 == 0) { __delay_ms(100); if (Y_1==0) return '*'; }
    if (Y_2 == 0) { __delay_ms(100); if (Y_2==0) return '0'; }
    if (Y_3 == 0) { __delay_ms(100); if (Y_3==0) return '#'; }
    if (Y_4 == 0) { __delay_ms(100); if (Y_4==0) return 'D'; }

    return 'n';   
}

void main(void)
{
   LCD_Begin();
   char Key;
   char EndKey = '#';
   InitKeypad();
   while (1)
   {
      LCD_Cmd(LCD_CLEAR);
      LCD_Goto(1, 1);
      LCD_Print("Enter Duration");
      LCD_Goto(1, 2);
      do
      {
         Key = switch_press_scan();
         if (Key != EndKey) LCD_PutC(Key);
      }   while(Key != EndKey );
   } // end of while
} // end of main
 

Thread Starter

swsean

Joined Jul 8, 2019
22
Hi guys,
Finally found out what was causing the error.
Turns out the error occurs because the PGD and the PGC of the PICKIT was sending the signal to the RB6 and RB7.
After removing the PGD and PGC connection, the Keypad was able to function without any errors.

95712940_3077777582244305_734063099761393664_n.jpg
This is the code I used.
Code:
#pragma config CONFIG1 = 0x2CD4
#pragma config CONFIG2 = 0x0700
 
#include <stdio.h>
#include <stdlib.h>

// button definitions
#define button1      RD6   // button B1 is connected to RB0 pin
#define button2      RD7   // button B2 is connected to RB1 pin
 
//LCD module connections
#define LCD_RS       RD0
#define LCD_EN       RD1
#define LCD_D4       RD2
#define LCD_D5       RD3
#define LCD_D6       RD4
#define LCD_D7       RD5
#define LCD_RS_DIR   TRISD0
#define LCD_EN_DIR   TRISD1
#define LCD_D4_DIR   TRISD2
#define LCD_D5_DIR   TRISD3
#define LCD_D6_DIR   TRISD4
#define LCD_D7_DIR   TRISD5
//End LCD module connections
 
//matrix keypad connections
#define X_1    RB0
#define X_2    RB1
#define X_3    RB2
#define X_4    RB3
#define Y_1    RB4
#define Y_2    RB5
#define Y_3    RB6
#define Y_4    RB7
#define Keypad_PORT          PORTB
#define Keypad_PORT_Direction     TRISB   

void InitKeypad(void);
char switch_press_scan(void);

 
#include <xc.h>
#define _XTAL_FREQ 8000000
#include <stdint.h>        // include stdint header
#include "LCD_Lib.c"       // include LCD driver source file

// Function declarations
void InitKeypad(void);
char switch_press_scan(void);

void InitKeypad(void)
{
    Keypad_PORT        = 0x00;    // Set Keypad port pin values zero
    ANSELH = 0;
    Keypad_PORT_Direction = 0xF0;    // Last 4 pins input, First 4 pins output
    nRBPU  = 0;                     // clear RBPU bit (OPTION_REG.7)
    OPTION_REG &= 0X7F;
    WPUB   = 0xF0;            // WPUB register = 0b11110000
}


char keypad_scanner(void)
{
    PORTB = 0X0e;  // PORTBbits -> 0000001, D0 is high
    if      ((Y_1 == 0)&&(X_1 == 0))  {return '1';}                     // S1  is pressed   
    else if ((Y_2 == 0)&&(X_1 == 0))  {return '2';}                     // S2  is pressed     
    else if ((Y_3 == 0)&&(X_1 == 0))  {return '3';}                     // S3  is pressed           
    else if ((Y_4 == 0)&&(X_1 == 0))  {return 'A';}             // S4  is pressed
    

    PORTB = 0X0D;  // PORTBbits -> 00000010, D1 is high
    if      ((Y_1 == 0)&&(X_2 == 0))  {return '4';}                     // S5  is pressed   
    else if ((Y_2 == 0)&&(X_2 == 0))  {return '5';}             // S6  is pressed   
    else if ((Y_3 == 0)&&(X_2 == 0))  {return '6';}             // S7  is pressed   
    else if ((Y_4 == 0)&&(X_2 == 0))  {return 'B';}             // S8  is pressed
    
 
    PORTB = 0X0B;  // PORTBbits -> 00000100, D2 is high
    if      ((Y_1 == 0)&&(X_3 == 0))  {return '7';}             // S9  is pressed
    else if ((Y_2 == 0)&&(X_3 == 0))  {return '8';}             // S10 is pressed
    else if ((Y_3 == 0)&&(X_3 == 0))  {return '9';}             // S11 is pressed
    else if ((Y_4 == 0)&&(X_3 == 0))  {return 'C';}             // S12 is pressed

 
    PORTB = 0X07;  // PORTBbits -> 00001000, D3 is high
    if      ((Y_1 == 0)&&(X_4 == 0))  {return '*';}             // S13 is pressed
    else if ((Y_2 == 0)&&(X_4 == 0))  {return '0';}             // S14 is pressed
    else if ((Y_3 == 0)&&(X_4 == 0))  {return '#';}             // S15 is pressed
    else if ((Y_4 == 0)&&(X_4 == 0))  {return 'D';}             // S16 is pressed
 
    return 'n'; 
}

// Function name: GetKey
// Read pressed key value from keypad and return its value
char switch_press_scan(void)                // Get key from user
{
    char key = 'n';              // Assume no key pressed

    while(key=='n')              // Wait until a key is pressed
        key = keypad_scanner();   // Scan the keys again and again

    return key;                  //when key pressed then return its value
}

void main(void)
{
    LCD_Begin();
    uint8_t t = 0;
    static char Duration[17];
    char Key = 'n';
    InitKeypad();
    LCD_Goto(1, 1);
    LCD_Print("Enter Duration"); 
    while(t<=16){
        Key = switch_press_scan();
        Duration[t] = Key;
        LCD_Goto(1, 2);
        LCD_Print(Duration);
        __delay_ms(100);
        t++;
    };
}
Thanks for the help given. Will let you guys know if I faced any more problems regarding this topic.
 

Thread Starter

swsean

Joined Jul 8, 2019
22
Hi guys,
I've encountered a problem. After I entered the last number of the array, some random characters are printed on the screen.
For example, I've entered 09182, As soon as I entered the 2, these random character appeared.

Does anyone know why did this happened.
96100508_2628600190739061_1042905101276020736_n.jpg96512894_1113135695730403_5296578459978432512_n.jpg

This is the code so far:
C:
#pragma config CONFIG1 = 0x2CD4
#pragma config CONFIG2 = 0x0700

#include <stdio.h>
#include <stdlib.h>

// button definitions
#define button1      RD6   // button B1 is connected to RB0 pin
#define button2      RD7   // button B2 is connected to RB1 pin

//LCD module connections
#define LCD_RS       RD0
#define LCD_EN       RD1
#define LCD_D4       RD2
#define LCD_D5       RD3
#define LCD_D6       RD4
#define LCD_D7       RD5
#define LCD_RS_DIR   TRISD0
#define LCD_EN_DIR   TRISD1
#define LCD_D4_DIR   TRISD2
#define LCD_D5_DIR   TRISD3
#define LCD_D6_DIR   TRISD4
#define LCD_D7_DIR   TRISD5
//End LCD module connections

//matrix keypad connections
#define X_1    RB0
#define X_2    RB1
#define X_3    RB2
#define X_4    RB3
#define Y_1    RB4
#define Y_2    RB5
#define Y_3    RB6
#define Y_4    RB7
#define Keypad_PORT          PORTB
#define Keypad_PORT_Direction     TRISB  

void InitKeypad(void);
char switch_press_scan(void);


#include <xc.h>
#define _XTAL_FREQ 8000000
#include <stdint.h>        // include stdint header
#include "LCD_Lib.c"       // include LCD driver source file

// Function declarations
void InitKeypad(void);
char switch_press_scan(void);

void InitKeypad(void)
{
    Keypad_PORT        = 0x00;    // Set Keypad port pin values zero
    ANSELH = 0;
    Keypad_PORT_Direction = 0xF0;    // Last 4 pins input, First 4 pins output
    nRBPU  = 0;                     // clear RBPU bit (OPTION_REG.7)
    OPTION_REG &= 0X7F;
    WPUB   = 0xF0;            // WPUB register = 0b11110000
}


char keypad_scanner(void)
{
    PORTB = 0X0E;  // PORTBbits -> 0000001, D0 is high
    if      ((Y_1 == 0)&&(X_1 == 0))  {return '1';}                     // S1  is pressed  
    else if ((Y_2 == 0)&&(X_1 == 0))  {return '2';}                     // S2  is pressed    
    else if ((Y_3 == 0)&&(X_1 == 0))  {return '3';}                     // S3  is pressed          
    else if ((Y_4 == 0)&&(X_1 == 0))  {return 'A';}             // S4  is pressed
   

    PORTB = 0X0D;  // PORTBbits -> 00000010, D1 is high
    if      ((Y_1 == 0)&&(X_2 == 0))  {return '4';}                     // S5  is pressed  
    else if ((Y_2 == 0)&&(X_2 == 0))  {return '5';}             // S6  is pressed  
    else if ((Y_3 == 0)&&(X_2 == 0))  {return '6';}             // S7  is pressed  
    else if ((Y_4 == 0)&&(X_2 == 0))  {return 'B';}             // S8  is pressed
   

    PORTB = 0X0B;  // PORTBbits -> 00000100, D2 is high
    if      ((Y_1 == 0)&&(X_3 == 0))  {return '7';}             // S9  is pressed
    else if ((Y_2 == 0)&&(X_3 == 0))  {return '8';}             // S10 is pressed
    else if ((Y_3 == 0)&&(X_3 == 0))  {return '9';}             // S11 is pressed
    else if ((Y_4 == 0)&&(X_3 == 0))  {return 'C';}             // S12 is pressed


    PORTB = 0X07;  // PORTBbits -> 00001000, D3 is high
    if      ((Y_1 == 0)&&(X_4 == 0))  {return '*';}             // S13 is pressed
    else if ((Y_2 == 0)&&(X_4 == 0))  {return '0';}             // S14 is pressed
    else if ((Y_3 == 0)&&(X_4 == 0))  {return '#';}             // S15 is pressed
    else if ((Y_4 == 0)&&(X_4 == 0))  {return 'D';}             // S16 is pressed

    return 'n';
}

// Function name: GetKey
// Read pressed key value from keypad and return its value
char switch_press_scan(void)                // Get key from user
{
    char key = 'n';              // Assume no key pressed

    while(key=='n')              // Wait until a key is pressed
        key = keypad_scanner();   // Scan the keys again and again

    return key;                  //when key pressed then return its value
}

void main(void)
{
    LCD_Begin();
    uint8_t t = 0;
    static char Duration[5];
    char Key = 'n';
    InitKeypad();
    LCD_Goto(1, 1);
    LCD_Print("Enter Duration");
    while(t<=4){
        Key = switch_press_scan();
        Duration[t] = Key;
        LCD_Goto(1, 2);
        LCD_Print(Duration);
        __delay_ms(200);
        t++;
    };
    __delay_ms(1000);
    LCD_Cmd(LCD_CLEAR);
}

The LCD library remains the same


LCD Library:
#pragma warning disable 520

#include <stdint.h>

#define LCD_FIRST_ROW          0x80
#define LCD_SECOND_ROW         0xC0
#define LCD_THIRD_ROW          0x94
#define LCD_FOURTH_ROW         0xD4
#define LCD_CLEAR              0x01
#define LCD_RETURN_HOME        0x02
#define LCD_ENTRY_MODE_SET     0x04
#define LCD_CURSOR_OFF         0x0C
#define LCD_UNDERLINE_ON       0x0E
#define LCD_BLINK_CURSOR_ON    0x0F
#define LCD_MOVE_CURSOR_LEFT   0x10
#define LCD_MOVE_CURSOR_RIGHT  0x14
#define LCD_TURN_ON            0x0C
#define LCD_TURN_OFF           0x08
#define LCD_SHIFT_LEFT         0x18
#define LCD_SHIFT_RIGHT        0x1E

#ifndef LCD_TYPE
   #define LCD_TYPE 2           // 0=5x7, 1=5x10, 2=2 lines
#endif

__bit RS;

void LCD_Write_Nibble(uint8_t n);
void LCD_Cmd(uint8_t Command);
void LCD_Goto(uint8_t col, uint8_t row);
void LCD_PutC(char LCD_Char);
void LCD_Print(char* LCD_Str);
void LCD_Begin();

void LCD_Write_Nibble(uint8_t n)
{
  LCD_RS = RS;
  LCD_D4 = n & 0x01;
  LCD_D5 = (n >> 1) & 0x01;
  LCD_D6 = (n >> 2) & 0x01;
  LCD_D7 = (n >> 3) & 0x01;

  // send enable pulse
  LCD_EN = 0;
  __delay_us(1);
  LCD_EN = 1;
  __delay_us(1);
  LCD_EN = 0;
  __delay_us(100);
}

void LCD_Cmd(uint8_t Command)
{
  RS = 0;
  LCD_Write_Nibble(Command >> 4);
  LCD_Write_Nibble(Command);
  if((Command == LCD_CLEAR) || (Command == LCD_RETURN_HOME))
    __delay_ms(2);
}

void LCD_Goto(uint8_t col, uint8_t row)
{
  switch(row)
  {
    case 2:
      LCD_Cmd(LCD_SECOND_ROW + col - 1);
      break;
    case 3:
      LCD_Cmd(LCD_THIRD_ROW  + col - 1);
      break;
    case 4:
      LCD_Cmd(LCD_FOURTH_ROW + col - 1);
    break;
    default:      // case 1:
      LCD_Cmd(LCD_FIRST_ROW  + col - 1);
  }

}

void LCD_PutC(char LCD_Char)
{
  RS = 1;
  LCD_Write_Nibble(LCD_Char >> 4);
  LCD_Write_Nibble(LCD_Char );
}

void LCD_Print(char* LCD_Str)
{
  uint8_t i = 0;
  RS = 1;
  while(LCD_Str[i] != '\0')
  {
    LCD_Write_Nibble(LCD_Str[i] >> 4);
    LCD_Write_Nibble(LCD_Str[i++] );
  }
}

void LCD_Begin()
{
  RS = 0;

  LCD_RS     = 0;
  LCD_EN     = 0;
  LCD_D4     = 0;
  LCD_D5     = 0;
  LCD_D6     = 0;
  LCD_D7     = 0;
  LCD_RS_DIR = 0;
  LCD_EN_DIR = 0;
  LCD_D4_DIR = 0;
  LCD_D5_DIR = 0;
  LCD_D6_DIR = 0;
  LCD_D7_DIR = 0;

  __delay_ms(40);
  LCD_Cmd(3);
  __delay_ms(5);
  LCD_Cmd(3);
  __delay_ms(5);
  LCD_Cmd(3);
  __delay_ms(5);
  LCD_Cmd(LCD_RETURN_HOME);
  __delay_ms(5);
  LCD_Cmd(0x20 | (LCD_TYPE << 2));
  __delay_ms(50);
  LCD_Cmd(LCD_TURN_ON);
  __delay_ms(50);
  LCD_Cmd(LCD_CLEAR);
  __delay_ms(50);
  LCD_Cmd(LCD_ENTRY_MODE_SET | LCD_RETURN_HOME);
  __delay_ms(50);
}
 

Attachments

AlbertHall

Joined Jun 4, 2014
11,498
'Duration' is declared to have space for 5 characters. The compiler probably initialises these five to be all zeroes.
When you enter the final '2' all the available characters have been overwritten.
'LCD_Print' prints the characters up to the terminating '/0' used to mark the end of C strings. When that last character is written there is no terminating zero so it will continue through memory printing whatever it finds until it gets to a zero somewhere.
Make 'Duration' 6 characters and only enter 5 and all will be well.
 

MrChips

Joined Oct 2, 2009
24,175
You still need to learn how to terminate a string of characters. I pointed this out before in an earlier post.
You need to put binary zero into the last character position (the next position following your last key), not the character '0'.

Duration[last] = 0;

not
Duration[last] = '0';

C:
void main(void)
{
   LCD_Begin();
   uint8_t t = 0;
   static char Duration[16];
   char Key = 'n';
   InitKeypad();
   LCD_Goto(1, 1);
   LCD_Print("Enter Duration");
   while(t<=4)
      {
         Key = switch_press_scan();
         Duration[t++] = Key;
         Duration[t] = 0;
         LCD_Goto(1, 2);
         LCD_Print(Duration);
         __delay_ms(200);
      }
   __delay_ms(1000);
   LCD_Cmd(LCD_CLEAR);
}
 
Top