@mstanley
Looks like I got the functionality right, but the technical name wrong (getting use to this

)...
As I read the code, I assumed it would simply call my function based on key state change... essentially a software interrupt...
It does call your listener function when you get a key state change but that is not really an interrupt.
It all happens in the same context underneath the getKey() function so it is just a callback.
The AVR can't even do a real software interrupt as the AVR does not include the TRAP instruction.
(s/w can be used to create a hardware interrupt though)
There are no delays added to the actual keypad procedures, only to the LCD print processes.
These delay are essential in order to reduce the possibility of printing random characters where the user enters data so quickly that the LCD routines can't complete the write cycle before the next key is pressed...
What I really need is a method to delay the keypad until the LCD write cycle is complete, in most cases this delay should not be noticeable...
This does not make sense.
Some things are synchronous like all the software and some things are asynchronous
like the user pressing a button.
Since all the software is synchronous (no ISRs, everything runs serially all in the same context)
the keypad code will never interrupt or overlap the LCD code
and the LCD library code will never interrupt or overlap the keypad code.
When you call an LCD library function, it goes away and does not return until
the data has been sent to the display. - The E signal has been lowered
and the write operation to the LCD has completed.
At that point, the data lines hooked up to the LCD are no longer looked at by the LCD.
When you call the getKey() library function, it goes away, scans the keypad
if 10ms has gone by since the last scan. If it did a scan and detects a key state change,
it will call the listener function, before returning.
After getKey() returns, the row and column pins are no longer looked at.
Adding delays before printing to the LCD is merely adding delay/latency before the data is sent
to the LCD. It is also adding delay/latency to the keypad code because it is delaying
the next call to getkey().
The keypad library tries to allow the sharing of all the column and row pins
with other libraries.
This is not really possible without protection circuitry
as it can potentially create shorts when the users presses a button
because his presses are totally asynchronous to the software controlling the pins.
In reality, only the keypad column pins can be shared.
This is because a column pin
and row pin are shorted together by the keypad when a button is pressed.
But since the row pins are all inputs
it won't affect the outputs on the column pins when used by some
other library even if a button connected to that column is pressed
which shorts it to a row pin.
Your example sketch is sharing the row pins with the LCD.
As the Dr pointed out this is not good and will have problems.
As far as LCD timing goes here is some timing:
The stock LiquidCrystal library in 4bit mode takes 338uS to send a
single character to the display. Commands like CLEAR and HOME take 20ms.
It takes the same amount of time to send a character to the display as to
set the cursor position as both are single byte transfer to the display.
Your listener function keypadEvent() sets the LCD cursor and sends a character
every time a key is "released".
Setting the cursor position and sending a character will be under 1ms.
This is faster than the 10ms keypad poll interval
and is much faster than a human could ever press the buttons.
Fm's liquidCrystal library reduces that 338us to 98us.
While Fm's library does not reset the LCD data lines back to outputs,
if pins for the LCD data lines are the ones used for the keypad column pins,
they will remain outputs all the time and can be used by either library
when needed.
--- bill