Keypad interface?

Started by arhodes19044 December 6, 2005
I want to interface to a 4x3 matrix-type keypad with NO additional
support.

I was successful in this when reading a single button press.

I have strobe the 3 rows individually, the non-strobed row's pin is
set to output high, and the strobed row's pin is set to output low.

I then read the 4 column pins (which are set to input-pullup) and
then look for the low pin. I left shift that nibble and read strobe
the next row.

This will not work and will make smoke if 2 buttons in the same
column are pressed simultaneously.

What alternative will work properly?

I tried making the non-strobed output pins set to input-tristate (so
they will not make a short), and the strobed pin is still output-low
(the input pins are also still input-pullup) and this seems to give
screwy results for some reason.

I think I will try making the non-strobed pins input-pullup, and
otherwise keep everything else the same.

Any suggestions for reading multiple keypresses with NO external
support stuff like current limiting resistors and pullup/down
resistors?

-Tony


--- In basicx@basi..., "arhodes19044" <spamiam@c...> wrote:
> I want to interface to a 4x3 matrix-type keypad with NO additional
> support.

Since a matrix keypad will short I/O pins together with multiple
keys down you either have to be able to endure that or add external
parts (open collector/drain inverters, diodes, resistors, etc.).

The only way to alleviate the problem is to have only one row being
driven low at a time with the I/O pins of other row lines set to
input/pullup.

The page below has an application note on interfacing a matrix
keypad. It uses external components to get the I/O pin count down
to just 3. Without external components, you'd need 7 for a 4x3
keypad.

http://www.zbasic.net/appNotes

Don


--- In basicx@basi..., "Don Kinzer" <dkinzer@e...> wrote:
>
> The only way to alleviate the problem is to have only one row being
> driven low at a time with the I/O pins of other row lines set to
> input/pullup.

