Inerfacing 4x4 keypad to Atom Pro

As a contribution to the DIY remote control, I am playing with a 4x4 keypad by ACT (purchased awhile ago from Jamco). I have the 4 pins of the Columns(or Rows) connected to P0-p3 on the ABB and the other 4 pins of the Rows(or Columns) plugged into P4-p7 on the ABB. Should be a piece of cake. I thought at first I could simply get away with code that looked like:

DirA = 0xf    ' Sets the 4 pins P0-p3 as output pins
DirB = 0x0    ' Sets the 4 pins p4-p7 as input pins

...


CheckKeypad:
	fKeypadChanged = 0						' assume nothing changed.
	
_CKPAgain:	
	wKeypadButtonsLast = wKeypadButtons		' save the old value

	OutA = 0x1
	wKeypadButtons.nib0 = inB
	OutA = 0x2
	wKeypadButtons.nib1 = inB
	OutA = 0x4
	wKeypadButtons.nib2 = inB
	OutA = 0x8
	wKeypadButtons.nib3 = inB
	if wKeypadButtons <> wkeypadButtonsLast then
		fKeypadChanged = 1			' ok something changed

		' quick and dirty try to handle debounce by pausing 1 and recalcing again until
		' we get the same value.
		pause 10
		goto _CKPAgain
	endif
	
	' Ok we are here with a stable keypad state.  If it changed we need to calculate a new PWM value
	' to return.
	if fKeypadChanged then
		' We will generate a pulsewidth between 1100 and 1900 that will translate to zero or one button
		' pressed.  Could easily be sped up with assembly...
		if wKeypadButtons = 0 then
			wKeypadPWM = 1100
		else
			wKeypadPWM = 1150
			wKeypadMask = 0x1
			
			while ((wKeypadButtons & wKeypadMask) = 0) 
				wKeypadPWM = wKeypadPWM + 50
				wKeypadMask = wKeypadMask << 1		' shift the mask down
			wend
		endif
	
	endif
	
	return

So far this approach has not worked. I did find one problem on my side. I am using an ABB :blush: and still had the jumpers in for the PS2, buttons, leds… Removed them. Still does not give me the results I am looking for.

The code is trying to set one bit high in P0-P3 and then check the 4 bits in P4-P7, where hopefully only 1 button will be high iff a button is pressed. So far that has not worked out that way. I was also wondering about P7 on the ABB as there appears to be more circuitry there including a resistor and transistor…

