Scanning Keyboard

Introduction

Often you need to read in some keys. There is a simple example to scan 12 keys. They keys are placed on every cross point of 4 rows and 3 columns.
Row0 is connected to ground, the other and the columns to the pins defined in the example.
The rows are outputs. If they activated they are driven low.
The columns are inputs. They are pulled high by its internal pull ups.
If a key was pressed and its row is activated (=low) then its column is on low level too.

In general all keys give many pulses during pressing or releasing. So you need a debouncing. This can be done by scanning 2 or more times with a delay between every scanning.
And only if these scans equal this key can be accept.

Program description

Look at the list file:

The columns are all pulled high by the internal pull ups. The rows are put to low, row0 first (permanent) and row3 last (by the "jbc" instructions line 29 .. 31).
If no key was pressed all columns still high and no jump (line 23, 25, 27) was done. So acc was 12 times incremented and be 1.
If a key was pressed the column was put low by the key which connect it with the low driven row. So the jump to ks2 was executed and the decrementing of acc was interrupted.
The key between row0 and col0 was checked at first and give 13 as result in the acc. The key between row3 and col2 was checked last and remain the acc = 2.
If 1 pressed key was found no other was checked.
The new value was stored and the previous was placed in acc by the "xch" instruction (line 33).
Then both compared and only if equal accepted (debouncing).

In most cases only the key pressing or releasing was needed.
So the value was compared with the older accepted. And only if the new different from the older the value was returned. Otherwise acc = 0 mark no change in key state.
E.g. if 1 key used to increment the hour of a timer you get only 1 increment of it by every pressing of this key.

In some cases an action want to be repeat if the key was pressed longer.
To do this, you can start a timer which gives out the last stored key number (=oldkey). And if the key release value (acc=1) was read, this timer can be stopped.

If you want detect 2 simultaneously pressed keys you must drive all 4 rows and only 1 row can be driven low at the time (use not the "jbc" instructions, shift simple the low level trough all rows, e.g.
mov a,p1
rl a
mov p1,a ), store the number of the 1.key and continue searching to get the 2.key.

It's also easy to expand  the count of rows and columns to scan more keys.