• AVR Freaks

Hot!Need help - a matrix keypad with interrupt

Author
abhi143
Junior Member
  • Total Posts : 102
  • Reward points : 0
  • Joined: 2018/05/20 09:06:52
  • Location: 0
  • Status: offline
2020/01/18 12:12:28 (permalink)
0

Need help - a matrix keypad with interrupt

Hello,
I am looking help to implement ISR to scan 4*4 matrix keypad.  I want to use interrupt on change of pic16f877a. I understand how that interrupt work. I also wrote a program where I was using one button and led. When I pressed LED was toggling 
 
Logically I am explaining what I need to do. I am having trouble  to scan matrix keypad with interrupt   

/*Scane Row1*/
R1 = 0; //Make R1 to low
R2=R3=R4=1; //Make All other Row to high
if(C1 == 0) //If button in columns 1 is pressed
return 1; //return '1'

if(C2 == 0) //If button in columns 2 is pressed
return 2; //return '2'

if(C3 == 0) //If button in columns 3 is pressed
return 3; //return '3'

if(C4 == 0)//If button in columns4 is pressed
return 4; //return '4'

/* scane Row2*/
R2 = 0; //Make ROW2 to low
R1=R3=R4=1; //Make All other Row to high

if(C1 == 0) //If button in columns 1 is pressed
return 5; //return '5'

if(C2 == 0)//If button in columns 2 is pressed
return 6; //return '6'

if(C3 == 0)//If button in columns 3 is pressed
return 7; //return '7'

if(C4 == 0)//If button in columns 4 is pressed
return 8; //return '8'

/*Scane Row3 */
R3 = 0; //Make ROW3 to low
R1=R2=R4=1;//Make All other Row to high
if(C1 == 0)//If button in columns 1 is pressed
return 9; //return '9'

if(C2 == 0) //If button in columns 2 is pressed
return 10; //return '10'

if(C3 == 0)//If button in columns 3 is pressed
return 11; //return '11'

if(C4 == 0) //If Switch in columns 4 is pressed
return 12; //return '12'

/*Scane Row4*/
R4 = 0; //Make ROW4 to low
R1=R2=R3=1;//Make All other Row to high

if(C1 == 0)//If button in columns 1 is pressed
return 13; //return '13'

if(C2 == 0)//If button in columns2 is pressed
return 14; //return '14'

if(C3 == 0)//If button in columns3 is pressed
return 15; //return '15'

if(C4 == 0)//If button in columns4 is pressed
return 16; //return '16'
  
 
Can anyone help me with the pesudo code to scan 4*4 matrix keypad ?
#1

