;********************************************************************** ;* 8052.com Single Board Computer -- SBCMON Demonstration Program * ;* ---> PS2/KEYBOARD DEMONSTRATION PROGRAM <--- * ;* For 8052.com SBC, hardware rev 1.3 * ;*--------------------------------------------------------------------* ;* CREDIT: This program is based on code submitted to 8052.com code * ;* library by Gabriel Lour (http://www.8052.com/codelib/kb.asm). * ;* It has been modified primarily to make it compatible with the * ;* Pinnacle 52 IDE, to conform to the style of other SBCMON example * ;* programs, and to use different pins for the keyboard connections.* ;* Also modified code so it uses "R" registers instead of specific .* ;* internal RAM addresses for variable storage. .* ;*--------------------------------------------------------------------* ;* This program is offered as-is with no warranty or guarantee of any * ;* kind. Its purpose is to serve as an educational aid in mastering * ;* the topics and concepts covered by the program. You are free to * ;* use this code for any purpose you see fit--including commercial-- * ;* but the exclusive responsibility for its use is the user of this * ;* code. This code is offered completely free of charge and VIS' and * ;* 8052.com's liability will be limited to the amount paid: zero. * ;*--------------------------------------------------------------------* ;* This program was coded to be compatible with the Pinnacle 52 IDE. * ;* Pinnacle 52 is available at http://www.vaultbbs.com/pinnacle. The * ;* program may require minor modifications in order to assemble with * ;* other assemblers. * ;*--------------------------------------------------------------------* ;* NOTE: This program was designed to be loaded into SBCMON's XRAM * ;* and executed as an SBCMON external program. It depends on one or * ;* more SBCMON library routines and, as such, will not work without * ;* SBCMON. This program is not intended to be loaded via in-system * ;* programming, only loaded within SBCMON. Should you wish to load * ;* this program via ISP as a stand-alone program, the SBCMON library * ;* entry point equates should be removed and the respective routines * ;* should be copied from SBCMON into this program. The source code * ;* for SBCMON may be found at http://www.8052.com/sbc/sbcmon. * ;*====================================================================* ;* Filename: PS2.ASM * ;* Description: This is an example program that allows a PS/2 keyboard* ;* or mouse to be attached to the 8052.com SBC using P1.2 as a clock* ;* and P1.3 as the data line. At that point, a keyboard or mouse * ;* may be attached to the SBC and the program will display all * ;* output from the device on a byte-by-byte basis. This is useful * ;* in viewing the raw data being produced by the PS/2 device. * ;* * ;* See http://www.8052.com/sbc/ps2 for details. * ;* * ;* Note: The program at http://www.8052.com/sbc/ps2key is a better * ;* example if you wish to deal with data specifically from a PS/2 * ;* keyboard since it will properly deal with multi-byte scan codes. * ;* This example program is meant to simply display the raw data from* ;* a PS/2 keyboard or mouse with no interpretation whatsoever of the* ;* data. * ;********************************************************************** KEYB_DATA EQU P1.3 ;Line to which PS/2 keyboard data line is connected KEYB_CLOCK EQU P1.2 ;Line to which PS/2 keyboard clock line is connected KB_ACK EQU 0FAh ;Constant which represents the 'ACK' code sent back from keyboard KB_BREAK EQU 0F0h ;Constant which represents that a key is no longer being pressed KB_EXTENDED EQU 0E0h ;Constant which represents an extended scan code sequence ;========================================================== ; SBCMON LIBRARY ROUTINE ENTRY POINT EQUATES ; ;If you wish to make this a stand-alone program, remove ;these equates and copy the source code for the named ;routines from the SBCMON source code. SBCMON source code ;may be found at http://www.8052.com/sbc/sbcmon. ;=========================================================== SendSerial EQU 0041h SendSerialHexByte EQU 0044h SendSerialByte EQU 0047h ;========================================================== ; PROGRAM LOCATION ; ;The program is located at 8000h since this is where the ;8052.com SBC's XRAM/code memory is in the memory map. ;Programs loaded into this RAM area can be accessed as both ;data and executed as a program. If you are going to make ;this a stand-alone program the following ORG should be ;modified to 0000h rather than 8000h. ;=========================================================== ORG 8000h ;========================================================== ; PROGRAM CODE ; ;This is the actual guts of the demonstration code. ;=========================================================== CLR P1.2 LCALL SendSerial ;Send 'initializing' message DB "Initializing mouse",13,0 LCALL PS2_MouseInit ;Initialize the keyboard LCALL SendSerial ;Send the 'init done' message DB "Init successful, you may move the mouse",13,0 CLR RI Loop: JNB RI,LoopOk LJMP ExitProgram ;If a key has been pressed, exit LoopOk: LCALL PS2_GetMouse ;Get a mouse read JNC Loop ;If no key was pressed, keep waiting MOV B,A MOV A,#13 LCALL SendSerialByte MOV A,#'{' ;Display a leading bracket LCALL SendSerialByte ;Send it to the serial port MOV A,B LCALL SendSerialHexByte ;Send it to the terminal as a 2-byte hex value MOV A,#'}' ;Display a trailing bracket LCALL SendSerialByte ;Send it to the serial port MOV A,#'{' ;Display a leading bracket LCALL SendSerialByte ;Send it to the serial port MOV A,R7 LCALL SendSerialHexByte ;Send it to the terminal as a 2-byte hex value MOV A,#'}' ;Display a trailing bracket LCALL SendSerialByte ;Send it to the serial port MOV A,#'{' ;Display a leading bracket LCALL SendSerialByte ;Send it to the serial port MOV A,R6 LCALL SendSerialHexByte ;Send it to the terminal as a 2-byte hex value MOV A,#'}' ;Display a trailing bracket LCALL SendSerialByte ;Send it to the serial port JNB B.7,NotBit7 LCALL SendSerial DB "OVY ",0 NotBit7: JNB B.6,NotBit6 LCALL SendSerial DB "OVX ",0 NotBit6: JNB B.5,NotBit5 LCALL SendSerial DB "Y- ",0 NotBit5: JNB B.4,NotBit4 LCALL SendSerial DB "X- ",0 NotBit4: JNB B.2,NotBit2 LCALL SendSerial DB "MID ",0 NotBit2: JNB B.1,NotBit1 LCALL SendSerial DB "RT ",0 NotBit1: JNB B.0,NotBit0 LCALL SendSerial DB "LT ",0 NotBit0: LJMP Loop ;Wait for the next keypress ExitProgram: CLR RI ;Clear serial input and exit back to SBCMON RET PS2_MouseInit: MOV A,#0FFh ;Initializtation command ACALL PS2_SendByte ;Send command to keyboard ACALL PS2_GetByte ;Get a response byte, should be ACK ACALL PS2_ChkAck ;Check to see if it was ACK JNC PS2_MouseInit ;If it wasn't repeat and try to initialize again MOV A,#0F6h ;Set default values ACALL PS2_SendByte ;Send command to keyboard ACALL PS2_GetByte ;Get a response byte, should be ACK ACALL PS2_ChkAck ;Check to see if it was ACK JNC PS2_MouseInit ;If it wasn't repeat and try to initialize again MOV A,#0F4h ;Enable reporting ACALL PS2_SendByte ;Send command to keyboard ACALL PS2_GetByte ;Get a response byte, should be ACK ACALL PS2_ChkAck ;Check to see if it was ACK JNC PS2_MouseInit ;If it wasn't repeat and try to initialize again RET ;*************************************************************** ;* Function: PS2_GetByte * ;* Author: Craig Steiner based on code by Gabriel Lour * ;* Input: None * ;* Output Carry bit: Clear=No key returned,Set=Key returned * ;* Accumulator: Byte returned by keyboard * ;* Registers Modified: None * ;*-------------------------------------------------------------* ;* Description: Gets a single byte from the keyboard, if there * ;* is a byte to get. Returns it in the accumulator and sets * ;* carry bit. Otherwise clears the carry bit. * ;*************************************************************** PS2_GetByteSetR0: MOV A,R0 ;We don't save Accumulator since return value can be in accumulator PUSH ACC ;Protect R0 SJMP PS2_GetByte2 ;Use R0 that is passed in PS2_GetByte: MOV A,R0 ;We don't save Accumulator since return value can be in accumulator PUSH ACC ;Protect R0 MOV R0, #50 ;Wait 50 loop cycles for data line to be lowered by keyboard PS2_GetByte2: SETB KEYB_DATA ;Raise data line so it can receive data SETB KEYB_CLOCK ;Raise clock so that keyboard communication is enabled PGB_CheckAgain: JNB KEYB_CLOCK, PGB_KeyHit ;If clock line is now low that means keyboard is talking to us DJNZ R0, PGB_CheckAgain ;Check R0 number of times SJMP PGB_KeyEnd ;No keyboard response was detected in loop period PGB_KeyHit: JNB KEYB_DATA, PGB_StartOk ;Start bit must be 0 PGB_KeyEnd: CLR KEYB_CLOCK ;Disable keyboard CLR C ;Clear carry to indicate no keypress PGB_PopExit: XCH A,R0 ;Hold accumulator temporarily in R0 POP ACC ;Restore value of R0 XCH A,R0 ;Restore accumulator and R0 RET PGB_StartOk: MOV R0,#8 ;8 bits to clock into accumulator CLR A ;Accumulator initially empty PGB_KeyHit3: ACALL PS2_GetBit ;Get one bit and shift into accumulator DJNZ r0, PGB_KeyHit3 ;Execute for each of the 8 bits PUSH ACC ;Save the value read from keyboard on the stack CLR A ACALL PS2_GetBit ;Get parity bit ACALL PS2_GetBit ;Get stop bit CLR KEYB_CLOCK POP ACC ;Restore the byte we read SETB C ;Set carry flag to indicate key press SJMP PGB_PopExit ;Exit routine ;*************************************************************** ;* Function: PS2_GetBit * ;* Author: Craig Steiner based on code by Gabriel Lour * ;* Input: Accumulator: Starting value of clocked-in data * ;* Output Accumulator: New value of cloced-in data * ;* Registers Modified: Carry bit * ;*-------------------------------------------------------------* ;* Description: Waits for a 1-0 transition on the clock line * ;* from the keyborad. When this happens, we have valid data * ;* on the data line so we get it and rotate it into the * ;* accumulator. * ;*************************************************************** PS2_GetBit: JNB KEYB_CLOCK, $ JB KEYB_CLOCK, $ MOV C, KEYB_DATA RRC A RET ;*************************************************************** ;* Function: PS2_WaitClock * ;* Author: Craig Steiner based on code by Gabriel Lour * ;* Input: None * ;* Output None * ;* Registers Modified: Nine * ;*-------------------------------------------------------------* ;* Description: Waits for a 1-0 transition on the clock line * ;* from the keyborad and returns. * ;*************************************************************** PS2_WaitClock: JNB KEYB_CLOCK, $ JB KEYB_CLOCK, $ RET ;*************************************************************** ;* Function: PS2_SendByte * ;* Author: Craig Steiner based on code by Gabriel Lour * ;* Input: Accumulator: Value to send to keyboard * ;* Output Accumulator: New value of cloced-in data * ;* Registers Modified: Carry bit * ;*-------------------------------------------------------------* ;* Description: Waits for a 1-0 transition on the clock line * ;* from the keyborad. When this happens, we have valid data * ;* on the data line so we get it and rotate it into the * ;* accumulator. * ;*************************************************************** PS2_SendByte: XCH A,R0 ;Swap A and R0 temporarily PUSH ACC ;This saves the value of R0 on stack XCH A,R0 ;And this restores the accumulator to its original value CLR KEYB_CLOCK ;Break the Keyboard MOV R0,#00h ;Some delay (safety reasons) DJNZ R0,$ ;Loop for 256 cycles CLR KEYB_DATA ;Request to send SETB KEYB_CLOCK ;Enable the Keyboard ACALL PS2_WaitClock ;Start Bit PUSH ACC ;Protect original value of accumulator MOV R0,#8 ; 8bits to receive PSB_Xmit: RRC A ;Shift bits into carry MOV KEYB_DATA, C ;Send highest bit out to keyboard ACALL PS2_WaitClock ;Wait for keyboard to acknowledge DJNZ R0,PSB_Xmit ;Loop for each bit POP ACC ;Restore original value of accumulator MOV C,PSW.0 ;This is Even parity CPL C ;And Keyboard needs Odd parity MOV KEYB_DATA,C ;Send parity bit ACALL PS2_WaitClock ;Wait for keyboard to acknowledge bit SETB KEYB_DATA ;Send stop bit ACALL PS2_WaitClock ;Wait for keyobard to acknowledge bit ACALL PS2_WaitClock ;Wait for keyboard to acknowledge bit MOV C, KEYB_DATA ;Get the ACK bit from the keyboard, store in carry CLR KEYB_CLOCK ;Deselect the keyboard XCH A,R0 POP ACC XCH A,R0 ;Restore R0 ret ;*************************************************************** ;* Function: PS2_CheckAck * ;* Author: Craig Steiner based on code by Gabriel Lour * ;* Input: Accumulator: Value received from keyboard * ;* Output Carry: Clear=NAK, Set=ACK receivedn data * ;*-------------------------------------------------------------* ;* Description: Checks to see if the contents of the acc is * ;* the ACK code (FAh). If it is, it sets the carry bit. If * ;* it isn't, it clears it. * ;*************************************************************** PS2_ChkAck: CJNE A,#KB_ACK,PCA_NAK ;If character was not ACK, clr carry to indicate failure SETB C ;Set carry to indicate successful ACK RET PCA_NAK: CLR C ;Clear carry to indicate failure RET ;*************************************************************** ;* Function: PS2_GetMouse * ;* Author: Craig Steiner * ;* Input: None * ;* Output Carry: Clear=No mouse rec'd, Set=Mouse received * ;* Accumulator: First byte of mouse movement * ;* Bit 7: Y overflow * ;* Bit 6: X overflow * ;* Bit 5: Y movement sign * ;* Bit 4: X movement sign * ;* Bit 3: Always set * ;* Bit 2: Middle button status * ;* Bit 1: Right button status * ;* Bit 0: Left button status * ;* R7: Second mouse byte (X movement) * ;* R6: Third mouse byte (Y movement) * ;*-------------------------------------------------------------* ;* Description: Gets three codes from the mouse, if available, * ;* and returns them. * ;*************************************************************** PS2_GetMouse: LCALL PS2_GetByte ;Try to get first character JC PGMC_GotKey ;If we got a byte, process it PGMC_NoKey: CLR C ;Clear carry to signify no character received RET ;No byte received, so just exit PGMC_GotKey: ;If we got a key then that is our first byte (holds movement sign, ;overflow, and mouse button status). This will get stored in the ;accumulator eventually but for now R6=First byte MOV R6,A LCALL PS2_GetAnotherByte JNC PGMC_NoKey ;We now have the second byte in accumulator. This will be returned ;in R7 so we move this to R7 and then call to get another byte MOV R7,A ;Return second byte in R7 LCALL PS2_GetAnotherByte JNC PGMC_NoKey ;We now have the third byte in the accumulator. However, the third ;byte should be returned in R6 and the first byte (currently in R6) ;should be returned in accumulator. So we swap them using the XCH ;instruction. XCH A,R6 ;This puts the first byte and third byte into proper registrs SETB C ;Clear carry to indicate a successful read RET ;Return to main program PS2_GetAnotherByte: MOV R0,#20 ;Try 20 times to wait for next byte from keyboard PGAB_AKeyLoop: LCALL PS2_GetByte ;We then get the next byte from keyboard JC PGAB_Exit ;A byte was received, so exit DJNZ R0,PGAB_AKeyLoop ;No key detected, so keep trying PGAB_Exit: RET