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.

Interface 3x4 matrix Keypad with PIC18F452 using 74C922

Status
Not open for further replies.

speedEC

Full Member level 6
Joined
Apr 1, 2011
Messages
337
Helped
23
Reputation
46
Reaction score
21
Trophy points
1,298
Activity points
4,324
Dear all,

I like to use 74C922 keypad encoder to connect the keypad (3x4) to PIC18F452. I searched the forum for this topic. But, I could not able to find anything useful for me. I have connected the DA(Data available) pin at interrupt pin on the PIC. I can able to receive some character from the keyboard when the key is pressed. But, I don't know how to scan the D0, D1, D2, D3 rows (that are connected to RB2, RB3, RB5 and RB6 of the PIC) and extract the correct key value. Pl help me.

Thanks
 

You don't have to. The 74C922 does all that for you.
All you need to do is monitor the "Data Available" signal on pin 13 and when it goes high, you read the data output lines. Each key produces a unique binary number on the output lines. Note that for the '922 to work you must have the -Output Enable (pin 14) held low or grounded.

Brian.
 
You don't have to. The 74C922 does all that for you.
All you need to do is monitor the "Data Available" signal on pin 13 and when it goes high, you read the data output lines. Each key produces a unique binary number on the output lines. Note that for the '922 to work you must have the -Output Enable (pin 14) held low or grounded.

Brian.

Thanks Brian.

Yes. I already grounded the OE pin (no:14). I have received some character. I wrote the code as follows:


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
as mentioned in the 74C992 datasheet A,B,C,D - 0,0,0,0 - Y1X1 - i.e button "1":
 
INTCONbits.INT0IF = 0; // disable PORTB interrupts
    
    if((PORTBbits.RB2 == 0) & (PORTBbits.RB3 == 0) & (PORTBbits.RB5 == 0) & (PORTBbits.RB6 == 0)){
        WriteCmdXLCD(CLR_LCD); 
        while(BusyXLCD()); 
        WriteCmdXLCD(HOME_LCD); 
        while(BusyXLCD()); 
        putrsXLCD("1");
    }
     else{
        WriteCmdXLCD(CLR_LCD); 
        while(BusyXLCD()); 
        WriteCmdXLCD(HOME_LCD); 
        while(BusyXLCD()); 
        putrsXLCD("Other Key Pressed");
    }
INTCONbits.INT0IE = 1; // enable PORTB interrupts



I always received "Other key pressed" even if I pressed kay "1" on key pad. Any help?
 

I think the problem is in the way you are handling the interupt. I assume the code you show is part of an ISR and is only entered when the "Data Available" pin goes high.
You can simplify the bit check into "if((PORTB & 0x93) == 0)" which will save some typing and execution time but I suspect your problem lies in the way you read the bits. Instead of checking the port bits individually which is risky because they might change during the read operation, read the whole PORTB into a variable (take a snapshot of PORTB contents) then check the bits in that variable instead. Doing that makes the value stable, it can't change between reading bit2 and reading bit 6.

Brian.
 
I think the problem is in the way you are handling the interupt. I assume the code you show is part of an ISR and is only entered when the "Data Available" pin goes high.
You can simplify the bit check into "if((PORTB & 0x93) == 0)" which will save some typing and execution time but I suspect your problem lies in the way you read the bits. Instead of checking the port bits individually which is risky because they might change during the read operation, read the whole PORTB into a variable (take a snapshot of PORTB contents) then check the bits in that variable instead. Doing that makes the value stable, it can't change between reading bit2 and reading bit 6.

Brian.

Actually I am very new to PIC and only moderate on C, C++. So, I don't know how to read the entire PORT and store the data into the variable. If possible if you provide some code example with details I can able to develop the application based on my requirements.

Also, I have little doubt about using Interrupts.

By default, INT0 is high priority. The HIGH priority starts at the address 0x08. and LOW priority starts at the address 0x18. Am I right?

I have already used 2 Priorities. One is INT0 for button press. I connected the push button on RB0(INT0) and i do execute something if INT0 interrupt occurred. Also, I have connected the GSM Modem (SIMCOM300) to the PIC18F452. I set the receive interrupt as LOW.

So, I used 2 interrupts.

Here the code snippet.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma code high_vector_section=0x8 //high interrupt vector
void
high_vector (void)
{
  _asm GOTO button _endasm
}
 
#pragma code rx_interrupt = 0x18 //low interrupt vector
void rx_int (void)
{
  _asm goto rx_handler _endasm
}
#pragma code



If I use another interrupt (i.e INT1) and specified the interrupt address as 0x8 or 0x18, I receive error.

for example (ERROR on following code):

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma code high_vector_section=0x8 //high interrupt vector
void
high_vector (void)
{
  _asm GOTO button _endasm
}
 