I have tried setting the IO registers directly (PMR5, PCR5 and PDR5 and that has not worked yet. Also I set individual bits of PCR5 to be the correct bits for Input or Output, but when I check PCR5 it always shows a value of 0xff, but that may be normal as it shows all of the pins as W and not R/W… Will play around more later, but now the heating people are here… May try moving wires to other pins…

Kurt

I think I will reverse my logic here. That is I am not sure what the state of the input IO pins are when they are floating. So instead I will set the Pull-up resister bits for these (PUCR5) so these values should be high when nothing is connected and then as I pull the bits I will set one IO line low in the P0-p3 to pull the value down…

Hello Kurte,

The extra circuitry on pin 7 is an inverter for a PS2 controller port for a BS2. It’s shiftin didn’t support the format required by the BS2 so we added an inverter. We ditched it on the Bot Board II btw. Feel free to cut traces on the Mini ABB. I will replace it for you. Thanks for your help!

Kurte you will more than likely need / want a stronger pull-up or pull-down on the input (row) pins, and you will need to add some time between asserting each column (assuming you are driving columns and reading rows) and reading the row.

Also a simple trick to figure out which input changed is to XOR the new value with the old.

First, the PCR registers or WRITE only. You can not read them back. They will always read 0xFF. I had to use a shadow register. Everytime I write them I update the shadow register. You will have to do the same if you want to use a read-modify-write sequence. Note that if you directly access the PCR registers my shadow registers are not updated so you could very well cause other functions to fail. You should use the input and output commands instead. Using the DIR variables should also udpate the internal shadow register IIRC.

Have you check that your outputs are happening as expected? If so that elliminates half the possible problems.

When no buttons are pressed are all your inputs low?

What are you getting for each of the input nibs when you press each button on the keypad?

Note that I’ve never used the internal pullups so I don’t know how they may react in this case. You may be better off using external pullups.

It is working better with the assuming the pullups… At least for P4-P6. P7 is mostly stuck. I will try modifying the board later. Got to get back to working on construction…

Current code:

[code]'First a simply program to check the state of the 16 buttons on the keypad.
’ For now the keypad is in the default positions that were proposed for the
’ DIY controller… Pins: 0-3 Rows pins 4-7 do Columns. Will try
’ the Basic variables to read or write 4 IO ports at a time…
’ Variables
fKeypadChanged var bit

wKeypadButtons var word
wKeypadPWM var word

bPDR51 var byte
bPDR52 var byte
bPDR53 var byte
bPDR54 var byte
bPCR5 var byte

'[Init]
wKeypadPWM = 0xffff ’ make sure we will generate a new keypad value…
’ Try going directly to the IO registers
PMR5 = 0x0 ’ all 8 IO pins are standard IO

output p0
output p1
output p2
output p3
input p4
input p5
input p6
input p7
		' The low 4 bits are output the high 4 bits are input
sound 9,[50\3960] 


gosub CheckKeypad
serout s_out, i9600, [hex wKeypadButtons, " ", dec wKeypadPWM, 13]
'serout s_out, i9600, [hex bPDR51, " ", hex bPDR52, " ",hex bPDR53, " ",hex bPDR54, " ",hex PCR5, 13]

Main:
gosub CheckKeypad
if fKeypadChanged then
serout s_out, i9600, [hex wKeypadButtons, " ", dec wKeypadPWM, 13]
'serout s_out, i9600, [hex bPDR51, " ", hex bPDR52, " ",hex bPDR53, " ",hex bPDR54, " ",hex PCR5, 13]
endif
goto main

'=====================================================================
’ function: CheckKeypad
’ This function is currently hard coded to pins 0-7 for the 8 pins. four
’ By BAP manual: DIRA, INA, OUTA (pins 0-3) DIRB, INB, OUTB(4-7)
’ are used as a row and 4 as columns. will parameterize this later
’ private variables used in the checkkeypad.
wKeypadButtonsLast var word
wKeypadMask var word

CheckKeypad:
fKeypadChanged = 0 ’ assume nothing changed.
DirA = 0xf ’ Sets the 4 pins P0-p3 as output pins
DirB = 0x0 ’ Sets the 4 pins p4-p7 as input pins
PUCR5.nib1 = %1111
_CKPAgain:
wKeypadButtonsLast = wKeypadButtons ’ save the old value

OutA = %1110
wKeypadButtons.nib0 = inB
OutA = %1101
wKeypadButtons.nib1 = inB
OutA = %1011
wKeypadButtons.nib2 = inB
OutA = %0111
wKeypadButtons.nib3 = inB
wKeypadButtons = ~wKeypadButtons
if wKeypadButtons <> wkeypadButtonsLast then
fKeypadChanged = 1 ’ ok something changed

  ' quick and dirty try to handle debounce by pausing 1 and recalcing again until 
  ' we get the same value. 
  pause 10 
  goto _CKPAgain 

endif

’ Ok we are here with a stable keypad state. If it changed we need to calculate a new PWM value
’ to return.
if fKeypadChanged then
’ We will generate a pulsewidth between 1100 and 1900 that will translate to zero or one button
’ pressed. Could easily be sped up with assembly…
if wKeypadButtons = 0 then
wKeypadPWM = 1100
else
wKeypadPWM = 1150
wKeypadMask = 0x1

     while ((wKeypadButtons & wKeypadMask) = 0) 
        wKeypadPWM = wKeypadPWM + 50 
        wKeypadMask = wKeypadMask << 1      ' shift the mask down 
     wend 
  endif 

endif

return

[/code]