Correct. I got the keypad working properly, including accurate reading of
multiple simultaneous keys. I did it with no support hardware (i.e.
resistors for current limiting and pullup/pulldown. Each key has a
unique bit in the final 12 bit numerical result.

I strobe each of the 3 rows separately with a low output. The other
rows are driven by pins set to "input-pullup". I then read the 4
column pins. Invert the bits, shift left, and repeat for the next
row. Ending up with a 12 bit number. Each key is separately
represented in that number with a high bit, if pressed. No shorting
of high-output high and low pins happens.

I have not tested the limit of the number of potential simultaneous
keys, but 3 is no problem. I only use 2 for a couple of operations. This does use 7 pins, which is significant on the BX platform. Your
reference to a multiplexing technique is well received.

-Tony
-Tony


--- In basicx@basi..., "arhodes19044" <spamiam@c...> wrote:
> I have not tested the limit of the number of potential simultaneous
> keys, but 3 is no problem.

I believe that 3 is a problem in one particular case. Consider four
keys that reside at the corners of any rectangle in the matrix. If
you press any three of them, the fourth will appear to be pressed
whether it is or not. This is known as a "phantom key" and is caused
by there being a conductive path from a row line, through the three
closed keyswitches to the column line of the key that is not pressed,
thus making it appear that a key is closed at that row/column
intersection. The common way of preventing this is to use diodes in
series with the keys to prevent the circuitous connection.

> This does use 7 pins, which is significant on the BX platform. Your
> reference to a multiplexing technique is well received.

It occurred to me that you might be able to connect a 4x4 keypad using
only 2 I/O lines and only one external component - a PCF8574 I/O
expander. If you already have other I2C devices connected, the
incremental I/O line usage would be zero since you could use the same
SDA/SCL lines.

Although I haven't prototyped this circuit, I believe that it would
work to connect the row/column lines directly to the expander's I/O
lines with no resistors. The expander's output stage is designed to
be tolerant of being shorted to ground when in the logic 1 state. In
fact, the way that you prepare a pin for input is to write a 1 to that
bit. The PCF8574 and PCF8574A are about $2 at DigiKey. The
difference between the two parts is the I2C base address.

Don
http://www.zbasic.net


--- In basicx@basi..., "Don Kinzer" <dkinzer@e...> wrote:
> ... you might be able to connect a 4x4 keypad using only 2 I/O
> lines and only one external component - a PCF8574 I/O expander.

Yes, it does work. Very nicely, in fact.

The other cool thing about this method is that you can get the
expander to generate an interrupt signal when a key is pressed. To do
this, you set your row lines to zeros and column lines to ones (or
vice versa) when you're not actively scanning the keypad. The
expander will detect a pin change when a key is pressed.

Don
http://www.zbasic.net



--- In basicx@basi..., "Don Kinzer" <dkinzer@e...> wrote:

>
> The other cool thing about this method is that you can get the
> expander to generate an interrupt signal when a key is pressed.
To do

That whole thing is cool. I _am_ using I2C because I am using my
custom RTC clock/FRAM daughter board, which is working perfectly,
BTW. I am running low on interrupts, though. I will soon have to
multiplex them. In my specific case, I only poll the keypad when I
need the info, so I do not need any keypad interrupt.

The "slow" speed of a 400KHz I2C bus is no problem for keypads!

-Tony

P.S. I will have trouble with non-unique results of 3-key combos,
but I am never going to use such, so if a user were to try it, too
bad for them.



>
> The "slow" speed of a 400KHz I2C bus is no problem for keypads!
>
Actually, PCF8574s are capable of "only" 100KHz. However, the Version 2
of I2C bus specification allows an increase in the bit rate up to 3.4
Mbit/s

http://www.esacademy.com/faq/i2c/general/i2cspecver.htm

Yuri.



--- In basicx@basi..., "ybernikov" <ybernikov@y...> wrote:
the Version 2
> of I2C bus specification allows an increase in the bit rate up to
3.4 Mbit/s That IS rather speedy. Of course that does not help us here much
because the bit-banged I2C interface of the BX-24 is rather slow. I
am Not sure what its speed is, but I'd bet it is rather lower than
100KHz.

Even the full hardware I2C on an ATMega128 running at 16MHz can only
get to 409KHz or so. I have some FRAM that is capable of 1MHz, but I
am only able to run it at 40% of its maximum under the best
circumstances.

-Tony



> That IS rather speedy. Of course that does not help us here much
> because the bit-banged I2C interface of the BX-24 is rather slow.
I
> am Not sure what its speed is, but I'd bet it is rather lower than
> 100KHz.
>

Let's do some calculations:

Netmedia claims that the speed of BX24 is 83,000 Basic instructions
per second. In order to send one byte via I2C, a sequence of at least
20 instructions has to be executed. Let's assume for the simplicity
sake, that all instructions have the same execution time. This gives
us VERY ROUGHLY:

83000 / 20 = 4150 bytes/sec

or

4150 * 8 / 1000 = 33.2 kbit/s,

but I believe the real speed is much lover.

I did not try the I2C capabilities of ZBasic, but it must be much
faster.

-Yuri


--- In basicx@basi..., "ybernikov" <ybernikov@y...> wrote:
> Netmedia claims that the speed of BX24 is 83,000 Basic
> instructions per second.

I have confirmed the accuracy of this claim. However, it should be
noted that this is a "best case" speed that is obtainable only with
a few specific instructions (e.g. incrementing an Integer variable).

A possibly more representative speed measurement can be obtained by
using the following program:

Sub Main()
Register.DDRC = &H01
Do
Register.PortC = Register.PortC Xor &H01
Loop
End Sub

This program generates a square wave on pin 12 having a period
equal to twice the loop execution time. With an oscilloscope or
logic analyzer you can measure the period and calculate the
execution time for one pass through the loop. For the BX-24, the
loop execution time is a little over 90uS; for the BX-24P it is a
little over 66uS.

It should be noted that more complicated instructions, like those
involving expressions with multiple operators or array indexing, are
going to take much longer. A single BasicX instruction can produce
dozens (or in some extreme cases, hundreds) of pcode instructions
for the processor to execute.

By way of comparison, the ZX-24 has a maximum execution speed of
172,000 instructions per second under the same conditions as the BX-
24's top speed. Its loop execution time for the program above is
about 32uS. More comparative data can be found at the site below.

Don
http://www.zbasic.net