4x4 Keypad Matrix

StigOfTheDump

Senior Member
Hi

I got some 4x4 keypads today. I found some code by Hippy but it is a bit too complicated for me to understand. The symbol definitions had ORs in them and some of the statements were ANDing masks and pins then XORing them with something else. Just too much for my head at this stage.

I wrote some code that seems to work and would appreciate it, if someone could cast their eye over it. The existing gosubs were just so that I can see that it is doing the right thing. The eventual intention is for this to be a gosub that I can call. Many of my projects will need a similar keypad input and I don't want it to fall to bits because of some scenario that I've overlooked.

Without the subroutines it comes in at about 100 bytes which seems a lot for reading 16 buttons. Also if the button values had to be displayed it would need a look-up table.

I didn't use any dirBs. Did I need to or are they implied by my commands?

The select case bit seems rather clumsy but I couldn't find a way to do it with loops and bits.

I've used up 4 variables, even with recycling one of them. The b1=b0-4*4+b2 line doesn't work as b1=b0-4*4+b1. I think that must be the left to right maths changing the b1 before it has been read. I could have saved a variable there.

Code:
#Picaxe 18M2
#Terminal 4800




'16 key 4x4 matrix keypad

'INPUTS
'B.0		 1	 2	 3	 A
'B.1		 4	 5	 6	 B
'B.2		 7	 8	 9	 C
'B.3		 *	 0	 #	 D
			
'OUTPUTS	B.4	B.5	B.6	B.7
		
		

main:

for b0=B.4 to B.7			'Output to one column at a time
high b0				'Switch on that output
b3=pinsB & %00001111		'See which row is pressed

do
b1=pinsB & %00001111		'Wait until button is released
loop while b1<>0

select case b3 
case 1 :b2=1			'If only row 1
case 2 :b2=2			'If only row 2
case 4 :b2=3			'If only row 3
case 8 :b2=4			'If only row 4
else b2=0				'Discount any other combinations
endselect

low b0				'Switch off the output

b1=b0-4*4+b2			'Add 4x column to row (to get unique 1-16 value)			'


if b2=0 then let b1=0 endif	'Wrong combination = no results


					'Select subroutine to visit
on b1 gosub btn0,btn1,btn2,btn3,btn4,btn5,btn6,btn7,btn8,btn9,btn10,btn11,btn12,btn13,btn14,btn15,btn16

next b0				'Next column


goto main


btn0:					'Empty routine for wrong combination
return

btn1:					'Show which button was pressed
sertxd ("Button 1 pressed",cr,lf)
return

btn2:
sertxd ("Button 4 pressed",cr,lf)
return

btn3:
sertxd ("Button 7 pressed",cr,lf)
return

btn4:
sertxd ("Button * pressed",cr,lf)
return

btn5:
sertxd ("Button 2 pressed",cr,lf)
return

btn6:
sertxd ("Button 5 pressed",cr,lf)
return

btn7:
sertxd ("Button 8 pressed",cr,lf)
return

btn8:
sertxd ("Button 0 pressed",cr,lf)
return

btn9:
sertxd ("Button 3 pressed",cr,lf)
return

btn10:
sertxd ("Button 6 pressed",cr,lf)
return

btn11:
sertxd ("Button 9 pressed",cr,lf)
return

btn12:
sertxd ("Button # pressed",cr,lf)
return

btn13:
sertxd ("Button A pressed",cr,lf)
return

btn14:
sertxd ("Button B pressed",cr,lf)
return

btn15:
sertxd ("Button C pressed",cr,lf)
return

btn16:
sertxd ("Button D pressed",cr,lf)
return
Has any body any thoughts/tips/gaping great holes spotted?
 

hippy

Ex-Staff (retired)
The problem is, if you make one B.4-B.7 keypad line high and, another low, what happens when you push two keys which short that high to low ?

