• AVR Freaks

Hot!Interfacing 4x4 Keypad

Author
delfindelfin
Super Member
  • Total Posts : 300
  • Reward points : 0
  • Joined: 2017/01/19 12:32:58
  • Location: Mexico
  • Status: offline
2019/04/18 20:35:21 (permalink)
0

Interfacing 4x4 Keypad

Hello, I am writing a code to interface a 4x4 Keypad
 
Keypad Library:
 
//////////////////////////////////////////////////////////////////////////////////
// 4x4 Matric Keypad
//
// Three modes
// - Normal Mode
// There are no pull-up or pull-down resistors
// - Pull-up mode
// The default state i high
// - Pull-down mode
// The default state is low
//
// Debouncing
// Spurious spikes generated during keypress events, can be filtered by hardware
// or software
// - Hardware
// Low pass filters in each line
// - Software
// Time Window between detection and scanning
//
//////////////////////////////////////////////////////////////////////////////////

#define _XTAL_FREQ 8000000

#include <xc.h>

#include "keypad.h"

// DEFINING KEYPAD PINS
#define KP_R1 PORTBbits.RB0 // RB0 will drive High Row A
#define KP_R2 PORTBbits.RB1 // RB1 will drive High Row B
#define KP_R3 PORTBbits.RB2 // RB2 will drive High Row C
#define KP_R4 PORTBbits.RB3 // RB3 will drive High Row D
#define KP_C1 PORTBbits.RB4 // RB4 will recieved Column 1
#define KP_C2 PORTBbits.RB5 // RB5 will recieved Column 2
#define KP_C3 PORTBbits.RB6 // RB6 will recieved Column 3
#define KP_C4 PORTBbits.RB7 // RB7 will recieved Column 4

char const *keyPadMatrix[] =
{
    '1','2','3','A',
    '4','5','6','B',
    '7','8','9','C',
    '*','0','#','D',
    0xFF
};

void kbd_init(){
    
    TRISB = 0xF0; // Setting Input/Output - RB7-1 RB6-1 RB5-1 RB4-1 RB3-0 RB2-0 RB1-0 RB0-0 ( 1=Input, 0=Output)
    PORTB = 0x00; // Setting RB3,RB2,RB1,RB0 as low
        
    OPTION_REGbits.nRBPU = 1; // Disablaling Pull-Ups Resistors
}

char *kbd_getc(){
    
    char row;
    char key, old_key = 0;
            
    
    for( row = 0b00000001; row < 0b00010000; row <<= 1 )
    {
        // Turning on row outputs
        {
            KP_R1 = (row & 0x0001)>>0;
            KP_R2 = (row & 0x0002)>>1;
            KP_R3 = (row & 0x0004)>>2;
            KP_R4 = (row & 0x0008)>>3;
            __delay_ms(1); // Time Window for debouncing
            
        }
        
        // Reading columns - Break when key press detected /////////////////////
        if( KP_C1 == 1 ){
            break;
        }
        key++;
        if( KP_C2 == 1 ){
            break;
        }
        key++;
        if( KP_C3 == 1 ){
            break;
        }
        key++;
        if( KP_C4 == 1 ){
            break;
        }
        key++;
     }
     
    KP_R1 = 0;
    KP_R2 = 0;
    KP_R3 = 0;
    KP_R4 = 0;
    
    if (key!=old_key){ // Detecting the key only once when it is pressed
      old_key=key;
      
    }
    else{
      return keyPadMatrix[0x10]; // Return of 0xFF
    }
     
}

 
Keypad Header:

#ifndef KEYPAD_H
#define KEYPAD_H

#include <xc.h> // include processor files - each processor file is guarded.

void kbd_init();
char *kbd_getc();

#endif


 
Main Function must be downloaded (Flipping Firewall)
 
 
I would appreciate suggestions of how to improve the code, particulary in the part of debouncing and the correct way to use pointers in the arrays. I don't understand completly those parts
 
Thanks
post edited by delfindelfin - 2019/04/18 20:40:36

MPLAB X IDE v5.05
XC8 2.00
#1

