Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] Matrix Keypad & 16*2 LCD interfacing with PIC

Status
Not open for further replies.

noobeestudent

Member level 1
Member level 1
Joined
Jul 4, 2019
Messages
37
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
290
Hi, guys. I am working on my final year project. I've been trying to interface the Matrix Keypad & 16*2 LCD along the with PIC. However, I wasn't able to get it to work. The LCD is able to display the 'Enter Duration' text but does not display the content of the 'Duration' array. The microcontroller I used is PIC16F887. My current code is listed below. Please help me check my code.

Code:
#pragma config CONFIG1 = 0x2CD4
#pragma config CONFIG2 = 0x0700
 
#include <stdio.h>
#include <stdlib.h>
 
//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   

#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
    Keypad_PORT_Direction = 0xF0;    // Last 4 pins input, First 4 pins output
    
    OPTION_REG &= 0x7F;
}

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

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

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

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

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

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

    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[10];
    char Key = 'n';
    InitKeypad();
    LCD_Goto(1, 1);
    LCD_Print("Enter Duration"); 
    LCD_Goto(1, 2);
    while(t<9){
        Key = switch_press_scan();
        Duration[t]=Key;
        LCD_Goto(t+1, 2);
        LCD_Print(Duration);
        t++;
    }
}

The library i used for in this code is provided below:
Code:
#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);
}
 

Your keypad scanning routine is very complicated, you can greatly simplify it. Also your code
Code:
  LCD_D4 = n & 0x01;
  LCD_D5 = (n >> 1) & 0x01;
  LCD_D6 = (n >> 2) & 0x01;
  LCD_D7 = (n >> 3) & 0x01;
seems to do the same as ANDing it with 0x0F.

I can't see any obvious reason why it shouldn't work to some extent though. Do you have pull-up resistors on the keypad input lines?

Brian.
 
Your keypad scanning routine is very complicated, you can greatly simplify it. Also your code
Code:
  LCD_D4 = n & 0x01;
  LCD_D5 = (n >> 1) & 0x01;
  LCD_D6 = (n >> 2) & 0x01;
  LCD_D7 = (n >> 3) & 0x01;
seems to do the same as ANDing it with 0x0F.

I can't see any obvious reason why it shouldn't work to some extent though. Do you have pull-up resistors on the keypad input lines?

Brian.

Where should I add the Pull-up resistors
I've not used any pull-up resistors. I thought about using internal weak pull-ups but have not implemented it in the code.
Edit: I've since added 3 lines of codes to do so in the keypad initialization function.
Code:
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)
    WPUB   = 0b11110000;   
}
After adding these codes, pressing some of the buttons have no effects but some buttons prints gibberish.

96357674_287040858978877_1554119970298789888_n (2).jpg
 
Last edited:

The character code you print on the LCD is looked up from an array called 'Duration[]' which I can't see in your code. Is it possible you are using the ASCII character from the keypad routine to index into it instead of the actual keypad number? For example, if you press key 'D' the character you send to the LCD is from Duration[68] which is well outside your array.

Brian.
 

Sorry, I dont quite understand what you meant.
The Duration Array was defined in the main function.
 

I dont think that is what happened. The Key is a char. I dont think that it sent the ASCII value of the character.
The Duration array was declared as a char array in the main function.
 

Maybe I'm misunderstanding what you are trying to do but this doesn't seem sensible to me:
Code:
    while(t<9){
        Key = switch_press_scan();
        Duration[t]=Key;
        LCD_Goto(t+1, 2);
        LCD_Print(Duration);
        t++;
Shouldn't the line be "LCD_Print(Duration[t]);"

Brian.
 

My bad, the code I used was actually "LCD_Print(Duration[t])";
 

Not your problem but with these old devices that don't have LAT registers, be very careful of code sequences such as
Code:
RB0 = 1; RB1 = 1; RB2 = 0; RB3 = 1;
(or whatever - I've made this up) as this can bring up the Read-Modify-Write (RMW) problem. You are far better to write all of those bits at the same time such as:
Code:
RB = (RB & 0xF0) | 0xB;
(Either that or use a more modern MCU that has LAT registers! I guess this is a school assignment and you have to use whatever MCU you are given.)
Susan
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top