Reading an AT-PC Keyboard
The following program was submitted by Dusko Djuricin.
It shows how to read a keyboard from an AT compatible PC.
Download source code in Bas file
'
=========================================================================================
'
' Program: ATPCKBD.BAS
' Author: Dusko Djuricin
' E-mail: djdusko@eunet.yu
'
' This program demonstrates how to interface AT PC
keyboard to 8031 microcontrollers family.
' Program was originally written and tested for ATMEL
89C2051. For keyboard interfacing it
' uses only two I/O lines with two pull up resistors. At
the output, through serial channel,
' it sends ASCII code of pressed key. Other used I/O lines
are not necessary.
' Complete description of PC keyboard operation, could be
found at the following address:
'
' http://www.geocities.com/SiliconValley/Bay/8302/keybrd.htm#1
'
'
=========================================================================================
Dim B1 As Byte , B2 As Byte , N As Byte , Status As Byte , Key As Byte
Dim Caps As Bit , Caps_lock As Bit , Ctrl As Bit , Alt As Bit , Tmp As Bit
Dim Temp As String * 1
Declare Sub Tx_byte(b1 As Byte)
Declare Sub Rx_byte
Declare Sub Kbd_status
Kbd_data Alias P1.1 ' connected with 4K7 pull up resistor
Kbd_clk Alias P1.0 ' connected with 4K7 pull up resistor
Buzzer Alias P3.7 ' for details see BASCOM51 documentation
Res_sw Alias P3.5 ' optional output (see code)
Dim Frequency As Const 2048
Dim Duration As Const 50
Dim L_shift As Const &H12
Dim R_shift As Const &H59
Dim Ctrl_key As Const &H14
Dim Alt_key As Const &H11
Dim Caps_key As Const &H58
Dim Scroll_key As Const &H7E
'---------------------------[Beginning of
Program]-------------------------------
Reset Kbd_clk ' disable the Keyboard
Waitms 100
Do
Tx_byte &HFF ' reset the Keyboard and wait
Rx_byte ' till the Keyboard answer with
If B1 = &HFA Then Exit Do ' acknowledge byte
If B1 = &HAA Then Exit Do ' or Power On Self Test OK code
Loop
Print
Print "*** AT PC Keyboard Interface ***"
Print " author: Dusko
Djuricin"
Print " E-mail:
djdusko@eunet.yu"
Print "********************************"
Print
' KBD LED: Status.0 - Scroll Lock, Status.1 - Num Lock,
Status.2 - Caps Lock
Status = 2 ' initially Num Lock On
Kbd_status
Do
' KEY variable will hold ASCII value of pressed key
Key = 0 ' initial value
Rx_byte ' read scan code from PC keyboard into B1
Select Case B1
Case Ctrl_key:
Set Ctrl ' mark that CTRL key is pressed
B1 = 0
Case Alt_key:
Set Alt ' same as above but for ALT key ...
B1 = 0
Case L_shift:
Set Caps ' same as above but for Left SHIFT key ...
B1 = 0
Case R_shift:
Set Caps ' same as above but for Right SHIFT key ...
B1 = 0
Case &HE0: ' extended codes are not handled!
B1 = 0
Case &HF0: ' BREAK CODE is detected (key depressed)
Rx_byte ' read again to see which key is depressed
If B1 = L_shift Then ' and keep tracking flags...
Reset Caps
Elseif B1 = R_shift Then
Reset Caps
End If
If B1 = Ctrl_key Then
Reset Ctrl
Elseif B1 = Alt_key Then
Reset Alt
End If
B1 = 0
Case Caps_key: ' in a case of CAPS LOCK key
Caps_lock = Caps_lock Xor 1 ' there must be
calculated status of it's LED
Status = Status Xor 4
Kbd_status ' and then we must send it to keyboard
B1 = 0
Case Scroll_key: ' I use combination of Ctrl + Alt + ScrLock
Tmp = Ctrl And Alt ' keys to generate reset signal...
If Tmp = 1 Then
Reset Res_sw ' ...for my host controller
Status = Status Xor 1 ' (Scroll Lock LED will lit and buzzer beeps)
Kbd_status
Sound Buzzer , Duration , 512
Waitms 100
Sound Buzzer , Duration , 512
Waitms 100
Sound Buzzer , Duration , 512
Waitms 100
Set Res_sw
Status = Status Xor 1 ' turn off Scroll Lock LED
Kbd_status
End If
B1 = 0
Case Else: ' handling of "printable" characters
If B1 > 131 Then ' this program handles only lower part
B1 = 0 ' of ASCII code table (with exception of
End If ' function keys - see lookup table)
If Caps = 1 Then
Key = Lookup(b1 , With_shift) ' one table is for SHIFT + key combination
Else
Key = Lookup(b1 , No_shift) ' and another is for key WITHOUT SHIFT
End If
If Caps_lock = 1 Then
If Caps = 0 Then ' if CAPS LOCK was ON and there is no
Temp = Chr(key) ' SHIFT + key combination, then convert
Temp = Ucase(temp) ' pressed key into upper case letter
Key = Asc(temp)
End If
End If
End Select
If B1 <> 0 Then
Sound Buzzer , Duration , Frequency ' beep
Print Chr(key); ' and print pressed key
End If
Waitms 10 ' dummy delay ...
Loop
'-----------------------[Receive Byte from
Keyboard]----------------------------
Sub Rx_byte
Set Kbd_clk ' enable Keyboard
mov {n},#0
jb Kbd_clk,*+0 ' wait CLK to become zero
' START bit
jnb Kbd_data,L_cont ' if START bit is zero continue
sjmp .L_error ' if not exit via error label
' DATA bits
!L_cont:
Incr N ' this is counter of received bits
acall zero2one
mov a,{b1} ' prepare buffer
mov c,Kbd_data ' read DATA bit
rrc a ' read it into the buffer
mov {b1},a ' store buffer value
mov a,{n}
cjne a,#8,L_cont ' if it isn't last bit repeat
' PARITY bit
acall zero2one
mov a,{b2} ' prepare buffer
mov c,Kbd_data ' read ODD PARITY bit
rrc a ' store it into the buffer
' STOP bit
acall zero2one
mov c,Kbd_data ' read STOP bit
rrc a ' store it into the buffer
rrc a ' now align bits to right...
rrc a
rrc a
rrc a
rrc a
rrc a
anl a,#3 ' extract valuable bits and
mov {b2},a ' store to buffer
' check STOP bit
anl a,#2
jz .L_error
' PARITY checking
mov a,{b1}
mov c,psw.0 ' this is EVEN PARITY
rlc a
anl a,#1
xch a,{b2}
anl a,#1
xrl a,{b2}
jz .L_error
sjmp .L_end
L_error: ' exit in case of an error
Waitms 1 ' wait end of transmission
mov a,#0
mov {b1},a
L_end:
Reset Kbd_clk ' stop the Keyboard
End Sub
'------------------------[Transmit Byte to
Keyboard]----------------------------
Sub Tx_byte(b1 As Byte)
B2 = 8
Reset Kbd_clk ' break the Keyboard
Delay ' (safety reasons)
Delay
Delay
Delay
Delay
Delay
Reset Kbd_data ' request to send
Set Kbd_clk ' enable the Keyboard
' START BIT
acall zero2one
' DATA BITS
mov a,{b1}
!L_tx_data:
rrc a
mov Kbd_data,c
acall zero2one
djnz {b2},L_tx_data
' PARITY BIT
mov a,{b1} ' calculate parity bit
mov c,psw.0 ' this is Even parity
cpl c ' and Keyboard needs Odd parity
mov Kbd_data,c ' send parity bit
acall zero2one
' STOP BIT
Set Kbd_data ' send stop bit
acall zero2one
' KBD ACK BIT
acall zero2one
Reset Kbd_clk ' stop the keyboard
End Sub
'------------------[ASM Subroutine wait for falling
edge]-----------------------
!zero2one:
jnb Kbd_clk,*+0 ' wait till CLK
rise
jb Kbd_clk,*+0 ' now wait till CLK fall down
ret
'------------[Subroutine for sending LED status to the
Keyboard]----------------
Sub Kbd_status:
Tx_byte &HED
Rx_byte
Tx_byte Status
Rx_byte
End Sub
'---------------------[Scan Code to ASCII conversion
table]---------------------
' Here are two lookup tables, one for handling ordinary
keys and other for
' handling combination of SHIFT + key. I gave (under block
remark) same tables
' written as strings, so matching with ASCII codes could
be easier.
'
' Note that function keys (F1 to F12) are coded as one
byte. F1 is coded as 129,
' F2 gives 130, F3 gives 131 and so on. This was OK for my
application and it is
' because of simplicity.
'
' Gray keys are not handled (INS, DEL, HOME, ARROWS etc)!
These keys returns ASCII
' value of appropriate key on numeric keypad (HOME will
give 7, END gives 1, etc).
'
' Pressing of Num Lock key have no effects. Num Lock LED
is always ON and serves
' as indicator that controller is turned on (if the
keyboard is connected).
'
' Keyboard mapping is for ordinary 101 keys keyboard
(standard US layout).
'
No_shift:
'(
Data ""
Data "F9" , "" , "F5" ,
"F3" , "F1" , "F2" , "F12" ,
"" , "F10" , "F8"
Data "F6" , "F4" , "TAB" ,
"`" , "" , "" , "LAlt" ,
"LSh" , "" , "LCtr" , "q"
Data "1" , "" , "" ,
"" , "z" , "s" , "a" , "w" ,
"2" , ""
Data "" , "c" , "x" ,
"d" , "e" , "4" , "3" , "" ,
"" , " "
Data "v" , "f" , "t" ,
"r" , "5" , "" , "" , "n" ,
"b" , "h"
Data "g" , "y" , "6" ,
"" , "" , "" , "m" , "j" ,
"u" , "7"
Data "8" , "" , "" ,
"," , "k" , "i" , "o" , "0" ,
"9" , ""
Data "" , "." , "/" ,
"l" , ";" , "p" , "-" , "" ,
"" , ""
Data "'" , "" , "[" ,
"=" , "" , "" , "Caps" ,
"RSht" , "Enter" , "]"
Data "" , "" , "" ,
"" , "" , "" , "" , "" ,
"" , ""
Data "BkSp" , "" , "" ,
"1" , "" , "4" , "7" , "" ,
"" , ""
Data "0" , "." , "2" ,
"5" , "6" , "8" , "ESC" ,
"NumLck" , "F11" , "+"
Data "3" , "-" , "*" ,
"9" , "ScrLck" , "" , "" , ""
, "" , "F7"
')
Data 0
Data 137 , 0 , 133 , 131 , 129 , 130 , 140 , 0 , 138 , 136
Data 134 , 132 , 9 , 96 , 0 , 0 , 0 , 0 , 0 , 0 , 113
Data 49 , 0 , 0 , 0 , 122 , 115 , 97 , 119 , 50 , 0
Data 0 , 99 , 120 , 100 , 101 , 52 , 51 , 0 , 0 , 32
Data 118 , 102 , 116 , 114 , 53 , 0 , 0 , 110 , 98 , 104
Data 103 , 121 , 54 , 0 , 0 , 0 , 109 , 106 , 117 , 55
Data 56 , 0 , 0 , 44 , 107 , 105 , 111 , 48 , 57 , 0
Data 0 , 46 , 47 , 108 , 59 , 112 , 45 , 0 , 0 , 0
Data 39 , 0 , 91 , 61 , 0 , 0 , 0 , 0 , 13 , 93
Data 0 , 92 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
Data 8 , 0 , 0 , 49 , 0 , 52 , 55 , 0 , 0 , 0
Data 48 , 46 , 50 , 53 , 54 , 56 , 27 , 0 , 139 , 43
Data 51 , 45 , 42 , 57 , 0 , 0 , 0 , 0 , 0 , 135
With_shift:
'(
Data ""
Data "F9" , "" , "F5" ,
"F3" , "F1" , "F2" , "F12" ,
"" , "F10" , "F8"
Data "F6" , "F4" , "TAB" ,
"~" , "" , "" , "LAlt" ,
"LSh" , "" , "LCtr" , "Q"
Data "!" , "" , "" ,
"" , "Z" , "S" , "A" , "W" ,
"@" , ""
Data "" , "C" , "X" ,
"D" , "E" , "$" , "#" , "" ,
"" , " "
Data "V" , "F" , "T" ,
"R" , "%" , "" , "" , "N" ,
"B" , "H"
Data "G" , "Y" , "^" ,
"" , "" , "" , "M" , "J" ,
"U" , "&"
Data "*" , "" , "" ,
"<" , "K" , "I" , "O" ,
")" , "(" , ""
Data "" , ">" , "?" ,
"L" , ":" , "P" , "_" , "" ,
"" , ""
Data 34 , 0 , "" , "{" , "+"
, "" , "" , "Caps" , "RSht" ,
"Enter" , "}"
Data "" , "|" , "" ,
"" , "" , "" , "" , "" ,
"" , ""
Data "BkSp" , "" , "" ,
"1" , "" , "4" , "7" , "" ,
"" , ""
Data "0" , "." , "2" ,
"5" , "6" , "8" , "ESC" ,
"NumLck" , "F11" , "+"
Data "3" , "-" , "*" ,
"9" , "ScrLck" , "" , "" , ""
, "" , "F7"
')
Data 0
Data 137 , 0 , 133 , 131 , 129 , 130 , 140 , 0 , 138 , 136
Data 134 , 132 , 9 , 126 , 0 , 0 , 0 , 0 , 0 , 0 , 81
Data 33 , 0 , 0 , 0 , 90 , 83 , 65 , 87 , 64 , 0
Data 0 , 67 , 88 , 68 , 69 , 36 , 35 , 0 , 0 , 32
Data 86 , 70 , 84 , 82 , 37 , 0 , 0 , 78 , 66 , 72
Data 71 , 89 , 94 , 0 , 0 , 0 , 77 , 74 , 85 , 38
Data 42 , 0 , 0 , 60 , 75 , 73 , 79 , 41 , 40 , 0
Data 0 , 62 , 63 , 76 , 58 , 80 , 95 , 0 , 0 , 0
Data 34 , 0 , 123 , 43 , 0 , 0 , 0 , 0 , 13 , 125
Data 0 , 124 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
Data 8 , 0 , 0 , 49 , 0 , 52 , 55 , 0 , 0 , 0
Data 48 , 46 , 50 , 53 , 54 , 56 , 27 , 0 , 139 , 43
Data 51 , 45 , 42 , 57 , 0 , 0 , 0 , 0 , 0 , 135
'-----------------------------[End of
Program]----------------------------------
|