Bascom and AVR, Keyboard
Most small controller applications use one or more buttons or switches for user input. When things
get a little more complicated, a small keyboard can be a good solution. These keyboards come in
3x4 or 4x4 variants, most often the keyswitches are arranged in a matrix:

The matrix is used because it minimises the number of connections from the keyboard to the
controller. A 4x4 keyboard has 16 keyswitches. You could wire all 16 switches to the controller,
but a more clever solution is to arrange the keys in a matrix and then wire the four columns and
rows to the controller.
With most keyboards, the 0 ... 9 keys are in the same place. They differ in the location and marking
of the other keys.
How to use such a keyboard? There are a number of methods. I use one eight-bit port of the controller.
The columns are wired to the upper four bits, the rows to the lower four bits. Now, a small difficulty:
once a key is pressed, an interrupt should be generated and the controller should read which key is
pressed. The best solution would be if the controller could generated an injterrupt on >any< change
in the state of the rows. A PIC controller can do this, but the small AT90S2313 only has two
interrupt pins. The solution is to add four diodes and a pull-up resistor to make an OR-gate wired to
Int0:
The 470 Ohm resistors in the row and column leads protect the controller in case there is a direct
connection through a keyswitch between a high output and a low output pin. This is a theoretical
possibility, you can do without them
The Int0 input pin has a 10k pull-up to Vcc. We make the upper four bits of PortB function as output
with a logic low. The lower four bits are made to funtion as input with a logic high. Now, if a key
is pressed, a connection is made between a column (output, logic low) and a row (input, logic high).
This row line will be pulled low. Also, the row input to the Diode-OR goes low, the OR output goes
low, and Int0 fires an interrupt.
In the interrupt routine we quickly read the state of the row lines to see on which row the pressed
key is. Then, the upper four bits of PortB are made input with logic level high, and the lower
four bits are made output with logic level low. Now, we read the state of the upper four bits to
determine on which column the pressed key is. We then wait a certain 'debounce' time. From the
state of the row and column lines read, the key pressed is determined. Lastly, the state of the
row and column bits of PortB is restored to the starting point.
Which key has been pressed is then determined from the state of the row and column bits:

Of course, the chosen arrangement of row and columnnumbers and keycodes is completely arbitrary. You
can choose an entirely different arrangement if that suits you better. (And actually, the arrangement I used
in the
<../i2c/i2c.html#keyboard>I2C keyboard example
is different)
An example of a keyboard decoding program:
keyboard-int.bas
$regfile = "2313def.dat"
$crystal = 4000000
$baud = 9600
Const Debouncetime = 150
Config Pind.6 = Output
Config Pind.2 = Input
Config Int0 = Falling
Dim Wtime As Byte
Dim Keycoderow As Byte
Dim Keycodecol As Byte
Dim Keycode As Byte
Dim Keychar As String * 1
On Int0 Button
'set upper nibble of portb to output, lower to input
Ddrb = &B11110000
Portb = &B00001111
Wtime = 255
Print "ready..."
Enable Interrupts
Enable Int0
Do
Set Portd.6
Waitms Wtime
Reset Portd.6
Waitms Wtime
Loop
Button:
Waitms Debouncetime
'read portb pins to determine which row is zero
Keycoderow = Pinb
'set portb upper nibble to input, lower to output
Ddrb = &B00001111
Portb = &B11110000
'give port time to settle
Waitms 1
'read portb pins to determine which col is zero
Keycodecol = Pinb
'set portb back to original state
Ddrb = &B11110000
Portb = &B00001111
'make keycode from portb pins read
Select Case Keycoderow
Case 7 : Keycode = 0
Case 11 : Keycode = 4
Case 13 : Keycode = 8
Case 14 : Keycode = 12
Case Else : Keycode = 99
End Select
'shift upper nibble to lower nibble
Shift Keycodecol , Right , 4
'make final keycode from portb pins read
Select Case Keycodecol
Case 7 : Keycode = Keycode + 0
Case 11 : Keycode = Keycode + 1
Case 13 : Keycode = Keycode + 2
Case 14 : Keycode = Keycode + 3
Case Else : Keycode = Keycode + 99
End Select
'illegal keycode from bounce effects
If Keycode > 15 Then Keycode = 16
Print Keycoderow ; " " ; Keycodecol ; " " ; Keycode
Keychar = Lookupstr(keycode , Keycodes)
Print Keychar
Gifr = 64
Return
End
Keycodes:
Data "1" , "2" , "3" , "A" , "4" , "5" , "6" , "B" ,
Data "7" , "8" , "9" , "C" , "R" , "0" , "E" , "D" , "?"
The mapping from keycode to key character is in the Keycodes Data block. If you have another keyboard
with different key assignement, the Data block must be updated.
The key character is sent to the PC through the RS232 interface as all of the PortB pins are assigned to
reading the keyboard and the Lcd had to be disconnected.
Note that Bascom has a Getkbd command that can be used to scan a 3x4 or 4x4 keyboard. However, I could not
get it to work properly inside an interrupt routine.
TOC