Search code examples
cembeddedmicrocontrollerpic18

Matrix Keypad Implementation problem: PICSimLab, PICGenios, PIC18F4580


I'm trying to use the matrix keypad in PICSimLab's PICGenios board with PIC18F4580 MCU. The schematic for the board is here. Below is the code.

matrix_keypad.h

#ifndef MATRIX_KEYPAD_H
#define MATRIX_KEYPAD_H

#define ROW1 PORTDbits.RD0
#define ROW2 PORTDbits.RD1
#define ROW3 PORTDbits.RD2
#define ROW4 PORTDbits.RD3

#define COL1 PORTBbits.RB0
#define COL2 PORTBbits.RB1
#define COL3 PORTBbits.RB2

#define DEBOUNCE_DELAY 400

void init_switch(void);
unsigned char scan_keypad(void);
unsigned char debounce_signal();

#endif

matrix_keypad.c

#include <xc.h>
#include "matrix_keypad.h"

void init_switch() {
    //digital pins.
    ADCON1 = 0xFF;
    
    //set first three bits as input & rest as output for PORTB.
    TRISB = 0x07;
    
    //set up PORTB internal pull-ups.
    RBPU = 0;

    //set PORTD as output.
    TRISD = 0;

    //set all row bits.
    ROW1 = ROW2 = ROW3 = ROW4 = 1;
}

unsigned char scan_keypad() {

    unsigned char ret_val = 0;

    //scan keys on row 1.
    ROW1 = 0;
    if (!COL1)
        ret_val = 1;
    if (!COL2)
        ret_val = 2;
    if (!COL3)
        ret_val = 3;
    ROW1 = 1;

    //scan keys on row 2.
    ROW2 = 0;
    if (!COL1)
        ret_val = 4;
    if (!COL2)
        ret_val = 5;
    if (!COL3)
        ret_val = 6;
    ROW2 = 1;

    //scan keys on row 3.
    ROW3 = 0;
    if (!COL1)
        ret_val = 7;
    if (!COL2)
        ret_val = 8;
    if (!COL3)
        ret_val = 9;
    ROW3 = 1;

    //scan keys on row 4.
    ROW4 = 0;
    if (!COL1)
        ret_val = 10;
    if (!COL2)
        ret_val = 11;
    if (!COL3)
        ret_val = 12;
    ROW4 = 1;

    /*if (ret_val)
        PORTBbits.RB6 = 1;              ----------->why tho?
    else
        PORTBbits.RB6 = 0;*/

    return ret_val;
}

main.c

#include <xc.h>
//#include "clcd.h"
#include "matrix_keypad.h"

void main(void) {

    init_switch();
    for (unsigned int i = 0; i < 1000; ++i);

    while (1) {
        if (scan_keypad()) {
            PORTBbits.RB7 = 1;
        } else {
            PORTBbits.RB7 = 0;
        }
    }

    return;
}

I expect the scan_keypad() call in main.c to output a non-zero value as long as I press and hold any key in the matrix keypad. But what happens is not that - the RB7 LED runs with a duty cycle of about 50%, meaning my scan_keypad() call is outputting zero and a non-zero values in an alternating fashion.

I saw that this problem goes away and scan_keypad() behaves as expected when I add the following lines before returning from it:

if (ret_val)
            PORTBbits.RB6 = 1;              ----------->why tho?
        else
            PORTBbits.RB6 = 0;

The PORT bits can be any PORT bits. I've spent the whole day trying to figure out why and I'm not able to come up with an answer. Help me please.


Solution

  • Your code is correct. But it is without any debounce treatment. Due to limitations of the PICSimLab simulator (I'm the developer), it is necessary to add a delay of at least 50 microseconds before reading the pins to work (normally the delay is added in the debounce treatment).

    unsigned char scan_keypad() {
    
        unsigned char ret_val = 0;
    
        //scan keys on row 1.
        ROW1 = 0;
        __delay_us(50);
        if (!COL1)
            ret_val = 1;
        if (!COL2)
            ret_val = 2;
        if (!COL3)
            ret_val = 3;
        ROW1 = 1;
    
        //scan keys on row 2.
        ROW2 = 0;
        __delay_us(50);
        if (!COL1)
            ret_val = 4;
        if (!COL2)
            ret_val = 5;
        if (!COL3)
            ret_val = 6;
        ROW2 = 1;
    
        //scan keys on row 3.
        ROW3 = 0;
        __delay_us(50);
        if (!COL1)
            ret_val = 7;
        if (!COL2)
            ret_val = 8;
        if (!COL3)
            ret_val = 9;
        ROW3 = 1;
    
        //scan keys on row 4.
        ROW4 = 0;
        __delay_us(50);
        if (!COL1)
            ret_val = 10;
        if (!COL2)
            ret_val = 11;
        if (!COL3)
            ret_val = 12;
        ROW4 = 1;
    
        /*if (ret_val)
            PORTBbits.RB6 = 1;              ----------->why tho?
        else
            PORTBbits.RB6 = 0;*/
    
        return ret_val;
    }