#pragma code rx_interrupt = 0x18 //low interrupt vector
void rx_int (void)
{
  _asm goto rx_handler _endasm
}
#pragma code INT1_interrupt = 0x18 //low interrupt vector
void rx_int (void)
{
  _asm goto INT1_handler _endasm
}
#pragma code



I want to use INT0/INT1/RX interrupts in a single application. Can you please help me?

Thanks.
 

You are correct about the two addresses but there are a few things that will cause problems.
The most obvious is that when you enter the interrupts you 'goto' code somewhere else. The return address is pushed onto the stack when the interrupt occurs so if you 'goto' another routine, you must end it with a return from interrupt instruction so the stack is restored and the program can continue from where it was. Until you are more familiar with 'C', I suggest you change the 'goto' to 'call' and treat the button and rx_int code like a subroutine. Then, add a line after the 'call' to return from the interrupt. So the structure is more like this:

1. Hardware triggers the interrupt and ISR code is entered
2. call the service routine - end it with a 'return' instruction
3. return from the interrupt

This will take you right back to the point in the program that was running when the interrupt occurred.

When you have more than one source of interrupt on one priority, the software has to ask each source of the interrupt if it needs servicing. In my example, you would add an extra stage between steps 1 and 2 in which the code interrogated the hardware and made a decision on which routine to call.

Brian.
 
Sorry betwixt. I could not able to reply for more than a week. Because, I was not in a position (due to personal problem) to use internet for this period. I regret for that. Now I came back to work.

I think the problem in my code structure as you told in your earlier reply. So, I have changed my code as you suggested as follows. In order to understand my problem, I have posted the large code. Excuse for that:



Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#pragma code high_vector_section=0x8 //high interrupt vector
void high_vector (void)
{
    if (INTCONbits.RBIF){
        KeyPad_Interrupt();
      //  return;
    }
    else{
        button();
      //  return;
    }
}
 
#pragma code rx_interrupt = 0x18 //low interrupt vector
void rx_int (void)
{
    rx_handler();
  //  return;
}
#pragma code
 
#pragma interrupt button
void button (void)
{
      
    if (LED == 1){
        LED = 0;
        ALARM = 1;
        strcpypgm2ram(WhatToDo, (const far rom char*)"SendSMS_SwitchOnOff");
        strcmppgm2ram(identity, (const far rom char*)"SendSMS_Interrupt");
        while (BusyUSART());
        putrsUSART((const far rom char*)"AT+CMGS=");
        putcUSART(0x22);
        putsUSART(strBuff_IncomingPhNum);
        putcUSART(0x22);
        while (BusyUSART());
        putcUSART(0x0D);
        
    }
 
  /* clear the interrupt flag */
  INTCONbits.INT0IF = 0;
 
}
 
#pragma interrupt KeyPad_Interrupt
void KeyPad_Interrupt(void){
    showPressedKey();
}
 
void showPressedKey(void){
.
.
.
.
}
 
#pragma interruptlow rx_handler // changed the interrupt to interruptlow
void rx_handler (void)
{
  unsigned char input;
  
  PIR1bits.RCIF = 0; // clear interrupt flag
  
  input = ReadUSART();
    
    switch(input){
                case '\x0A':
                .
                case '': showGSM_DATA(gsmOutput_c[]);
                .
                default:
          }
}
 
void showGSM_DATA(char gsmOutput_s[]){
.
.
.
.
.
}



The above code works fine for Button, Keypad interrupt.

But for the rx_handler interrupt there is a error I encountered. For example the following code works fine.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//Processing and Validating GSM_MODEM_OR_MODULE OUTPUT
 
void showGSM_DATA(char gsmOutput_s[]){
 
   if (strcmppgm2ram(gsmOutput_s, (const far rom char*)"OK") == 0){
       OK = TRUE;
   }
 
   if (strcmppgm2ram(gsmOutput_s, (const far rom char*)"ERROR") == 0){
       OK = FALSE;
     return;
   }
  
   // READING PHONE BOOK AND COPY ALL STORED PHONE NUMBERS INTO 
// ARRAY FOR FUTURE REFERENCE AND FOR VALIDATION
 
    if(strcmp(NextGSMCmd, Read_PhBk) == 0){
        *NextGSMCmd = 0;
           WriteCmdXLCD(CLR_LCD); 
    while(BusyXLCD()); 
    WriteCmdXLCD(HOME_LCD); 
    while(BusyXLCD()); 
        
        if (OK == TRUE){
            
            OK = FALSE;
            strcpypgm2ram(NextGSMCmd, (const far rom char*) "store_PhBk_Into_Array");
            *gsmOutput_s = 0;
            count_CPBR = 0;
            
            while (BusyUSART());
            putrsUSART((const far rom char *)"AT+CPBR=1");
            while (BusyUSART());
            putcUSART(0x0A);
            putcUSART(0x0D);
        }
        else{
            putrsXLCD("BAUD SETTING ERROR");
        }
      return;
    }
}
 