You can either block current flow with diodes use current limiting resistors, or use dirB.x ( or INPUT commands ) to ensure only one line is ever an output at a time and that it can never happen.

Of course the PICmicro / PICAXE is quite robust and can generally withstand short periods of abuse so you could decide it's a risk you are prepared to take but it is a risk.

You'll also need pull-downs so that the inputs B.0-B.3 aren't floating when no keys are pressed. By using active low strobes that allows internal weak pull-ups to be used but you have to map keypad lines to the right I/O pins.

There's also a question of speed, how quickly you can scan the matrix when none are pushed, but that's usually not that important. One trick is to set all B.4-B.7 lines high ( shorts won't matter as they are all high ) then you can detect if any of those keys were pressed, continue next bank of keys, or determine which and bail out.

I expect my code covered all that which is why it's quite complicated. Your principle is fine, just that 'shorting risk' really.
 

StigOfTheDump

Senior Member
Good point about the series resistors. I kind of forgot that when an output is not high it is LOW. Pressing certain combinations could cause a short.

The pull-downs are fitted I just didn't show them on the picture.

Don't really understand about making them all high (B.4-B.7) How will I know if button 1,2,3 or A etc. is the one that has been pressed?

Hopefully speed won't be an issue as it will be a subroutine called rather than something running all the time.

Thanks for the input before I blew something.
 

dlanodnosreme

New Member
Use the ADC function for your keypad

Just a thought, there is a magazine you might want to look in to, the Oct 2010
issue of Nuts And Volts has an article "implimenting an ADC Keypad" by Ron Hacket. Very much worth reading. For it's picaxe articles alone it's worth the subscription. I subscribe to the magazines digital issues. By the way Ron Hacket breifly mentions an article he wrote back in 2007 about how to use the
18M picaxe with a row coluum scan scheme. At the very least visit the Nuts and Volts site www.nutsvolts.com
Regards
 

hippy

Ex-Staff (retired)
Don't really understand about making them all high (B.4-B.7) How will I know if button 1,2,3 or A etc. is the one that has been pressed?
It's a quick test to see if any key has been pressed. Set B.4 through B.7 all high and if any are pressed you'll read a high on at least one of the inputs. If the inputs are all low then no keys pressed, no need to actually scan the matrix.

Set say B.4 high, read all inputs and you can say the same; if all inputs low, no keys connected to B.4 are pressed, try B.5.

Once you find a B.4 to B.7 with a key pressed, then scan all inputs in turn to see which is pressed.

The speed is then improved from the nominal 4 x 4 = 16 tests for each key tested in turn to ...

1 test if none pushed

1 test plus 1 per B.4-B.7, plus up to 3 other tests if a key is pushed ( 3-7 tests )
 

westaust55

Moderator
The switch matrix approach with resistors into an ADC pin has long ago been covered on this forum by BCJKiwi and others should you care to search. Needs only 1 pin and maybe less code.

Another option is the 74922 or 74923 keypad encoder chips (with a 74HC165 shift register) which use just 3 pins and minimal code - at the expense of an external chip.

I have also seen a project on the Internet where by use of 4 diodes and a matrix type keypad it can be read by just 5 pins rather than 8 pins.
 
Last edited:

westaust55

Moderator
The switch matrix approach with resistors into an ADC pin has long ago been covered on this forum by BCJKiwi and others should you care to search. Needs only 1 pin and maybe less code.

Another option is the 74922 or 74923 keypad encoder chips (with a 74HC165 shift register) which use just 3 pins and minimal code - at the expense of an external chip.

I have ales seen a project on the Internet where by use of 4 diodes and a matrix type keypad it can be read by just 5 pins rather than 8 pins.
Edit: not the schematic I had seen previously but this attached diagram should give the idea for diodes and minimal IO without resorting to ADC or external chip. Obviously needs bidirectional pins as can be done on X1 parts (portC only) and any X2 or M2 part.
 

Attachments

Top