PDA

View Full Version : Inconsistent output on a 4x4 matrix keypad



markcadcam
- 22nd November 2006, 13:10
I am using the code listed below. It is wired per this website http://rentron.com/serkey16.htm. The output from the keypad is inconsistent. Sometimes the output is correct and sometimes the output will give the correct Column but not the correct Row. Does anybody have any ideas on why this is happening?

Thanks,
Mark











'************************************************* ***********
'* Name: Turret Controller Keypad *
'* Micro: 18F452 *
'************************************************* ***********
INCLUDE "modedefs.bas"
define OSC 20
define LOADER_USED 1 ' bootloader

col VAR BYTE ' Keypad column
row VAR BYTE ' Keypad row
key VAR BYTE ' Key value
baud VAR PortA.0 ' Baud select pin
serpin VAR PortA.1 ' Serial output pin
ADCON1 = 7 'set I/O pins to digital on PORT.A
TRISA = %00000001' PortA.0 = baud select pin
INTCON2.7 = 0 ' Enable PORTB weak pull-ups
B0 Var Byte

loop:
GOSUB getkey 'Get key from keypad
send:
'IF baud = 1 THEN fast'If baud = 1 then N9600,else N2400
SEROUT serpin,N2400,[key,B0]'Send key value out PortA.1
GOTO loop
getkey:
PAUSE 50 'Debounce key-input
getkeyu:' Wait for all keys up
PORTB = 0 ' All output-pins low
TRISB = $f0 ' Bottom 4-pins out, top 4-pins in
IF ((PORTB >> 4) != $f) THEN getkeyu'If keys down, loop
PAUSE 50 ' Debounce key-input

getkeyp:' Wait for keypress
FOR row = 0 TO 3 ' 4 rows in keypad
PORTB = 0 ' All output-pins low
TRISB = (DCD row) ^ $ff ' Set one row pin to output
col = PORTB >> 4 ' Read columns
IF col != $f THEN gotkey' If any keydown, exit
NEXT row
GOTO getkeyp ' No keys down, go look again

gotkey: ' Change row and column to key number 1 - 16
key = (row * 4) + (NCD (col ^ $f))
'NOTE: for 12-key keypad, change to key = (row * 3)
RETURN ' Subroutine over

END

peterdeco1
- 22nd November 2006, 14:16
Hi Mark. I use a 4x4 matrix to address an ISD chip to record & play messages. This is a piece of the routine I use to test the matrix. All of portb is held high with a resistor network. Maybe it will help with your problem.

TESTCELLS:
Low PORTC.1 'COLUMN 1
Pause 1
IF PORTB.4 = 0 THEN MESSAGE 1 'ROW 1
IF PORTB.5 = 0 THEN MESSAGE 2 'ROW 2
IF PORTB.6 = 0 THEN MESSAGE 3 'ROW 3
IF PORTB.7 = 0 THEN MESSAGE 4 'ROW 4
High PORTC.1

Low PORTC.2 'COLUMN 2
Pause 1
IF PORTB.4 = 0 THEN MESSAGE 5 'ROW 1
IF PORTB.5 = 0 THEN MESSAGE 6 'ROW 2
IF PORTB.6 = 0 THEN MESSAGE 7 'ROW 3
IF PORTB.7 = 0 THEN MESSAGE 8 'ROW 4
High PORTC.2

Low PORTC.6 'COLUMN3
Pause 1
IF PORTB.4 = 0 THEN MESSAGE 9 'ROW 1
IF PORTB.5 = 0 THEN MESSAGE 10 'ROW 2
IF PORTB.6 = 0 THEN MESSAGE 11 'ROW 3
IF PORTB.7 = 0 THEN MESSAGE 12 'ROW 4
High PORTC.6

Low PORTC.7 'COLUMN 4
Pause 1
IF PORTB.4 = 0 THEN MESSAGE 13 'ROW 1
IF PORTB.5 = 0 THEN MESSAGE 14 'ROW 2
IF PORTB.6 = 0 THEN MESSAGE 15 'ROW 3
IF PORTB.7 = 0 THEN MESSAGE 16 'ROW 4
High PORTC.7
GoTo TESTCELLS

markcadcam
- 22nd November 2006, 15:10
Hi Peterdeco1,

I appreciate the feedback but unfortunately I have made a circuit board for this design which is already installed in a piece of equipment. If I cannot get this to work I’ll give your idea a try.

Thanks,
Mark

mister_e
- 22nd November 2006, 17:51
Alternative...


include "C:\PBP_PROG\INCLUDE_ROUTINES\KeyPad.bas"