if (strcmp(strBuff, PH_BK_CPBR) == 0){
            
     *strBuff = 0;
      if (strcmppgm2ram(NextGSMCmd, (const far rom char*) "store_PhBk_Into_Array") == 0){
          strcpypgm2ram(NextGSMCmd, (const far rom char*) "PhBk_Stored");



HERE THE PROBLEM ARAISES: i.e. If we comment the following code entire thing works fine.


Code C - [expand]
1
2
3
4
5
6
7
/*    
                      WriteCmdXLCD(CLR_LCD); 
                      while(BusyXLCD()); 
                      WriteCmdXLCD(HOME_LCD); 
                      while(BusyXLCD()); 
                      putrsXLCD("gsmOutput_s"); 
              */



But, If I uncomment, the data displayed correctly and hangs.


Code C - [expand]
1
2
3
4
5
WriteCmdXLCD(CLR_LCD); 
                      while(BusyXLCD()); 
                      WriteCmdXLCD(HOME_LCD); 
                      while(BusyXLCD()); 
                      putrsXLCD("gsmOutput_s");




Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
}
            return;
} 
 
if (strcmppgm2ram(NextGSMCmd, (const far rom char*) "PhBk_Stored") == 0){
            
            *NextGSMCmd = 0;
            *gsmOutput_s = 0;
            count_CPBR = 0;
            WriteCmdXLCD(CLR_LCD); 
        while(BusyXLCD()); 
        WriteCmdXLCD(HOME_LCD); 
        while(BusyXLCD());
            
            if (OK == TRUE){
                OK = FALSE;
                putrsXLCD("PH BK READ - OK");
            }
            else{
                putrsXLCD("PH BOOK ERROR");
            }
         return; 
}



Any help to locate the issue. I strongly believe that the error could be related to interrupt as you told. But, I do not know how to change the code. Pl go thro' and pl guide me.

Advance thanks.
 

Just a guess - I can't see where you clear the keypad interrupt. Look at the code for the rx_handler interrupt, the first thing you do is clear the interrupt flag which is the right thing to do but I cannot see where you do the same for the RBIF bit if 'keypad_interrupt()' is called.

Brian.
 
I have not put the code for "keypressed" interrupt in order to reduce the code size and also there is no problem in that interrupt. Sorry for that. Here is the detailed code for "keypressed" interrupt


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void showPressedKey(void){
    
    char incode; // temporary variable
    INTCONbits.RBIE = 0; // disable PORTB interrupts
    // decode row and column
    PORTB = 0x0f;
    PORTBbits.RB1 = 0; // enable CDEF column
    Nop();
    incode = PORTB & 0xf0;
    
    switch (incode)
    {
        case 0x70: NewKey = '3'; break;
        case 0xB0: NewKey = '6'; break;
        case 0xD0: NewKey = '9'; break;
        case 0xE0: NewKey = '#'; break;
    }
    .
    .
    .
    .
    INTCONbits.RBIF = 0; // clear PORTB flag
    INTCONbits.RBIE = 1; // enable PORTB interrupts
}



Also I have cleared the RCIF flag and Enable RC interrupt at


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#pragma interruptlow rx_handler // changed the interrupt to interruptlow
void rx_handler (void)
{
  unsigned char input;
  
  PIR1bits.RCIF = 0; // clear interrupt flag
  
  input = ReadUSART();
    
    switch(input){
            
            case '\x0A': // if line feed detected in the GSM output i.e. '\n'
                        break;
            case '\x0D': // if carriage return detected i.e. '\r'
                        gsmOutput_c[i] = '\x00';
                        
                        lenOfGSMOutput = strlen((char*)gsmOutput_c);
                        if (lenOfGSMOutput > 0){
                            i = 0;
                            lenOfGSMOutput = 0;
                            PIE1bits.RCIE = 0;
                            showGSM_DATA(gsmOutput_c);
                            
                            *gsmOutput_c = 0;
                            PIR1bits.RCIF = 0; // clear interrupt flag
                            PIE1bits.RCIE = 1; // enable receive interrupts
.
.
.
.
.
.
}



Anyother suggestions that I have to change. pl advice needed.
 

To be honest, I can't see what is wrong. I'm not familiar with your compiler either so if there is something wrong in a function parameter I wouldn't spot it although I would expect it to show up as a compilation error.
The only other thing I can think of is maybe the interrupt priority is not configured properly. Check the IPEN, GIEH and GIEL bits. Are you seeing the error in a simulation or in real hardware?

Brian.
 

To be honest, I can't see what is wrong. I'm not familiar with your compiler either so if there is something wrong in a function parameter I wouldn't spot it although I would expect it to show up as a compilation error.
The only other thing I can think of is maybe the interrupt priority is not configured properly. Check the IPEN, GIEH and GIEL bits. Are you seeing the error in a simulation or in real hardware?

Brian.

I am not receiving any error but hangs after displayed the "text" on LCD. The code hangs in real hardware only.

any idea. pl.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top