• Forums
• Posts
Latest Posts
Active Posts
Recently Visited
Search Results
• Page Extras
• Forum Themes
• 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
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 highif(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 ?

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.
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 ?
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.
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)
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
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 highif(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';}`

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 NextColread rowsis 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 colexit`

cheers

Tony
post edited by teenix - 2020/01/18 23:33:30
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 lowR2=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.
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.

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 highif(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)  {  }}`

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.

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.
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.