Kamikaze47,
Here is the approach I've taken with decoding a PS2 style keyboard. I'll be dishing this out in chunks. The first module is an ASM interrupt service routine that retrieves the key, does some error checking, and stuffs it into a ring buffer for later retrieval and decoding within the PBP program.
Code:
'===========================================================================
' Interrupt Handler (Low Priority)
'===========================================================================
' Keyboard "getkey" handler
; KB_getkey
; Keyboard to Host Protocol
; ___ _ _ _ _ _ _ _ _ _ _ ___
; CLOCK |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_|
;
; DATA | S | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | P | E |
;
; S = start bit = 0 P = odd parity E = stop bit = 1
; data valid on falling edge of clock
' The getkey handler responds to a high-to-low transition of the KBCLK line,
' which is the INT2 interrupt connection. Each time this occurs, data bits
' coming in through the KBDAT line (RB4) are temporarily stored in the KBcode
' variable. When a valid stop bit has been received, the data is transferred
' to a ring buffer KBbuf. This information will be later extracted by the
' PicBasic routine mod_keybd.bas and translated into ASCII and ASCIIE code.
'===========================================================================
asm
myintL
; save the state of critical registers
movwf wsave ; Save W
swapf STATUS,W ; Swap STATUS to W
clrf STATUS ; bank 0, regardless of current bank
movwf ssave ; Save swapped STATUS
; save the FSR value because it gets changed below
movf FSR0L, W
movwf fsave
movf FSR0H, W
movwf fsave+1
;===========================================================================
;AT Keyboard Service Routine
;*** check start bit ***
KB_getkey
movf _KBcnt,W ; check keyboard scan code bit counter
bnz KB_getdat ; branch if not zero (start bit)
btfsc _KBDAT ; test start bit of keyboard data input
goto KB_abort ; no valid start bit, abort
goto KB_exit ; exit
;*** keyboard scan code acquisition ***
KB_getdat
movf _KBcnt,W ; get keyboard scan code bit counter
sublw d'8' ; w = d'8' - KBDcnt (*)
bnc KB_parity ; branch if negative (carry == 0)
btfss _KBDAT ; Test keyboard data input
bcf _KBcode,7 ; clear bit 7 if KBDAT = 0
btfsc _KBDAT ; Test keyboard data input
bsf _KBcode,7 ; set bit 7 if KBDAT = 1
bz KB_exit ; exit on zero (zero flag still valid from (*))
rrncf _KBcode,F ; shift new bits right (do this only 7 times)
goto KB_exit ; exit
;*** check for parity and stop bit ***
KB_parity
movf _KBcnt,W ; get keyboard scan code counter
sublw d'9' ; w = d'9' - KBDcnt
bnc KB_stop ; branch if negative (carry == 0)
goto KB_exit ; ignore parity bit
;*** check stop bit ***
KB_stop
btfss _KBDAT ; check if stop bit is valid
goto KB_abort ; if not set, abort
;*** increment the buffer input index & test for buffer overrun ***
incf _KBindxI,W
subwf _KBindxO,W ; subtract indexes to test buffer
btfsc STATUS,Z ; check for zero (KBindxI = KBindxO)
goto KB_stall ; if error stall keyboard
;*** increment the buffer input index ***
incf _KBindxI,F
movf _KBindxI,W
sublw _KBbufsize-1 ; test if index is outside the ring buffer
btfss STATUS,C ; if it is...
clrf _KBindxI ; reset it
; Set FSR0 with the location of the next empty location in buffer
LFSR FSR0, _KBbuf ; set counter base address
; Read and store the character from the USART
movf _KBindxI, W ; W = offset value for the next empty location
movff _KBcode, PLUSW0 ; Move the character in KBcode to address (FSR0+W)
;*** stall keyboard ***
; to prevent the arrival of more data before having finished decoding
KB_stall ; hold keyboard (with keyboard clk low):
bcf TRISB,2 ; set clkline to output (back to input externally)
bcf _KBCLK ; set keyboard clk line low (stall)
bcf _INT2IE ; disable keyboard IRQ (re-enabled externally)
goto KB_term ; terminate successfully
KB_abort
clrf _KBcode ; abort / invalid data
KB_term
clrf _KBcnt ; reset keyboard scan code acquisition counter
goto KB_end ; terminate execution of keyboard IRQ
KB_exit
incf _KBcnt,F ; increment acquisition counter
KB_end
bcf _INT2IF ; clear INT2 interrupt flag
;restore registers
movf fsave, W
movwf FSR0L
movf fsave+1, W
movwf FSR0H
swapf ssave,W ; Retrieve the swapped STATUS value
movwf STATUS ; Restore it to STATUS
swapf wsave,F ; Swap the stored W value
swapf wsave,W ; Restore it to W
retfie ; Return from the interrupt
endasm
And here is the PBP equates (please forgive me if I've missed any) and initialization code:
Code:
' PIC18F series processor used
DEFINE OSC 40
DEFINE INTLHAND myintL
'===========================================================================
' Equates
'===========================================================================
'Variables for saving state in interrupt handler
wsave VAR BYTE bankA system ' Saves W
ssave VAR BYTE bankA system ' Saves STATUS
fsave VAR WORD bankA system ' Saves FSR0
'Keyboard (Low Priority) Interrupt Handler equates
KBbufsize con 10 ' keyboard buffer size
KBcnt var byte bankA ' bit counter for keyboard data
KBbuf var byte[KBbufsize] bankA ' keyboard ring buffer
KBindxI var byte bankA ' keyboard buffer Input index pointer
KBindxO var byte bankA ' keyboard buffer Output index pointer
KBcode var byte bankA ' temporary storage for scan code
'Ketboard Handler equates
LED var byte
scrlock var LED.0 ' If true, scroll lock is on (active)
numlock var LED.1 ' If true, num lock is on (active)
caplock var LED.2 ' If true, caps lock is on (active)
pscrlck var LED.3 ' If true, scroll lock pressed
pnumlck var LED.4 ' If true, numlock pressed
pcaplck var LED.5 ' If true, caps lock pressed
keystat var byte
Lshift var keystat.0 ' If true, left Shift pressed
Rshift var keystat.1 ' If true, right Shift pressed
L_ctrl var keystat.2 ' If true, left Ctrl pressed
R_ctrl var keystat.3 ' If true, right Ctrl pressed
L_alt var keystat.4 ' If true, left Alt pressed
R_alt var keystat.5 ' If true, right Alt pressed
keydec var keystat.6 ' If true, a key has been decoded
scancode var byte ' temporary storage for raw keyboard scan code
keycode var byte ' temporary storage for converted scancode
ascii var byte ' temporary storage for Ascii equivalent
parity var byte ' used during getkey for Parity tracking
bitcnt var byte ' bit counter for putkey routines
shift var bit ' If true, either shift key is pressed
ctrl var bit ' If true, either control key is pressed
alt var bit ' If true, either alt key is pressed
KBrelease var bit ' flags the release of a standard key
KBextend var bit ' flags that an extended key has been pressed
KBrelextend var bit ' flags the release of an extended key
enav var bit ' flags navigation key as extended version
KB_timeout var byte
TOvalue con $FF
TOcntDLY con 10
'===========================================================================
' Intitialize keyboard module, check for keyboard presence, and enable IRQ
'===========================================================================
'Check for presence of keyboard
startupKB:
init = 1
Gosub modstart_KBinit ' initialize & start keyboard module
If KB_timeout = TOvalue Then
; *** error code goes here *** (keyboard not present on start-up)
Endif
Pause 1000
'Set-up Interrupts
INTEDG2 = 0 ' INT2 (KBCLK) interrupt on falling edge
INT2IP = 0 ' INT2 (KBCLK) set as low priority interrupt
INT2IF = 0 ' INT2 (KBCLK) clear flag
INT2IE = 1 ' INT2 (KBCLK) interrupt enabled
IPEN = 1 ' Enable priority levels on interrupts
INTCON = %11000000 ' Enable all interrupts!
'===========================================================================
' Program Start (MAIN)
'===========================================================================
mainloop:
Gosub KBmain ' checking for keyboard activity...
' and decode any incoming characters.
' ---------------------------------
'
' program code here --- KBmain will return result in ascii variable
'
' ---------------------------------
Goto mainloop
The nice thing about using the assembly interrupt routine, is that there will be very little overhead to the PBP part of the program, and no matter how busy it gets, you will never miss a key.
If you are interested in seeing more, then on the next installment I'll post the KBmain code (decodes keyscan codes), followed by the lookup table. Please let me know 
Cheers,
Bookmarks