I made myself a small PCB (measuring about 6cm by 5cm). This is what is supposed to happen:
1. Upon power-up, the LED goes red to indicate that the unit is ready for input.
2. I then press any key down (where the contacts in the button meet), then the red led goes off.
3. The correct value is found from a memory location that is determined based on the row and column the key press is detected.
4. The program waits until the remote unit bit-bangs 4 bits out so that it knows the button that's pressed.
5. The green light goes off and no lights are on until no key is pressed in the current row for 30+ms.
6. The red light goes back on and the entire process repeats.
The problem is sometimes I can't get past step 2. It seems that with my current setup, only keys are detected from one row only. Adding a delay of 128+uS before changing the row does help somewhat (it allows me to detect 9 keys instead of 3), but I can't seem to detect the last two keys in the last row of keys no matter what I do.
I made sure all my hardware is connected correctly, and I made sure all input ports stay as inputs so that nothing blows up in my face.
This is the datasheet to my keypad: https://futurlec.com/Keypad3x4.shtml
What am I doing wrong?
1. Upon power-up, the LED goes red to indicate that the unit is ready for input.
2. I then press any key down (where the contacts in the button meet), then the red led goes off.
3. The correct value is found from a memory location that is determined based on the row and column the key press is detected.
4. The program waits until the remote unit bit-bangs 4 bits out so that it knows the button that's pressed.
5. The green light goes off and no lights are on until no key is pressed in the current row for 30+ms.
6. The red light goes back on and the entire process repeats.
The problem is sometimes I can't get past step 2. It seems that with my current setup, only keys are detected from one row only. Adding a delay of 128+uS before changing the row does help somewhat (it allows me to detect 9 keys instead of 3), but I can't seem to detect the last two keys in the last row of keys no matter what I do.
I made sure all my hardware is connected correctly, and I made sure all input ports stay as inputs so that nothing blows up in my face.
This is the datasheet to my keypad: https://futurlec.com/Keypad3x4.shtml
What am I doing wrong?
Code:
;Keypad uC version
;Microcontroller Uses 22.1184Mhz crystal
;LED indicators. low value = LED on
RED equ P3.4
GREEN equ P3.5
;Serial Data connection
DAT equ P3.0 ;Data
CLKO equ P3.2 ;Clock out to parent uC
CLKI equ P3.1 ;Clock ack from parent uC
org 0h
mov IE,#0h ;Clear automatic interrupts so program doesn't act funny
mov P3,#0FFh ;Set IO lines to high-impedance
mov P1,#0FFh
;49h to 7Ch = number matrix space
;These values are returned for corresponding number. Will explain later...
;Note: Value 0Ah = star and Value 0Bh = pound
mov 01001100b,#06h
mov 01001010b,#04h
mov 01001001b,#05h
mov 01011100b,#09h
mov 01011010b,#07h
mov 01011001b,#08h
mov 01101100b,#0Bh
mov 01101010b,#0Ah
mov 01101001b,#00h
mov 01111100b,#03h
mov 01111010b,#01h
mov 01111001b,#02h
premain:
clr RED ;Turn red light on to indicate we're ready for keypad input
main:
inc R6 ;Select next row
orl 6h,#0FCh ;Make row range 0 - 3
mov P1,R6 ;P1.2 to P1.7 = logic 1 to accept input. P1.0 and P1.1=row #
nop ;waste machine cycles to let hardware catch up
nop
nop
nop
nop
mov A,P1 ;Scan all 3 columns at once
anl A,#070h ;We only want P1.6, P1.5 and P1.4 bits since columns connect there
cjne A,#070h,detk ;See if any of the above bits are low
sjmp main ;here, they're all high so start over continuing with next row.
detk:
;Here a key is detected (but for some keys this is never reached. why?)
;So based on informarion, we make a memory address that contains the value we
;pressed.
setb RED ;Turn off red light
mov B,R6 ;Copy row info to B
anl B,#03h ;We only want LSB and bit next to it. It contains row number.
orl A,B ;merge row number with our pressed key config value
;...Value here equals 0ccc00rr where c equals column and r = row
swap A ;Swap value
anl A,#01111111b ;Make MSB=0
orl A,#01001000b ;set the 7th and 4th bit to 1
;... Value here equals 01rr1ccc which is OK.
mov R0,A ;Save value as address to data
mov A,@R0 ;Load correct data to accumulator
clr GREEN ;Turn green light on to tell master we have data
;... At this point We stall until data is shifted out
rrc A ;Extract one bit into carry
mov DAT,C ;Set it as data
clr CLKO ;Set clock to let master know we have data
jb CLKI,$ ;Wait until master acknowledges this
rrc A ;Do same but use raised clock lines here
mov DAT,C
setb CLKO
jnb CLKI,$
rrc A ;Repeat for remaining two bits
mov DAT,C
clr CLKO
jb CLKI,$
rrc A
mov DAT,C
setb CLKO
jnb CLKI,$
setb GREEN ;Turn off green light as we are done with data
debounce:
mov R4,#0h ;Prepare for 30ms debounce
mov R5,#0h
db2:
mov A,P1 ;Get line value
anl A,#070h ;We only want key values
cjne A,#070h,debounce ;If any key in row is down within 30ms then extend time by 30ms
djnz R4,db2 ;Here keys are not pressed so count down one register
djnz R5,db2 ;and the other register too
sjmp premain ;here, the keys have been let go long enough so press is valid. Start all over.