define OSC 20
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_SPBRG 129 ' 9600 Baud @ 0.16%
DEFINE HSER_CLROERR 1 ' Clear overflow automatically

DEFINE KEYPAD_ROW 4 ' 4 ROW keypad
DEFINE KEYPAD_ROW_PORT PORTB ' ROW port = PORTB
DEFINE KEYPAD_ROW_BIT 0 ' ROW0 = PORTB.4
DEFINE KEYPAD_COL 4 ' 4 COL keypad
DEFINE KEYPAD_COL_PORT PORTB ' COL port = PORTB
DEFINE KEYPAD_COL_BIT 4 ' COL0 = PORTB.0
DEFINE KEYPAD_DEBOUNCEMS 200 ' debounce delay = 200 mSec
DEFINE KEYPAD_AUTOREPEAT 1 ' use auto-repeat feature

INTCON2.7=0
kKey var byte

Start:
@ READKEYPAD _kKey
hserout ["Key=",dec kkey,13,10]
goto start

Just modify the include to suite your requirement :D
kEYpAD.BAS... AVAILABLE BELLOW
http://www.picbasic.co.uk/forum/showthread.php?t=3250

and IN YOUR serout LINE...



SEROUT serpin,N2400,[#key,#B0]'Send key value out PortA.1


AND now that some know you experiment a Write/Read/Modify behaviour... use your existing code but modify it like



getkeyu:' Wait for all keys up
LATB = 0 ' All output-pins low
TRISB = $f0 ' Bottom 4-pins out, top 4-pins in
@ nop
IF ((PORTB >> 4) != $f) THEN getkeyu'If keys down, loop
PAUSE 50 ' Debounce key-input

getkeyp:' Wait for keypress
FOR row = 0 TO 3 ' 4 rows in keypad
LATB = 0 ' All output-pins low
TRISB = (DCD row) ^ $ff ' Set one row pin to output
@ nop
col = PORTB >> 4 ' Read columns
IF col != $f THEN gotkey' If any keydown, exit
NEXT row
GOTO getkeyp ' No keys down, go look again


What happen now ?

markcadcam
- 22nd November 2006, 19:22
I'll give it a try.

Thanks,
Mark

Ioannis
- 23rd November 2006, 06:43
If you still have problem after Steve's suggestions, please check the circuits. Better send the circuit here to see how you connected the buttons to the PIC. I suspect noise from some lines.

Ioannis

mister_e
- 23rd November 2006, 07:39
FYI, using his code, i had similar problem as markcadam, so i decide to use my 'easy to use' INCLUDE with the same PIC and crystal... confirm that my hardware was good (EasyPIC4 + Keypad 4X4 adapter). Worked with internal pull-up AND external (of course).

Then i worked around his code. Use LATB intead of PORTB to write to the port for safety sake. On a whole port write, it doesn't really matter.. but when you write to few bit .. it may cause some problem. In this case leaving PORTB AS IS, will work anyways.

Writing to PORT before TRIS is also for safety sake even if some don't believe it ;) But if you leave it like this... it still working.. but sometimes you have some screwed values

BUT the real magic is in the @ nop. remove those lines and the readings are screwed up.. or intermittent. just by this famous PIC18Xxxxx feature called 'Read/Modify/write' behaviour.

18Fs are much noise sensitive.. so i would avoid to use internal weak-pull-ups... IMHO.. you know i hate those anyways ;)

mister_e
- 23rd November 2006, 07:59
mmm, just double/triple/quad check the whole thing...
it appear that the TRIS work better if before the PORT/LATB line ....DOH!

BUT if you want to use the 'Microchip says' approach (write to PORT before TRIS), replace @ nop by @ GOTO $+2

That way... it works ... a treat

M.F.Sorry!

Ioannis
- 23rd November 2006, 08:20
Hi Steve. Doesn't @ GOTO $+2 being equal to jump to next instruction? Also the same as NOP. So whats the difference?

Ioannis

mister_e
- 23rd November 2006, 08:23
ASM GOTO need 2 cycle to execute, NOP only 1 cycle

Ioannis
- 23rd November 2006, 08:29
Yeap. You are right. Its a typical delay then...

Ioannis

markcadcam
- 24th November 2006, 02:48
I believe I found the problem. This circuit was designed for a 4Mz crystal and I am running it at 20Mz. I added a 'PAUSE 1" after the line 'TRISB = (DCD Row) ^ ff' to slow it down and this seems to of fixed the problem.

Thanks for everbodys help,
Mark

mister_e
- 24th November 2006, 03:54
That's what @ GOTO $+2 did... but 2500 times faster

also try with shorter PAUSEUS. PAUSEUS 5 should also work...