9 Replies Related Threads

    delfindelfin
    Super Member
    • Total Posts : 300
    • Reward points : 0
    • Joined: 2017/01/19 12:32:58
    • Location: Mexico
    • Status: offline
    Re: Interfacing 4x4 Keypad 2019/04/18 20:47:12 (permalink)
    0
    I have a problem in my code, it only recognizes the Row 1 and it is behaving as the Row 4. I have already checked and rechecked and I don't find the error 
    post edited by delfindelfin - 2019/04/18 20:51:34

    MPLAB X IDE v5.05
    XC8 2.00
    #2
    PStechPaul
    Super Member
    • Total Posts : 2294
    • Reward points : 0
    • Joined: 2006/06/27 16:11:32
    • Location: Cockeysville, MD, USA
    • Status: online
    Re: Interfacing 4x4 Keypad 2019/04/18 22:10:35 (permalink)
    0
    I can't really figure out what you are trying to do with that code. Here is code I have used for a 2x4 matrix:

    #define    K_INIT_UP       16+0
    #define    K_INIT          16+1
    #define    K_STOP          16+2
    #define    K_MO_MA         16+8
    #define    K_MODE          16+4
    #define    K_SECCYC        4
    #define    K_RNG_UP        8
    #define    K_RNG_DN        1
    #define    K_RESET         2
    #define    K_REM           32+1
    #define    K_REM_UP        32+0
    #define    K_DEMO          K_SECCYC | K_RESET
     
    #define K_COL_0             PORTBbits.PORTB4
    #define K_COL_1             PORTBbits.PORTB5
    #define K_COL_2             PORTBbits.PORTB6
    #define K_COL_3             PORTBbits.PORTB7
    #define K_COLS              (PORTB & 0b11110000) >> 4
    #define K_ROW_0             LATCbits.LATC0
    #define K_ROW_1             LATCbits.LATC1


    int                         NewKey=FALSE;
    int                         col;
    unsigned char               keys[4], oldkeys[4];
    int                         keynum;


    /** Scan Keys *******************************************************/

    void    ScanKeys(void)
        {
        if( col < 1 )
            col++;
        else
            col=0;
        switch(col) {
            case 0:     K_ROW_0 = 0;
                        K_ROW_1 = 1;
                        break;
            case 1:     K_ROW_0 = 1;
                        K_ROW_1 = 0;
                        break;
        }
        oldkeys[col] = keys[col];       // 0b00001111 key pressed bit=0
        keys[col] = PORTB & 0xf0;
        keys[col]>>=4;// move to LSB
        if( !NewKey ) {
            if( oldkeys[col] != keys[col] ) {
                keynum = (int)(~keys[col] & 0x0f) + 16*(int)col;    // 1, 2, 4, 8
                NewKey = TRUE;
                }
            }
        }
     
        if( NewKey ) {

            switch(keynum) {
                case    K_INIT:     fReset();
                                    fInit();
                                    break;
                case    K_RESET:    fReset();
                                    ShowAll();
                                    break;
                }
            keynum = 0;
            NewKey = FALSE;
            Delay_mSec(10);
            }


     
    #3
    qhb
    Superb Member
    • Total Posts : 9998
    • Reward points : 0
    • Joined: 2016/06/05 14:55:32
    • Location: One step ahead...
    • Status: offline
    Re: Interfacing 4x4 Keypad 2019/04/18 23:45:25 (permalink)
    +2 (2)
    I see a number of problems in your "KeyPad Library" code.
     
    char const *keyPadMatrix[] =

    should be
    char const keyPadMatrix[] =

     
    char *kbd_getc(){

    should be
    char kbd_getc(){

     
    This block of code is missing a line
        if (key!=old_key){ // Detecting the key only once when it is pressed
          old_key=key;     
        }
        else{
          return keyPadMatrix[0x10]; // Return of 0xFF
        }

    should be
        if (key!=old_key){ // Detecting the key only once when it is pressed
          old_key=key;     
          return keyPadMatrix[key]; // Return value from array
        }
        else{
          return keyPadMatrix[0x10]; // Return of 0xFF
        }

    (and notice the "else" is not really needed at all, due to the added return.)
     
    Also, this bit of code is very awkward, all those shoifts are very inefficient.
                KP_R1 = (row & 0x0001)>>0;
                KP_R2 = (row & 0x0002)>>1;
                KP_R3 = (row & 0x0004)>>2;
                KP_R4 = (row & 0x0008)>>3;

    you would get more efficient code from just
          if (row == 1)
              KP_R1 = 1
         if (row == 2)
              KP_R2 = 1
         if (row == 4)
              KP_R3 = 1
         if (row == 8)
              KP_R24 = 1

    Or better yet, just let row count from 0 to 3, and code it as:
          switch (row)
          {
              case 0:
                  KP_R1 = 1;
                  break;
              case 1:
                  KP_R2 = 1;
                  break;
              case 2:
                  KP_R2 = 1;
                  break;
              default:
                  KP_R3 = 1;
          }

     

    Nearly there...
    #4
    pcbbc
    Super Member
    • Total Posts : 1098
    • Reward points : 0
    • Joined: 2014/03/27 07:04:41
    • Location: 0
    • Status: offline
    Re: Interfacing 4x4 Keypad 2019/04/19 00:00:11 (permalink)
    +2 (2)
    char *kbd_getc()

    You do not need the *. Just return the char of the key pressed, not a pointer to it.

    char key, old_key = 0;

    I don’t think you’ve initialised key there? What value should it start with?
    Since you’ve set old_key = 0, how are you expecting to “remember” what the previously pressed key was next time in the function when you get here:
    if (key!=old_key){ // Detecting the key only once when it is pressed
    old_key=key;

    You need to declare old_key as a global.

    __delay_ms(1); // Time Window for debouncing

    This is a funny place to debounce, because you do it on every row, and the number of times you do it depends on which row you find a pressed key in.
    A crude but effective denounce can be done if you only check the keyboard every 20ms or so. For that the delay can go outside the loop so you only do it once per test of whole matrix.

    char const *keyPadMatrix[] =
    {
    '1','2','3','A',
    '4','5','6','B',
    '7','8','9','C',
    '*','0','#','D',
    0xFF
    };

    Try storing in a string with
    const char keyPadMatrix[] = “123A456B789C*0#D\xFF”;

    There is no need for the pointers here.

    Then you can translate from key index to key character after your loop exits with:
    key = keyPadMatrix[key];

    Although note that using key for both values is not great coding. key_index and pressed_chr would be better variable names.

    This code:
        if (key!=old_key){ // Detecting the key only once when it is pressed
    old_key=key;

    You are never returning anything here. All function, except those declared void, should end with a return on all code paths.
    Here you need to be returning key (or pressed_chr) if you detect a new key is pressed.
        }
    else{
    return keyPadMatrix[0x10]; // Return of 0xFF

    That can be replaced with simply return 0xFF as you have got rid of the pointers, and you know what the 16th entry in the array is.

    This is not an exhaustive list of all the errors, but might get you started in the right direction.
    #5
    qhb
    Superb Member
    • Total Posts : 9998
    • Reward points : 0
    • Joined: 2016/06/05 14:55:32
    • Location: One step ahead...
    • Status: offline
    Re: Interfacing 4x4 Keypad 2019/04/19 00:06:40 (permalink)
    0
    Looks like we provided pretty similar advice ;)
     

    Nearly there...
    #6
    pcbbc
    Super Member
    • Total Posts : 1098
    • Reward points : 0
    • Joined: 2014/03/27 07:04:41
    • Location: 0
    • Status: offline
    Re: Interfacing 4x4 Keypad 2019/04/19 00:21:24 (permalink)
    +2 (2)
    And then in main just...
            keypress = kbd_getc();
    if(keypress!=0xFF){
    Lcd_Write_Chàr(keypress);
    }

    You do not need variable keyboard at all.
    Also you might be better with 0x00 as your default ‘nothing pressed’ key character instead of 0xFF. It’s a bit more logical as 0x00 is the string terminator.

    Note that variables that are assigned results from functions directly (keypress for example) should be of the same type as the function where they are defined.
    Your initial (wrong) definition for the function was:
    char *kbd_getc()
    Which defines the function as returning a pointer, not the character itself.
    So your definition of keypress (if you did want a pointer returned) should then have been:
    char* keypress;
    Or, if you wanted the key from the pointer, you should have coded:
    keypress = *kbd_getc();
    To dereference the pointer.

    But hopefully you have now corrected the function definition (to char kbd_getc()), so you do not need to change any of these issues now!

    Also the problem with the firewall (or one of them at least is it doesn’t like this character sequence (accent added to get around it):
    Chàr(
    So you’d do well not to name your functions with char at the end if you want to post them here. Try chr instead. ;)
    #7
    pcbbc
    Super Member
    • Total Posts : 1098
    • Reward points : 0
    • Joined: 2014/03/27 07:04:41
    • Location: 0
    • Status: offline
    Re: Interfacing 4x4 Keypad 2019/04/19 00:25:48 (permalink)
    0
    qhb
    Looks like we provided pretty similar advice ;) 
    Indeed.
    Also, no offence to PStechPaul, and I’m sure his code works, if found delfindelfin’s code very easy to read.
    A fairly good first attempt. Well done.
    #8
    PStechPaul
    Super Member
    • Total Posts : 2294
    • Reward points : 0
    • Joined: 2006/06/27 16:11:32
    • Location: Cockeysville, MD, USA
    • Status: online
    Re: Interfacing 4x4 Keypad 2019/04/19 12:04:55 (permalink)
    0
    I understand it better now, especially after the corrections and suggestions offered. I just couldn't see what the shifts were doing, and qhb's code makes a lot more sense (although it has a couple typo errors).

     
    #9
    qhb
    Superb Member
    • Total Posts : 9998
    • Reward points : 0
    • Joined: 2016/06/05 14:55:32
    • Location: One step ahead...
    • Status: offline
    Re: Interfacing 4x4 Keypad 2019/04/19 14:14:31 (permalink)
    0
    what's a missing semi-colon between friends? ;)
     

    Nearly there...
    #10
    Jump to:
    © 2019 APG vNext Commercial Version 4.5