KEYBOARD

<< Frame Pseudographics   ·    Home   ·   UART >>

It is would be a straightforward task to make the PS2 keyboard routine, but in this project the timings are too tight to realize the full PS2 communication and, to get things worse, video signal and keyboard packets are totally asynchronous and there is no way to synchronize them. The approach used here is to poll the Clock state at the beginning of each horizontal scan line and fetch Data status if the falling edge was detected. Macro EXTRAJOB does this. Start, parity and stop bits are ignored, and the only synchronization condition is if the pause in clock signal is longer than 3.2 ms. The received data bytes are written into 4-byte buffer KBDSTREAM, where they are waiting for the end of the frame (routine LOWERFRAME) to be analyzed. The keyboard scan codes (set 2) are converted into ASCII codes and written at the location KBDBUF, where it is available for the user's program, located outside of the interrupt routine. Bit FLAG,#1 is used for handshaking: interrupt routine sets it when the key is depressed ("make" scan code detected), and the user's routine has to reset it when the ASCII character is read from KBDBUF.

The raw scan codes are written in the 6-byte variable RAW_KEY (4-byte keyboard scan codes in RAW_KEY+0...RAW_KEY+3, and the byte count in RAW_KEY+4). If you uncomment the line call keydata at the beginning of DEMO.INC file, those bytes will be displayed at the top of the screen in hexadecimal form, each time the key is pressed. The fourth 4-digit hex number is ASCII code (or special code, according to the following table) for the pressed key.

Uppercase and lowercase codes are automatically affected by the state of the SHIFT key and CAPS LOCK key. Special (non-ASCII) keys have their special codes, which are listed here. Those codes (which are located in table CODES_00 or, if code begins with EO byte, table CODES_E0) do not belong to any standard (excluding BKSP and TAB), they are used only in this project.

KEY MAKE BREAK   KEY MAKE BREAK   KEY MAKE BREAK
F1 128     R CTRL 142 221   NKP 1 177  
F2 129     R GUI 143     NKP 2 178  
F3 130     R ALT 144 222   NKP 3 179  
F4 131     PRT SCRN 145     NKP 4 180  
F5 132     SCR LOCK 146     NKP 5 181  
F6 133     PAUSE 147     NKP 6 182  
F7 134     INSERT 148     NKP 7 183  
F8 135     HOME 149     NKP 8 184  
F9 136     PG UP 150     NKP 9 185  
F10 137     DELETE 151     NKP / 186  
F11 138     END 152     NKP * 187  
F12 139     PG DN 153     NKP - 188  
CAPS 140     UP ARROW 154     NKP + 189  
L SHIFT 141 220   LEFT ARROW 155     NKP ENTER 190  
L CTRL 142 221   DOWN ARROW 156     NKP . 191  
L GUI 143     RIGHT ARROW 157     BKSP 8  
L ALT 144 222   NUM LOCK 158     TAB 9  
R SHIFT 141 220   NKP 0 176     ENTER 13 223

There is the special KBDFLAG variable in data memory, which is serviced by the routine so that it contains flags for some special keys. Those flags should only be read, not modified by the user's routine (BREAK codes listed in the previous table are are used by the interrupt routine for KBDFLAG servicing).

KBDFLAG,#0   set if the SHIFT key is depressed, reset when released
KBDFLAG,#1
  set if the CTRL key is depressed, reset when released
KBDFLAG,#2
  set if the ALT key is depressed, reset when released
KBDFLAG,#3
  set if the ENTER key is depressed, reset when released
KBDFLAG,#8
  toggled each time when the CAPS LOCK key is depressed
KBDFLAG,#9
  toggled each time when the NUM LOCK key is depressed
KBDFLAG,#10
  toggled each time when the SCROLL LOCK key is depressed

There is the subroutine GET_KEY, which does most of the job for keyboard interfacing via KBDBUF and FLAG,#1. This is the action:

Wait for key pressed (FLAG,#1 set) and get key code from KBDBUF
If code >220, it is break code; update KBDFLAG bits and return code in W0
If code >186, it is numeric keypad spec code; translate it to ? * - + . ENTER
If code >176, it is numeric keypad 0-9 code; reset bit 7 and return ASCII in W0
IF CAPS LOCK active (KBDFLAG,#8 set), convert lowercase to uppercase
If SHIFT pressed, exchange lowercase and uppercase via lookup table SHIFT_CONV

For most applications, the best way to read keyboard is to call this subroutine and read W0 when it returns. W0 will contain ASCII code of the pressed key or the code from the previous table. All SHIFT and CAPS LOCK variations are covered. If you need just to test if the key is pressed, without looping until it is pressed, and to return to the main program, you have to test the FLAG,#1 and, if it is set, call subroutine CONVERT_KEY, which will clear FLAG,#1, translate KBDBUF content and return ASCII or special code value in W0.

 

Note 1: In this project, there is no way to pass the parameters (autorepeat timings and LEDs states) to the keyboard.

Note 2: The protocol in this routine is simplified, as it is highly optimized for the execution speed. In some cases, when the keyboard sends more scan codes without the pause, it may omit some keys. It makes it theoretically possisible to omit some SHIFT, CTRL and ALT break codes if more keys are pressed at the same time. So, in some rare cases, the false states of KBDFLAG bits may occur, e.g. KBDFLAG,#0 may be set even if the SHIFT key was released. Depressing and releasing SHIFT again will rebuild the correct flag state. The same applies for CTRL, ALT and ENTER bits in variable KBDFLAG. The possible way to solve this problem is to employ some ring buffer which will be loaded by the raw data from the keyboard, even if there was no pause between data streams detected, as the problem is the consequence of waiting for that pause. To improve the keyboard routine, that part of the program must be rearranged, with the larger (but still fast enough) buffer, and the another routine (possibly in the main program) which analyzes the content of that buffer.

Note 3: The unit was tested with several PS/2 keyboards and it worked, but it supports only SET 2 codes. Although SET 3 is rarely used, there is still the possibility that you have such keyboard. In that case, you have to rearrange keyboard tables in file TABLES.INC (codes.00 and codes.e0). SET 1 is used only by the obsolete XT keyboard, which is not supported by this project.

<< Frame Pseudographics   ·    Home   ·   UART >>