I made myself a small PCB (measuring about 6cm by 5cm). This is what is supposed to happen:
- Upon power-up, the LED goes red to indicate that the unit is ready for input.
- I then press any key down (where the contacts in the button meet), then the red led goes off.
- The correct value is found from a memory location that is determined based on the row and column the key press is detected.
- The program waits until the remote unit bit-bangs 4 bits out so that it knows the button that's pressed.
- The green light goes off and no lights are on until no key is pressed in the current row for 30+ms.
- 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:
Here's the 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.
Here's the circuit:
What am I doing wrong?