AT/PS2 Keybord - PIC Interface?


Closed Thread
Results 1 to 40 of 74

Hybrid View

  1. #1
    Join Date
    Nov 2005
    Location
    Perth, Australia
    Posts
    429


    Did you find this post helpful? Yes | No

    Default

    After looking thought the pbp manual im thinking the SHIFTIN *might* do the trick?

    What u guys recon?

  2. #2
    Join Date
    Sep 2003
    Location
    Vermont
    Posts
    373


    Did you find this post helpful? Yes | No

    Default

    Search the archives, there are some good links there. Also, Shiftin is a master routine. You need a slave routine to work with the keyboard. Tom Enghdahl's? site has some excellent info on the interfacing of a uP to a keyboard. Alas, it's in assembly, but it is fairly easy to translate to PBP.

    Ron

  3. #3
    Join Date
    Nov 2005
    Location
    Perth, Australia
    Posts
    429


    Did you find this post helpful? Yes | No

    Default

    So i take it that pbp doesnt have a slave version of shiftin?

  4. #4
    Join Date
    Sep 2003
    Location
    Vermont
    Posts
    373


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Kamikaze47
    So i take it that pbp doesnt have a slave version of shiftin?
    Nope. You basically "sit and rotate"... Let me explain, the keyboard line has a data and a clock line. It is controlled by the keyboard clock. I don't remember, but I believe the data is valid on a high to low transition of the clock. This can be confirmed with a Google search. You will also need to know whether the data is clocked in MSB, or LSB first. The shiftin subroutine waits for the clock line to go low(?), puts the data state into the lowest bit of your variable,if MSB,and shift the variable one position to the left. This is followed by a wait for the clock line to go back high, and it is done 7 more times. You can do this in a for next loop, and the code is pretty simple.
    FOR A = 1 to 8
    loop1: IF clock = 1 then loop1
    Key_data.0 = dataline
    Key_data = Key_data *2 ; Shift once to left
    loop2: IF clock = 0 then loop2
    Next A
    Key_data now contains the keypress value. It is not the neat Ascii representation of the character you pressed. Nooooo....Lest it be that simple! Now you must use a lookup table with the proper characters in the right order, but when you are done, you will have the right character. Right? Unless you want upper and lower case. You will have to look at the shift keypress characters and see if they are being held down, or if caps lock has been engaged. Let's not even talk about the "extended characters"!

    Have fun,
    Ron

  5. #5
    Join Date
    Nov 2005
    Location
    Perth, Australia
    Posts
    429


    Did you find this post helpful? Yes | No

    Default

    Thanks for that Ron Marcus. Yep the data comes in when the clock does a high to low transition, is least signicant bit first, and is 11 bits long (1 start bit, 8 data bits, 1 parity bit and 1 stop bit).

    So, hopefully something like this will work:

    FOR A = 1 to 11
    loop1: IF clock = 1 THEN GOTO loop1
    IF A=1 OR A=10 or A=11 THEN GOTO loop2 'No need to store start, stop or partiy bits
    Key_data.7 = dataline
    Key_data = Key_data/2 'Shift once to the right
    loop2: IF clock = 0 THEN GOTO loop2
    NEXT A

  6. #6
    mytekcontrols's Avatar
    mytekcontrols Guest


    Did you find this post helpful? Yes | No

    Default Here's an interrupt routine I use to retrieve the key...

    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,
    Last edited by mytekcontrols; - 8th November 2005 at 05:13. Reason: missed something

  7. #7
    Join Date
    Nov 2005
    Location
    Perth, Australia
    Posts
    429


    Did you find this post helpful? Yes | No

    Default

    mytekcontrols: Thanks heaps for that.

    I managed to get it somewhat going without interrupts but it messes up whenever I type fast on the keyboard, so i'll give ur code a try. I'll just have to go through it all 1st to make sure I understand it

    If you could post your code that decodes the keyscan codes that would be excellent. I tried writing my own but the code was so long that it wouldn’t fit on the PIC16F84A that im using. It may be the case that I need to go with a different PIC?

Similar Threads

  1. MXcom "C-BUS" interface to PIC question
    By tcbcats in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 1st May 2014, 04:59
  2. Interface a pic with a Iphone/Itouch
    By Luckyborg in forum General
    Replies: 1
    Last Post: - 6th May 2009, 17:02
  3. 4 pin 4 x 4 keypad interface using pic basic pro
    By dunlao_john in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 15th January 2009, 06:21
  4. USB Interface using PIC
    By Tissy in forum mel PIC BASIC Pro
    Replies: 21
    Last Post: - 22nd May 2006, 17:04
  5. Serial Pic to Pic using HSER
    By Chadhammer in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 12th March 2005, 00:14

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts