Here is the 2nd and final piece of the KBmain module, which is responsible for the keyboard keyscan-to-ascii decoding process. This code covers all the subroutines utilized within the first part.
The KBmain Module Part B:
Here are the port I/O assignments that I used on my PIC18F2525:Code:;=============================================================================== ; scrl - Toggle Status of Scroll lock and Echo to Keyboard ;=============================================================================== scrl: pscrlck = 1 'set flag to prevent routine recall LED = (LED ^ %001) 'toggle Scroll lock flag Goto LEDshow ;=============================================================================== ; nums - Toggle Status of Num lock and Echo to Keyboard. ;=============================================================================== nums: pnumlck = 1 'set flag to prevent routine recall LED = (LED ^ %010) 'toggle Num lock flag Goto LEDshow ;=============================================================================== ; caps - Toggle Status of Caps lock and Echo to Keyboard. ;=============================================================================== caps: pcaplck = 1 'set flag to prevent routine recall LED = (LED ^ %100) 'toggle Caps lock flag Goto LEDshow ;=============================================================================== ; extend - An Extended key has been pressed. ;=============================================================================== extend: KBextend = 0 Gosub getbuf Select Case scancode Case $F0 'an extended key has been released KBrelextend = 1 Goto KBexit Case $11 'Right Alt pressed R_alt = 1 Case $14 'Right Ctrl pressed R_ctrl = 1 Case $5A 'Enter key on Numpad pressed ascii = $0D Goto dec_done Case $4A '"/" on Numpad pressed ascii = "/" Goto dec_done Case $71 'Delete on Nav keys pressed keycode = $4A Goto navkey1 End Select If scancode > $83 Then KBexit 'exceeds table boundry Gosub keycode_tbl 'translate to keycode If keycode = $80 Then KBexit 'value not defined in table If keycode < $31 Then KBexit 'not a navigation key enav = 1 navkey: If keycode = $45 Then KBexit 'ignore numpad 5 key If numlock = 1 Then If ctrl = 0 Then If shift = 0 Then If keycode = $4A Then ' if delete then... ascii = "." ' make as period Goto dec_done Endif Endif Endif Endif If keycode < $4A Then Goto navkey2 navkey1: keycode = keycode - $19 're-index for table read Goto KBmain1 navkey2: ascii = keycode + $50 'normal key If shift = 1 Then If enav or keycode < $40 Then ascii = keycode + $70 'shift modified key Else ascii = keycode - $10 're-index for numbers 0-9 Endif enav = 0 Endif If ctrl = 1 Then ascii = keycode + $90 'ctrl modified key Goto dec_done ;=============================================================================== ; release - A Key has been Released. ;=============================================================================== release: KBrelease = 0 gosub getbuf Select Case scancode Case $12 'Left shift key released Lshift = 0 Case $59 'Right shift key released Rshift = 0 Case $14 'Left Ctrl key released L_ctrl = 0 Case $11 'Left Alt key released L_alt = 0 Case $58 'Caps lock key released pcaplck = 0 Case $7E 'Scroll lock key released pscrlck = 0 Case $77 'Num lock key released pnumlck = 0 End Select Goto KBexit ;=============================================================================== ; rel_ext - An Extended Key has been Released. ;=============================================================================== rel_ext: KBrelextend = 0 Gosub getbuf Select Case scancode Case $11 'Right Alt key released R_alt = 0 Case $14 'Right Ctrl key released R_ctrl = 0 End Select Goto KBexit ;=============================================================================== ; LEDshow - Copies the 3 LSB of the LED register to the keyboard for the ; keyboard's Status LEDs (i.e.; Num Lock, Caps Lock, Scroll Lock). ;=============================================================================== LEDshow: scancode = $ED Gosub putkey scancode = (LED & %111) Gosub putkey If init = 1 Then init = 0 Return Endif Goto KBexit ;=============================================================================== ; _putkey ; Host to Keyboard Protocol ; ___ _ _ _ _ _ _ _ _ _ _ _ _ ___ ; CLOCK |__| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| ; ; DATA | S | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | P | E |ACK| ; ; S = start bit = 0 P = odd parity E = stop bit = 1 ACK =0 ; data valid on falling edge of clock ;=============================================================================== putkey: parity = 1 'set-up parity register (odd parity) 'Let's initiate a com request to the keyboard. Low KBCLK 'pull clock line low. Pauseus 35 'pause 35uSec... Low KBDAT 'pull data line low. Pauseus 125 'pause 125uSec longer... Input KBCLK 'then release the clock line. 'we have now signaled the keyboard 'that we wish to send data to it 'so let's do it! For bitcnt = 1 To 8 'set for 8 data bits Gosub sendbit 'send DATA BIT If scancode.0 = 0 Then nextbit 'if not a 1 then continue parity = parity + 1 'else, add up total # of 1's nextbit: scancode = scancode >> 1 'shift out next bit Next bitcnt scancode.0 = parity.0 Gosub sendbit 'send PARITY BIT scancode.0 = 1 Gosub sendbit 'send STOP BIT 'all data bits sent so... Input KBDAT 'release the data line Pauseus 100 'and wait for ACK BIT to pass. Return 'DONE --- Scancode sent to keyboard!!! sendbit: ' time-out counter --- requires keyboard response, else bail out! Pauseus TOcntDLY 'determines delay for each count KB_timeout = KB_timeout + 1 If KB_timeout = TOvalue Then Return Endif ' looking for keyboard clock line to go low, then send data bit to it! If KBCLK = 1 Then sendbit 'loop until clock line goes low KBDAT = scancode.0 'send data bit KB_timeout = 0 clkhigh: If KBCLK = 0 Then clkhigh 'loop until clock line goes high Return
Actually any port pin can be used for the KBDAT I/O, and any port pin capable of generating an interrupt on a high-to-low transition could be used for KBCLK (with the proper changes in the interrupt code). Both ports are used for bi-directional communications with the keyboard, and should both be provided with 4.7K pull-up resistors to +5 Vdc. No initialization is required for either of these ports (it is all handled from within the KBmain module).Code:KBCLK VAR PORTB.2 ; INT2 KBDAT VAR PORTB.3
Here is the pin-out for the mini-din plug used on a typical PS2 keyboard (I hope those guys in the Proton area don't mind me borrowing this):
<img src="http://www.picbasic.co.uk/forum/attachment.php?attachmentid=603&stc=1&d=1131493312 ">
And here is a test routine to see if everything is working properly:
And this concludes the last of our series on Interfacing a PS2 Keyboard to your PICCode:DEFINE HSER_TXSTA 20h DEFINE HSER_BAUD 9600 A var byte B var byte temp var byte '============================================ ' Test Routine '============================================ mainloop: Gosub KBmain ' Do keyboard decode routine and if ' a key has been pressed then a jump ' will be made to "modstart_prnt2scrn". Goto mainloop ' Else, keep looping! modstart_prnt2scrn: If keydec Then ' check if decoded key is present keydec = 0 ' If so... reset key decoded flag, Gosub dec2hex ' create 2 digit hex value from ascii, ' and send formatted info out RS232. ' serial output example: ascii = A ($41) hserout["ascii = ",ascii," ($",A,B,")",$0D,$0A] Endif Return dec2hex: temp = ascii/16 Gosub dec2hex_tbl A = temp temp = ascii//16 Gosub dec2hex_tbl B = temp Return dec2hex_tbl: Lookup temp,["0123456789ABCDEF"],temp Return
P.S. Let me know if I missed something. I all stripped this stuff out of a much larger program that I wrote, and hopefully I got all the bits.





Bookmarks