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.

4x3 Keypad scanning using interrupt method MikroC and PIC

Status
Not open for further replies.

georgiod9

Newbie level 4
Joined
Dec 21, 2015
Messages
5
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
83
Hello People,

I am new to this forum and to programming PIC microcontrollers. I am facing a problem with interfacing a 4x3 keypad matrix using the interrupt method rather than polling. I need this interrupt method for my specific application as I do not want the Microcontroller to waste time and processing power trying to do a job which can be done easier.
I have written the following C code using MikroC PRO for Pic. Moreover, I have tried simulating it with Proteus, so i am pretty sure my code has something wrong. Never mind the RTC DS1307 in the Proteus. Please any help would be much appreciated; I have been trying to solve this issue ever since 5 days ago and I haven't been sleeping doing research on other projects and ways to go around this issue.
Thanks in advance.


Code:
unsigned short kp;
int flag;                     //Flag which determines to which row the 
                              //keypress resides
//Keypad Connections
sbit COL1 at RA0_bit;
sbit COL2 at RA1_bit;
sbit COL3 at RA2_bit;
sbit ROW1 at RB4_bit;
sbit ROW2 at RB5_bit;
sbit ROW3 at RB6_bit;
sbit ROW4 at RB7_bit;
//End Keypad connections

//LCD Connections
sbit LCD_RS at RD0_bit;
sbit LCD_EN at RD1_bit;
sbit LCD_D4 at RD4_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D7 at RD7_bit;

sbit LCD_RS_Direction at TRISD0_bit;
sbit LCD_EN_Direction at TRISD1_bit;
sbit LCD_D4_Direction at TRISD4_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D7_Direction at TRISD7_bit;
// End LCD module connections

char text[6];
void my_keypad();             //This function allows to set a column of the
                              //keypad while clearing others

void main()
{
     INTCON = 0x08;           //Enable RBIF bit
     TRISB = 0xF0;            //Set RB4-RB7 as inputs to mcu
     TRISA = 0X00;            //Set RA0-RA2 as outputs from mcu
     lcd_init();
     lcd_cmd(_LCD_CURSOR_OFF);
     lcd_cmd(_LCD_CLEAR);

     lcd_out(1,1,"hello");    //just a test for the lcd
     while(1)
  {
     my_keypad();
     if(flag == 1)            //If we have a keypress on row 1
     {
          if(PORTA.B0)        //number value:
             kp = 49;         //1 ---> 49 in ASCII
          else if(PORTA.B1)
             kp = 50;         //2 ---> 50 in ASCII
          else if(PORTA.B2)
             kp = 51;         //3 ---> and so on...
     }
     else if(flag == 2)       //If we have a keypress on row 2
     {
          if(PORTA.B0)        //If Column1 == 1
             kp = 52;         //4
          else if(PORTA.B1)   //If Column2 == 1
             kp = 53;         //5
          else if(PORTA.B2)   //If Column 3 == 1
             kp = 54;         //6
     }

     else if(flag == 3)       //If we have a keypress on row 3
     {
          if(PORTA.B0)
             kp = 55;         //7
          else if(PORTA.B1)
             kp = 56;         //8
          else if(PORTA.B2)
             kp = 57;         //9
     }

     else if(flag == 4)       //If we have a keypress on row 4
     {
          if(PORTA.B0)
             kp = 42;         //*
          else if(PORTA.B1)
             kp = 48;         //0
          else if(PORTA.B2)
             kp = 35;         //#
     }
     lcd_out(1,1,kp);
  }


}
void interrupt()
{
     if(INTCON.RBIF)          //checks for an interrupt flag on port B
     {
       if(PORTB.F4 == 0)      //check the value on pin B4 or Row 1 of keypad
          flag = 1;           //flag = 1 means we have a keypress on row 1

       else if(PORTB.F5 == 0) //check the value on pin B5 or Row 2 of keypad
          flag = 2;           //flag = 2 means we have a keypress on row 2

       else if(PORTB.F6 == 0) //check the value on pin B6 or Row 3 of keypad
          flag = 3;           //flag = 3 means we have a keypress on row 3

       else if(PORTB.F7 == 0) //check the value on pin B7 or Row 4 of keypad
          flag = 4;           //flag = 4 means we have a keypress on row 4
     }
     INTCON.RBIF = 0;         //Reset interrupt flag on port B
}

void my_keypad()             //function that sets and resets the columns
                             //columns are outputs of mcu
                             //rows are inputs to mcu, rows are connected
                             //to pulldown resistors
{
    //Test column 1
    PORTA.F0 = 1;           //Set Column 1 to 1
    PORTA.F1 = 0;           //Set Column 2 to 0
    PORTA.F2 = 0;           //Set Column 3 to 0
    DELAY_MS(20);

    //Test column 2
    PORTA.F0 = 0;           //Set Column 1 to 0
    PORTA.F1 = 1;           //Set Column 2 to 1
    PORTA.F2 = 0;           //Set Column 3 to 0
    DELAY_MS(20);

    //Test column 3
    PORTA.F0 = 0;          //Set Column 1 to 0
    PORTA.F1 = 0;          //Set Column 2 to 0
    PORTA.F2 = 1;          //Set Column 3 to 1
    delay_ms(20);
}

Attached is a compressed folder with the code files and the proteus simulation files.
 

Attachments

  • Keypad.zip
    73.9 KB · Views: 125

You haven't enabled the GIE bit so the interrupt will never trigger.

Also check that you read PORTB again after resetting the RBIF bit. It sets when the pin state changes so it needs an update on present state to be able to see it changing. I'm not familiar with MikroC so it may be reading anyway when you execute the 'if(PORTB..." instructions. Beware that if the ISR finishes before the key has been released, it will assume key down is the default state and interrupt again as it is released.

Brian.
 

Hey Brian,

I tried adding the code which sets the GIE at the beginning of the main function. However, this did not solve the problem. Let me tell you what is happening. When i run the simulation, variations in voltage are only happening on column 3 of the keypad. It seems like only the last block of my_keypad() is executing. Another thing is the compiler in do while loop in the main function is not accessing the if statements which test the pins of PORTA (columns). As an example, else if(PORTA.B2) is not entering its body even though PORTA.B2 = 1.
 

I don't use MikroC or Proteus so I can't compile or simulate it but looking at your source file I see some things that don't look right:

1. Check the bit names you are using, I think MikroC uses the port bit definitions interchangeably (.A0 = .B0 = .C0 = .D0 = .E0 = .F0 for example) but if I'm wrong you are assigning the port bits wrongly.

2. You drive the columns high one at a time but the ISR sets the flags if the row bit is low. I suspect you intend to check them for being high.

3. You use the functions DELAY_MS() and delay_ms(). The C language is case sensitive so make sure both are valid.

4. There is no detection of 'no key pressed'. The interrupt on PORTB changing works whenever a bit toggles from it's previously read state so if you return from the ISR while the key is still pressed, a further interrupt will be generated when it is released. Consider adding some code to check the row inputs are all zero before enabling the interrupt again. Hint: do not do this inside the interrupt itself as it will block any other interrupts while you wait.

Brian.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top