12 Replies Related Threads

    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11577
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: Need help - a matrix keypad with interrupt 2020/01/18 12:53:04 (permalink)
    0
    Why do you want to use interrupts?  Interrupts are generally not appropriate for buttons.
    #2
    abhi143
    Junior Member
    • Total Posts : 102
    • Reward points : 0
    • Joined: 2018/05/20 09:06:52
    • Location: 0
    • Status: offline
    Re: Need help - a matrix keypad with interrupt 2020/01/18 13:11:22 (permalink)
    0
    jtemplesWhy do you want to use interrupts?  Interrupts are generally not appropriate for buttons.

    I have read it in many places they use interrupt to scan matrix So i was asking for it. Otherwise the code I posted is for without interrupt to scan keypad. 
    How do you scan matrix keypad ?
    #3
    nigelwright7557
    Super Member
    • Total Posts : 344
    • Reward points : 0
    • Joined: 2006/11/06 08:15:51
    • Location: 0
    • Status: offline
    Re: Need help - a matrix keypad with interrupt 2020/01/18 13:16:23 (permalink)
    0
    Its not just a matter of capturing key down.
    You have to deal with debounce too and multiple keys pressed at same time.
    I usually use a 1mS timed interrupt and time division multiplex the function in stages.
    Just draw out a flow chart starting at key down detect and debounce key going away.
    #4
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11577
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: Need help - a matrix keypad with interrupt 2020/01/18 14:29:54 (permalink)
    #5
    teenix
    Junior Member
    • Total Posts : 51
    • Reward points : 0
    • Joined: 2017/12/21 13:47:21
    • Location: Australia, Melbourne
    • Status: offline
    Re: Need help - a matrix keypad with interrupt 2020/01/18 19:12:21 (permalink)
    +3 (3)
    To read the keys in a 4x4 keypad, you generally bring each of the keypad columns low in a sequential manner. All 4 rows in this case would normally be pulled to a high state.
     
    When a column is pulled low, you then read the state of all 4 rows and see if any of them are low. If so, then you know the row and column for that key and can decide what to do from there.
     
    In this arrangement IOC is probably not the easiest choice because and you still need to have code operating that sequentially changes the low state of each column.
     
    Depending on the requirements of the project you can also do the key scan procedure as part of the main code loop, or have the scan done in an interrupt driven by a timer.
     
    If done this way, then when a column is taken low, it is not wise to immediately read the row pins in the following instructions. The IO pins take time to change due to the electrical loading on each pin. If you have time in the interrupt, you can wait (say) 5uS and then read the row state. Another way is to read the row state the next time the interrupt fires and there are other methods as well. This can also be accomplished without interrupts.
     
    Key contacts can bounce when the connection is made and when they are broken. To avoid the code detecting multiple key actions caused by this bouncing you need to set up a delay so that after the code detects a key change, the keyboard state is ignored for a period of time. This de-bounce time depends on the type of key being used and somewhere around the 20mS range is usually good enough if you don't have an oscilloscope to see the bouncing.
     
    Multiple keys can be pressed at the same time. A simple way around this is to sequentially test each row for a low state and take the first one seen as low to be the key pressed, and then ignore the others.
     
    You also have to know when no keys are pressed. If multiple keys are pressed, they can be released in any order. You may see that the initial key has released and then you see other rows that are still low and falsely act on those. You can really only do this by checking that after all 4 columns have been scanned all rows were in a high state.
     
    Now you have to reset the de-bounce time due to the key release and ignore the keyboard state until it expires.
     
    If you are inexperienced writing code for switches, perhaps write code for one switch only. Set one column low and test one row to see what state it is in. Get a LED to toggle state each time the key is pressed, or get it to come on when the key is down and go off when the key is up. Then expand the code to test all 4 rows. Maybe toggle a separate LED for each key. Then change the code to make sure the other keys are ignored when one key is down. Try a different low column, then you will see that the active keys have shifted on the keyboard. Once you get this working then you have a good understanding of how to interface switches and then you can write code to activate the whole keyboard.
     
    cheers
     
    Tony
    #6
    abhi143
    Junior Member
    • Total Posts : 102
    • Reward points : 0
    • Joined: 2018/05/20 09:06:52
    • Location: 0
    • Status: offline
    Re: Need help - a matrix keypad with interrupt 2020/01/18 19:59:59 (permalink)
    0
     
    How to improve following function to deal with debounce  and multiple keys pressed at same time.

    Should i make new routine for debounce ( timer interrupt )

    unsigned char Keypad_Scan()
    {
    /*Scane Row1*/
    R1 = 0; //Make R1 to low
    R2=R3=R4=1; //Make All other Row to high
    if(C1 == 0) //If button in columns 1 is pressed
    return 1; //return '1'

    if(C2 == 0) //If button in columns 2 is pressed
    return 2; //return '2'

    if(C3 == 0) //If button in columns 3 is pressed
    return 3; //return '3'

    if(C4 == 0)//If button in columns4 is pressed
    return 4; //return '4'
    /* scane Row2*/
    R2 = 0; //Make ROW2 to low
    R1=R3=R4=1; //Make All other Row to high

    if(C1 == 0) //If button in columns 1 is pressed
    return 5; //return '5'

    if(C2 == 0)//If button in columns 2 is pressed
    return 6; //return '6'

    if(C3 == 0)//If button in columns 3 is pressed
    return 7; //return '7'

    if(C4 == 0)//If button in columns 4 is pressed
    return 8; //return '8'

    /*Scane Row3 */
    R3 = 0; //Make ROW3 to low
    R1=R2=R4=1;//Make All other Row to high
    if(C1 == 0)//If button in columns 1 is pressed
    return 9; //return '9'

    if(C2 == 0) //If button in columns 2 is pressed
    return 10; //return '10'

    if(C3 == 0)//If button in columns 3 is pressed
    return 11; //return '11'

    if(C4 == 0) //If Switch in columns 4 is pressed
    return 12; //return '12'
    /*Scane Row4*/
    R4 = 0; //Make ROW4 to low
    R1=R2=R3=1;//Make All other Row to high

    if(C1 == 0)//If button in columns 1 is pressed
    return 13; //return '13'

    if(C2 == 0)//If button in columns2 is pressed
    return 14; //return '14'

    if(C3 == 0)//If button in columns3 is pressed
    return 15; //return '15'

    if(C4 == 0)//If button in columns4 is pressed
    return 16; //return '16'

    return '\0';
    }

    #7
    teenix
    Junior Member
    • Total Posts : 51
    • Reward points : 0
    • Joined: 2017/12/21 13:47:21
    • Location: Australia, Melbourne
    • Status: offline
    Re: Need help - a matrix keypad with interrupt 2020/01/18 21:42:51 (permalink)
    0
    You could use the timer interrupt for the entire key scan routine, say every 1mS.
     
    Here's a simple outline...
     
    Assume:
      col 0 is low to start
      keyDownFlag = Clear
      keyValue = nil
     

    if debounce > 0
      dec debounce
      bra NextCol
    read rows
    is any row = lo
      yes: set keyDownFlag
           is keyValue set
           no: decode keypress
               set keyValue
               process key press
               set debounce = 20 (mS)
     
    NextCol:
    is col 4 active
      yes: set col 1
           is keyDownFlag set
             no: is keyValue set
                 yes: set debounce = 20 (mS)
                      keyValue = nil
           clear keyDownFlag
      no:  set next col
    exit

     
    cheers
     
    Tony
    post edited by teenix - 2020/01/18 23:33:30
    #8
    pcbbc
    Super Member
    • Total Posts : 1507
    • Reward points : 0
    • Joined: 2014/03/27 07:04:41
    • Location: 0
    • Status: offline
    Re: Need help - a matrix keypad with interrupt 2020/01/19 00:05:04 (permalink)
    +1 (1)
    Get it working without interrupts first. You’ll find that quite challenging enough.
     
    Unless you have diodes in your matrix you code for the row drivers is probably wrong (at least according to the comments)...
    R1 = 0; //Make R1 to low
    R2=R3=R4=1; //Make All other Row to high

    Only one row should be an output at any one time.  Otherwise, if you accidentally press buttons in multiple rows, you can create a short between two row pins through their common column line. One row at a logic high and the other at logic low....
     
    Make the rows you are not scanning inputs, ideally with a pull-up. Then only one pin (the row you are currently scanning) is low at any one time, and all other row/column pins inputs and pulled up. This way you cannot have any shorts.
     
    But as you do not show use the definitions for R1-R4 I am only guessing these are defined as the port or lat register bits.
     
    You’ll get more helpful responses if you post your complete code rather than incomplete snippets.
    #9
    nigelwright7557
    Super Member
    • Total Posts : 344
    • Reward points : 0
    • Joined: 2006/11/06 08:15:51
    • Location: 0
    • Status: offline
    Re: Need help - a matrix keypad with interrupt 2020/01/19 03:02:58 (permalink)
    0
    Be careful with your hardware too.
    If you have two keys pressed on different columns you can short a 0 output to a 1 output.
    Use diodes on column outputs.
     
    #10
    abhi143
    Junior Member
    • Total Posts : 102
    • Reward points : 0
    • Joined: 2018/05/20 09:06:52
    • Location: 0
    • Status: offline
    Re: Need help - a matrix keypad with interrupt 2020/01/19 09:03:20 (permalink)
    0
    pcbbcYou’ll get more helpful responses if you post your complete code rather than incomplete snippets.

    I have seen some codes that are beyond my comprehension. I do not understand how to move forward from here

    // PIC16F877A Configuration Bit Settings
    // 'C' source line config statements
    // CONFIG
    #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
    #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
    #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
    #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
    #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
    #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
    #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
    #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
    // #pragma config statements should precede project file includes.
    // Use project enums instead of #define for ON and OFF.
    #include <xc.h>
    #define _XTAL_FREQ 20000000

    #define R1 RB0
    #define R2 RB1
    #define R3 RB2
    #define R4 RB3
    #define C1 RB4
    #define C2 RB5
    #define C3 RB6
    #define C4 RB7

    unsigned char Keypad_Scan()
    {
    /*Scane Row1*/
    R1 = 0; //Make R1 to low
    R2=R3=R4=1; //Make All other Row to high
    if(C1 == 0) //If button in columns 1 is pressed
    return 1; //return '1'

    if(C2 == 0) //If button in columns 2 is pressed
    return 2; //return '2'

    if(C3 == 0) //If button in columns 3 is pressed
    return 3; //return '3'

    if(C4 == 0)//If button in columns4 is pressed
    return 4; //return '4'
    /* scane Row2*/
    R2 = 0; //Make ROW2 to low
    R1=R3=R4=1; //Make All other Row to high

    if(C1 == 0) //If button in columns 1 is pressed
    return 5; //return '5'

    if(C2 == 0)//If button in columns 2 is pressed
    return 6; //return '6'

    if(C3 == 0)//If button in columns 3 is pressed
    return 7; //return '7'

    if(C4 == 0)//If button in columns 4 is pressed
    return 8; //return '8'

    /*Scane Row3 */
    R3 = 0; //Make ROW3 to low
    R1=R2=R4=1;//Make All other Row to high
    if(C1 == 0)//If button in columns 1 is pressed
    return 9; //return '9'

    if(C2 == 0) //If button in columns 2 is pressed
    return 10; //return '10'

    if(C3 == 0)//If button in columns 3 is pressed
    return 11; //return '11'

    if(C4 == 0) //If Switch in columns 4 is pressed
    return 12; //return '12'
    /*Scane Row4*/
    R4 = 0; //Make ROW4 to low
    R1=R2=R3=1;//Make All other Row to high

    if(C1 == 0)//If button in columns 1 is pressed
    return 13; //return '13'

    if(C2 == 0)//If button in columns2 is pressed
    return 14; //return '14'

    if(C3 == 0)//If button in columns3 is pressed
    return 15; //return '15'

    if(C4 == 0)//If button in columns4 is pressed
    return 16; //return '16'

    return '\0';
    }
    void main(void)
    {
    while(1)
    {

    }
    }

    #11
    mpgmike
    Super Member
    • Total Posts : 365
    • Reward points : 0
    • Joined: 2014/01/23 17:27:06
    • Location: NJ
    • Status: offline
    Re: Need help - a matrix keypad with interrupt 2020/01/19 10:40:46 (permalink)
    +1 (1)
    I learned a way to use a single analog input for matrixed keypads.  Output is at Vss potential until a key is pressed.  The internal comparator can trigger a read (either through an interrupt or polling) with DACCON1 = 1.  A switch() can then parse through options to find the pressed key.  It only uses 1 analog I/O pin.  Test key presses in Debug mode, then set your switch() thresholds at midpoints between values.
     

    Attached Image(s)


    I don't need the world to know my name, but I want to live a life so all my great-grandchildren proudly remember me.
    #12
    pcbbc
    Super Member
    • Total Posts : 1507
    • Reward points : 0
    • Joined: 2014/03/27 07:04:41
    • Location: 0
    • Status: offline
    Re: Need help - a matrix keypad with interrupt 2020/01/19 17:04:12 (permalink)
    +1 (1)
    Which code is “beyond your comprehension”? What bits of it don’t you understand?
    teenix gave you a very long and detailed description earlier in this thread of how a matrix keyboard routine works.
     
    Currently your function Keypad_scan isn’t being called from anywhere, so it does nothing.
    Also you are writing to individual output pins directly, which almost certainly will cause RMW issues and I’m sure  you’ve been told about those before...
     
    1. Write some initialisation so that you set up the PIC correctly.  You haven’t even set the TRISB register to configure PORTB pins as inputs/outputs! You should have learnt to do this when flashing a led. Go back and study that example if you did not understand it properly the first time.
    2. Call Keypad_scan in your main while loop.
    3. Do something with the returned result (e.g. light some LEDs) so you can tell if it is working or not.
    4. Fix your row outputs so that only ONE of the rows is an output pin (and driven low) at any one time.  Otherwise you will risk high output pins being shorted to ground via key presses. To do this...
    a) RB0..RB3 should all be low. You can set these before the main loop in your initialisation. You do not need to change them thereafter.
    b) Instead of toggling the row pins high/low in Keyboard_scan, switch ONE of the rows to be an output at a time using TRISB. Leave the other three rows as inputs so you do not get a short.
     
    #13
    Jump to:
    © 2020 APG vNext Commercial Version 4.5