http://home.clear.net.nz/pages/joecolquitt/pic_keyboard.html
The object of this project is to capture keys of a standard AT keyboard.
They
can be stored, compiled as strings, and re-transmitted either to the PC or
to
some other device, as the original key presses or as extracted commands
For example, the PIC could capture strings, and perform actions
Such as
sc:1329:040810[enter] to set the PIC's clock-calendar to 1:29pm, 4th August
2010
ky:[F1]a:1000:050810[enter] to simulate pressing F1 then 'a' at 10:00am on
5th August 2010
ir:94:2030:060810[enter] to send the number 94 by infra-red at 8:30pm on
the 6th
[ ] indicates the code for a special key. [F1] has the value 0x05 for
instance.
[enter] may not always be suitable for the string terminator. Perhaps [Esc]
or
'<' or [Tab] for example as alternates
PIC pin definitions ;
#define ir_data lata,0 ;infra-red drive #define pickup porta,1 ;press to store keys #define kbd_out lata,2 ;keyboard data out (transistor drive, ie inverted logic) #define kbc_out lata,3 ;keyboard clock out (transistor drive, ie inverted logic) #define send porta,4 ;press to manually transmit stored key(s) ;#define mclr porta,5 ;reset #define led lata,6 ;LED #define rw lata,7 ;LCD R/W #define kbc_in portb,0 ;keyboard clock in, normally high #define kbd_in portb,1 ;keyboard data in, normally high #define en latb,2 ;LCD Enable #define rs latb,3 ;LCD RS ;#define portb,4 ;LCD data, 4-bit mode ;#define portb,5 ;#define portb,6 ;#define portb,7 ;================================================ ; Receive and store key data ;================================================ ;Keyboard Clock (kbc_in) and Data (kbd_in) normally high, ;open-collectors with pullups ;release clock and data lines (ie no transistor drive, resistors pull lines high) bcf kbd_out nop nop bcf kbc_out ;Data format - ;1 start bit, '0' ;8 data bits, LSb first ;1 parity bit, odd ;1 stop bit, '1' ;Data changes when clock = 1, valid when clock = 0 As the keyboard codes have no direct relationship to ASCII codes, the key code is used as a pointer to its ASCII code in a table, but simply for display in my case. The key code itself would be stored if required for re-transmission In the s/w presented here, only the basic layout is shown. For example letters are all lower case. By detecting the Shift, Alt and Ctrl keys, the corresponding alternate layout can be displayed. This can be done by calculation, for example a (lower case) = 0x61, Shift a (or A, upper case) = 0x41 b = 0x62, B = 0x42 and so on, or by adding more tables, still using the key value as the pointer For example a Shift layout could be used to get Shift number characters - ! @ # $ etc For my project, I used arbitrary conversions for non-alphanumeric keys so that each key has a unique representation and assignment ;0x00 no conversion available (ie no key exists) ;0x20 to 0x7f LCD display code in ASCII ; ;0x80 to 0x8f function key, 0x80 + function key number ;0xf0 to 0xff special key, as assigned ; ;f0 Tab, f1 tilde, f2 left shift, f3 Ctrl, f4 Caps Lock, f5 right shift, f6 Enter ;f7 backslash, f8 backspace, f9 back space, fa Esc, fb Num Lock, fc Alt ; ;Note that right-hand versions of some same-name keys (eg Ctrl) are preceded by ;0xE0, as can be seen in the keyboard codes diagram below ; ;Others, such as the numeric keypad, are treated differently by the PC depending ;on the status of Lock keys. The transmitted code is still the same, only the ;interpretation (for display and usage etc) by s/w changes ;******************************* kb_loop call data_st ;detect and get key into kbdat1 ;================================================ ; Convert key data to key name ;================================================ kb_dec movlw upper(kb_codes);base address = kb_codes movwf tblptru movlw high(kb_codes) movwf tblptrh movlw low(kb_codes) addwf kbdat1,w ;add k/b value movwf tblptrl tblrd*+ movff tablat,temp0 ;get value from table movfw temp0 bz no_key ;no equivalent movlw 0xf0 cpfslt temp0 ;if temp0 < f0 bra special ;else f? (special key) movlw 0x80 cpfslt temp0 ;if temp0 < 80 bra function ;else 8? (function key) call store ;store the key if necessary movfw temp0 dispw ;otherwise, printable on LCD goto release ;detect either 0xf0 or another key pressed special keys routines ;process (and store) special key, check release function keys routine ;process (and store) function key, check release store routine ;if desired, store the key in a queue for ;later retrieval and transmission release call data_st ;get data movlw 0xf0 ;key release code xorwf kbdat1,w At this point - The XOR result will be 0, ie a key released. Get more data to determine which key it was, if more than one key was down For example, if 'A' was pressed and released, the sequence will be 0x1c 0xf0 0x1c If Left Ctrl '.', the sequence will be 0x14 0x49 0xf0 0x49 0xf0 0x14
ie Left Ctrl pressed, '.' pressed, '.' released, Left Ctrl released
Or the XOR result will be <> 0, meaning either a key is down and is repeating or a second key is pressed. Get more data. If the first key down is a special key such as Shift, Ctrl or Alt, then the next key detected may need to be looked up in an alternate conversion table. eg Shift ',' to make '<'
Include a timing routine to test for repeat. Default time before repeating starts is around 500ms. Time between repeats is the Typematic setting
;================================================ ; Receive key from PC ;================================================ ;Clock line shared with mouse, so use Data line for activity detection data_st btfsc kbd_in ;Data low, k/b is active bra $-2 ;Start bit btfsc kbc_in ;keyboard clock low bra $-2 btfss kbc_in ;end of Start bit bra $-2 movlw .8 ;data bit counter movwf temp1 clrf kbdat1 ;receiving buffer ;pick up 8 bits, data valid when clock is low kb8 rrncf kbdat1 ;shift bit through buffer, 1st time is dummy bcf bit_in ;data = default 0 btfsc kbc_in ;wait for clock = 0 bra $-2 btfsc kbd_in ;skip if data is 0 bsf bit_in ;else store 1 btfss kbc_in ;wait for clock = 1 bra $-2 decfsz temp1 ;counter bra kb8 ;Parity bit - receive, ignore btfsc kbc_in bra $-2 btfss kbc_in bra $-2 ;Stop bit - receive, ignore btfsc kbc_in bra $-2 btfss kbc_in bra $-2 return ;with key in kbdat1 ;================================================ ; Transmit key to PC ;================================================ ;1 start bit, '0' ;8 data bits, LSb first ;1 parity bit, odd ;1 stop bit, '1' ;Data changes when clock = 1, valid when clock = 0 ;Clock and data outputs are inverted by transistors ;ie PIC '1' drives transistor to ground the line ;data in temp0 transmit movwf temp0 ;byte to transmit movlw .8 movwf temp1 ;data bit counter clrf temp4 ;parity counter ;Start bit bsf kbd_out ;data line low call _17us ;hold for 17us bsf kbc_out ;clock line low call _44us ;hold for 44us bcf kbc_out ;clock line high call _17us ;5us > delay < 25us before data transition ;begin data transmission. key_loop movlw b'00000001' ;test data bit to send andwf temp0,w bnz _1bit ;data = 1 _0bit bsf kbd_out ;data = 0 (ground data line) bra bit_del _1bit bcf kbd_out ;data = 1 (release data line) incf temp4 ;parity count bit_del call _25us ;25us delay bsf kbc_out ;data valid call _44us ;hold for 44us bcf kbc_out ;clock high call _17us ;hold for 17us rrncf temp0 ;shift in next data bit decfsz temp1 ;bit counter bra key_loop movlw b'00000001' ;test parity count andwf temp4,w bz parity1 parity0 bsf kbd_out ;result odd, send '0' -> odd parity bra tx_end parity1 bcf kbd_out ;result even, send '1' -> odd parity tx_end call _25us bsf kbc_out call _44us bcf kbc_out ;Stop bit call _17us bcf kbd_out ;data line idle call _25us usec usec bsf kbc_out ;clock line low call _44us bcf kbc_out ;clock line idle return
;================================================ ;convert keyboard data to key name and/or ASCII character for PIC's use ; ;data received from keyboard ; ;00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f data received ; F9 F5 F3 F1 F2 F12 F10 F8 F6 F4 Tab ~ = key pressed ;10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ; Alt LSh Ctl q 1 z s a w 2 ;20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f ; c x d e 4 3 SP v f t r 5 ;30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f ; n b h g y 6 m j u 7 8 ;40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f ; , k i o 0 9 . l p - ;50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f ; [ = Cap RSh Ent ] \ ;60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 'n' indicates ; Bksp 1n 4n 7n numeric keypad ;70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f ;0n .n 2n 5n 6n 8n Esc Num F11 +n 3n *n -n ;80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f ; F7 org kb_codes ;ASCII and special codes for keys Examples - ;key received is 0x2d. Data at table address 0x2d is 0x72 = ASCII r ;key received is 0x78. Data at table address 0x78 is 0x8b = F11 ;key received is 0x12. Data at table address 0x12 is 0xf2 = Left Shift ;key received is 0x47. Data at table address 0x47 is 0x00 = no equivalent ;18F table, basic layout ; 1 0 3 2 5 4 7 6 9 8 b a d c f e data 0x8900,0x8500,0x8183,0x8c82,0x8a00,0x8688,0xfc84,0x00f1 ;0x data 0xf900,0x00f2,0x71f3,0x0031,0x0000,0x737a,0x7761,0x0032 ;1x data 0x6300,0x6478,0x3465,0x0033,0x2000,0x6676,0x7274,0x0035 ;2x data 0x6e00,0x6862,0x7967,0x0036,0x0000,0x6a6d,0x3775,0x0038 ;3x data 0x2c00,0x696b,0x306f,0x0039,0x2e00,0x6c00,0x7000,0x002d ;4x data 0x0000,0x0000,0x3d7b,0x0000,0xf5f4,0x7df6,0xf700,0x0000 ;5x data 0x0000,0x0000,0x0000,0x00f8,0x3100,0x3400,0x0037,0x0000 ;6x data 0x2e30,0x3532,0x3836,0xfbfa,0x2b8b,0x0033,0x002a,0x002d ;7x data 0x0000,0x8700,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 ;8x ;16F table, basic layout ; ; 0 1 2 3 4 5 6 7 8 9 a b c d e f ; dt 0x00,0x89,0x00,0x85,0x83,0x81,0x82,0x8c,0x00,0x8a,0x88,0x86,0x84,0xfc,0xf1,0x00 ;0x ; dt 0x00,0xf9,0xf2,0x00,0xf3,0x71,0x31,0x00,0x00,0x00,0x7a,0x73,0x61,0x77,0x32,0x00 ;1x ; dt 0x00,0x63,0x78,0x64,0x65,0x34,0x33,0x00,0x00,0x20,0x76,0x66,0x74,0x72,0x35,0x00 ;2x ; dt 0x00,0x6e,0x62,0x68,0x67,0x79,0x36,0x00,0x00,0x00,0x6d,0x6a,0x75,0x37,0x38,0x00 ;3x ; dt 0x00,0x2c,0x6b,0x69,0x6f,0x30,0x39,0x00,0x00,0x2e,0x00,0x6c,0x00,0x70,0x2d,0x00 ;4x ; dt 0x00,0x00,0x00,0x00,0x7b,0x3d,0x00,0x00,0xf4,0xf5,0xf6,0x7d,0x00,0xf7,0x00,0x00 ;5x ; dt 0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0x31,0x00,0x34,0x37,0x00,0x00,0x00 ;6x ; dt 0x30,0x2e,0x32,0x35,0x36,0x38,0xfa,0xfb,0x8b,0x2b,0x33,0x00,0x2a,0x00,0x2d,0x00 ;7x ; dt 0x00,0x00,0x00,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ;8x
Questions:
Code: