$mod51
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
;==========================================================
;===========================================================
;SendSerial EQU 0041h
;SendSerialHexByte EQU 0044h
;SendSerialByte EQU 0047h
;==========================================================
; PROGRAM LOCATION
;
;modified to 0000h rather than 8000h.
;===========================================================
ORG 0000h
;==========================================================
; PROGRAM CODE
;
;This is the actual guts of the demonstration code.
;===========================================================
LCALL lcdi
LCALL SendSerial ;Send 'initializing' message
DB "Initializing keyboard ",13,0
LCALL PS2_GenericInit ;Initialize the keyboard
LCALL SendSerial ;Send the 'init done' message
DB "Init successful dumping PS/2 Communication ",13,0
CLR RI
MOV R7,#00
Loop:
JB RI,ExitProgram ;If a key has been pressed, exit
; LCALL PS2_GetByte ;Get a scan code from the keyboard
LCALL PS2_GetScanCode
JNC Loop ;If no key was pressed, keep waiting
;See if the key we got IS the key we're looking for
;JZ skip
LCALL datawrt
skip:PUSH ACC ;Otherwise, save the value returned by the keyboard
MOV A,#'{' ;Display a leading bracket
LCALL SendSerialByte ;Send it to the serial port
POP ACC ;Restore the value returned by the keyboard
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
SJMP Loop ;Wait for the next keypress
ExitProgram:
CLR RI ;Clear serial input and exit back to SBCMON
RET
;*****************************************************************
;* Function: ByteTo2Hex *
;* Purpose: Convert a single byte into two hex digits *
;* Input: A = Byte to convert (0x00-0xFF) *
;* Output: A = High nibble (ASCII 0x30-0x39,0x41-0x46) *
;* R0 = Low nibble (ASCII 0x30-0x39, 0x41-0x46) *
;* Destroyed Registers: None *
;*****************************************************************
ByteTo2Hex:
MOV R0,A
ANL A,#0Fh
ADD A,#0F6h
JNC byte_to_bcd_2
ADD A,#07h
byte_to_bcd_2:
ADD A,#3Ah
XCH A,R0
SWAP A
ANL A,#0Fh
ADD A,#0F6h
JNC byte_to_bcd_3
ADD A,#07h
byte_to_bcd_3:
ADD A,#3Ah
RET
;*****************************************************************
;* Function: SendSerialHexByte *
;* Purpose: Sends the byte in the accumulator to the serial *
;* port as two hexadecimal nibbles. *
;* Input: ACC: Byte to send *
;* Output: None. *
;* Destroyed Registers: None *
;*****************************************************************
SendSerialHexByte:
PUSH 00h ;Save R0
PUSH ACC ;Save ACC
LCALL ByteTo2Hex ;Convert high byte to two bytes of BCD
LCALL SendSerialByte ;Send the high byte
MOV A,R0 ;Send the low byte
LCALL SendSerialByte ;Send it
POP ACC ;Restore R0
POP 00h ;Restore R0
RET
;*****************************************************************
;* Function: SendSerialByte *
;* Purpose: Sends the byte in the accumulator to the serial *
;* port and waits for it to be sent before returning. *
;* Input: ACC: Byte to send *
;* Output: None. *
;* Destroyed Registers: None *
;*****************************************************************
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SendSerialByte:
CLR TI ;Prepare for transmit
MOV SBUF,A ;Send the byte out
JNB TI,$ ;Wait for byte to be sent
RET ;Done!
;*****************************************************************
;* Function: SendSerial *
;* Purpose: Sends the null-terminated string that immediately *
;* follows the LCALL that called the function to the *
;* serial port. *
;* Input: ACC: Byte to send *
;* Output: None. *
;* Destroyed Registers: None *
;*****************************************************************
SendSerial:
MOV TMOD,#22h ;Timer 1 and timer 0in Auto-reload mode
MOV TH1,#0FDh ;Reload value for 9600 baud @ 11.059 Mhz
SETB TR1 ;Turn on timer 1 for baud rate generator
MOV SCON,#52h ;Receiver Enable/Timer 1 Baud Rate 8-bit
POP DPH
POP DPL
PUSH ACC
PUSH PSW
CLR TI
SendSerial1:
CLR A
MOVC A,@A+DPTR
INC DPTR
JZ SendSerialExit
MOV SBUF,A
JNB TI,$
CLR TI
;(v1.3.1) - Removed LF-appending
;----------------------------------
CJNE A,#13,SendSerial1
MOV A,#10
MOV SBUF,A
JNB TI,$
CLR TI
;----------------------------------
SJMP SendSerial1
SendSerialExit:
POP PSW
POP ACC
PUSH DPL
PUSH DPH
RET
PS2_GenericInit:
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_GenericInit ;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_GenericInit ;If it wasn't repeat and try to initialize again
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: Scan code translation table *
;* Author: Craig Steiner *
;*-------------------------------------------------------------*
;* Description: The following codes are the scan codes returned*
;* by PS2_GetScanCode. The keyboard sends a byte(s) when a *
;* key is pressed and another sequence of bytes when the key *
;* is released. These sequences can be 1-3 bytes in length. *
;* The PS2_GetScanCode routine converts the keyboard scan *
;* codes into an internal representation that can be fit in *
;* a single byte. The constants below are the values that *
;* will be returned in the case of certain keypresses. In *
;* all cases, a value of 0-127 means the key was pressed *
;* while a value between 128-255 means the key was released. *
;***************************************************************
KS_KP_SLASH EQU 'a'
KS_RIGHTCTRL EQU 'b'
KS_RIGHTGUI EQU 'c'
KS_RIGHTALT EQU 'd'
KS_APPS EQU 'e'
KS_PRTSCREEN1 EQU 'f'
KS_PRTSCREEN2 EQU 'g'
KS_INSERT EQU 'h'
KS_HOME EQU 'i'
KS_PGUP EQU 'j'
KS_DELETE EQU 'k'
KS_END EQU 'l'
KS_PGDOWN EQU 'm'
KS_UPARROW EQU 'n'
KS_LEFTARROW EQU 'o'
KS_DOWNARROW EQU 'p'
KS_RIGHTARROW EQU 'r'
KS_KP_ENTER EQU 's'
KS_BACKSPACE EQU 't'
KS_TAB EQU 'u'
KS_CAPS EQU 'v'
KS_LEFTSHIFT EQU 'w'
KS_LEFTCTRL EQU 'x'
KS_LEFTGUI EQU 'y'
KS_LEFTALT EQU 'z'
KS_F1 EQU 01h
KS_F2 EQU 02h
KS_F3 EQU 03h
KS_F4 EQU 04h
KS_F5 EQU 05h
KS_F6 EQU 06h
KS_F7 EQU 07h
KS_F8 EQU 08h
KS_F9 EQU 09h
KS_F10 EQU 0Ah
KS_F11 EQU 0Bh
KS_F12 EQU 0Ch
KS_RIGHTSHIFT EQU 0Dh
KS_ENTER EQU 0Eh
KS_SCROLL EQU 0Fh
KS_NUMLOCK EQU 10h
KS_KP_ASTERISK EQU 11h
KS_KP_MINUS EQU 12h
KS_KP_PLUS EQU 13h
KS_KP_POINT EQU 14h
KS_ACPI_POWER EQU 15h
KS_ACPI_SLEEP EQU 16h
KS_ACPI_WAKE EQU 17h
KS_ESCAPE EQU 1Bh
KS_KP_0 EQU ')'
KS_KP_1 EQU '!'
KS_KP_2 EQU '@'
KS_KP_3 EQU '#'
KS_KP_4 EQU '$'
KS_KP_5 EQU '%'
KS_KP_6 EQU '^'
KS_KP_7 EQU '&'
KS_KP_8 EQU '*'
KS_KP_9 EQU '('
;***************************************************************
;* 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_Init *
;* Author: Craig Steiner based on code by Gabriel Lour *
;* Input: None *
;* Output Carry: Clear=Failure, Set=Success *
;*-------------------------------------------------------------*
;* Description: Initializes the keyboard and indicates whether *
;* the initialization was successful or not. *
;***************************************************************
PS2_Init:
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_Init ;If it wasn't repeat and try to initialize again
MOV A,#0F4h ; Enable keyboard 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_Err ;If not success, abort command and exit
MOV A, #0F3h ; Set Typematic
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_Err ;If not success, abort command and exit
MOV A, #00h ; Typematic = 250 ms / 30 cps
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_Err ;If not success, abort command and exit
MOV A,#0 ;Keyboard starts with LEDs off, fall through to Set LEDs
PS2_SetLeds:
PUSH ACC ;Protect LED setting passed in accumulator
MOV A, #0EDh ;Set Leds 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_Err ;If not success, abort command and exit
POP ACC ;Restore the LED setting that was passed in
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
PS2_Err:
RET
;***************************************************************
;* Function: PS2_GetScanCode *
;* Author: Craig Steiner based on code by Gabriel Lour *
;* Input: None *
;* Output Carry: Clear=No key received, Set=Key received *
;* Accumulator: Scan key code *
;*-------------------------------------------------------------*
;* Description: Gets a scan code from the keyboard and returns *
;* it. A scan code is the printable alphabet and numbers in *
;* unshifted form. 0-127 means key pressed, 128+ means *
;* key released. *
;***************************************************************
PS2_GetScanCode:
LCALL PS2_GetByte ;Try to get first character
JC PGSC_GotKey ;If we got a byte, process it
PGSC_NoKey:
CLR C ;Clear carry to signify no character received
RET ;No byte received, so just exit
PGSC_GotKey:
;If we got a key then "B" is going to be used as our return
;register. It starts out clear
MOV B,#00h ;Clear our return code
MOV DPTR,#PGSC_NormalCodes ;Point initially to the normal codes
PGSC_ProcKey:
MOV R1,A ;Hold received character in R1
CJNE A,#KB_BREAK,PGSC_NotBreak ;If it's not a break code (F0) then continue
;If it is a break code then we set the high bit of 'B' to indicate that the
;key was released.
SETB B.7 ;Set high bit
PGSC_AnotherKey:
MOV R0,#20 ;Try 20 times to wait for next byte from keyboard
PGSC_AKeyLoop:
LCALL PS2_GetByte ;We then get the next byte from keyboard
JC PGSC_ProcKey ;A byte was received, so process it
DJNZ R0,PGSC_AKeyLoop ;No key detected, so keep trying
SJMP PGSC_NoKey ;No key was found after multiple tries
PGSC_NotBreak:
;Check to see if it was an extended key
CJNE A,#KB_EXTENDED,PGSC_FindCode ;If not an extended code (E0), go process it
;This means we got an extended code. If so, we set our look-up table
;to the extended scan code table and get another key and process it.
MOV DPTR,#PGSC_ExtendedCodes ;Set lookup table to extended codes
SJMP PGSC_AnotherKey ;Go get another key and process it
PGSC_FindCode:
;This now looks for the code we received in the proper table
CLR A ;Make sure offset is zero
MOVC A,@A+DPTR ;Get next scan code from DPTR
JZ PGSC_NoKey ;If zero then end of table, so exit
XRL A,R1 ;See if the key we got IS the key we're looking for
JZ PGSC_FoundKey ;If it is, so process it
;It wasn't the right key, so we increment DPTR twice to point to the
;next table entry and process that
INC DPTR
; INC DPTR
SJMP PGSC_FindCode
PGSC_FoundKey:
INC DPTR ;Point to the translation
CLR A ;No offset
MOVC A,@A+DPTR ;Get the translated character
; ORL A,B ;Combine it with B which may hold a "break" code
SETB C ;Set carry flag to indicate we have a character
RET
PGSC_NormalCodes:
;These are the translations for the normal, non-extended codes. Basically
;these are the scan codes that consist of a single byte
DB 01Ch,'A'
DB 032h,'B'
DB 021h,'C'
DB 023h,'D'
DB 024h,'E'
DB 02Bh,'F'
DB 034h,'G'
DB 033h,'H'
DB 043h,'I'
DB 03Bh,'J'
DB 042h,'K'
DB 04Bh,'L'
DB 03Ah,'M'
DB 031h,'N'
DB 044h,'O'
DB 04Dh,'P'
DB 015h,'Q'
DB 02Dh,'R'
DB 01Bh,'S'
DB 02Ch,'T'
DB 03Ch,'U'
DB 02Ah,'V'
DB 01Dh,'W'
DB 022h,'X'
DB 035h,'Y'
DB 01Ah,'Z'
DB 045h,'0'
DB 016h,'1'
DB 01Eh,'2'
DB 026h,'3'
DB 025h,'4'
DB 02Eh,'5'
DB 036h,'6'
DB 03Dh,'7'
DB 03Eh,'8'
DB 046h,'9'
DB 00Eh,'`'
DB 04Eh,'-'
DB 055h,'='
DB 05Dh,'\'
DB 066h,KS_BACKSPACE
DB 029h,' '
DB 00Dh,KS_TAB
DB 058h,KS_CAPS
DB 012h,KS_LEFTSHIFT
DB 014h,KS_LEFTCTRL
DB 011h,KS_LEFTALT
DB 059h,KS_RIGHTSHIFT
DB 05Ah,KS_ENTER
DB 076h,KS_ESCAPE
DB 005h,KS_F1
DB 006h,KS_F2
DB 004h,KS_F3
DB 00Ch,KS_F4
DB 003h,KS_F5
DB 00Bh,KS_F6
DB 083h,KS_F7
DB 00Ah,KS_F8
DB 001h,KS_F9
DB 009h,KS_F10
DB 078h,KS_F11
DB 007h,KS_F12
DB 073h,KS_SCROLL
DB 054h,'['
DB 077h,KS_NUMLOCK
DB 07Ch,KS_KP_ASTERISK
DB 07Bh,KS_KP_MINUS
DB 079h,KS_KP_PLUS
DB 071h,KS_KP_POINT
DB 070h,KS_KP_0
DB 069h,KS_KP_1
DB 072h,KS_KP_2
DB 07Ah,KS_KP_3
DB 06Bh,KS_KP_4
DB 073h,KS_KP_5
DB 074h,KS_KP_6
DB 06Ch,KS_KP_7
DB 075h,KS_KP_8
DB 07Dh,KS_KP_9
DB 05Bh,']'
DB 04Ch,';'
; DB 052h,'''
DB 041h,','
DB 049h,'.'
DB 04Ah,'/'
PGSC_ExtendedCodes:
;These are the translations for the extended codes. These are the codes
;that start with E0 and then a second character. This table lists that
;second character
DB 01Fh,KS_LEFTGUI
DB 04Ah,KS_KP_SLASH
DB 014h,KS_RIGHTCTRL
DB 027h,KS_RIGHTGUI
DB 011h,KS_RIGHTALT
DB 02Fh,KS_APPS
DB 012h,KS_PRTSCREEN1
DB 07Ch,KS_PRTSCREEN2
DB 070h,KS_INSERT
DB 06Ch,KS_HOME
DB 07Dh,KS_PGUP
DB 071h,KS_DELETE
DB 069h,KS_END
DB 07Ah,KS_PGDOWN
DB 075h,KS_UPARROW
DB 06Bh,KS_LEFTARROW
DB 072h,KS_DOWNARROW
DB 074h,KS_RIGHTARROW
DB 05Ah,KS_KP_ENTER
DB 037h,KS_ACPI_POWER
DB 03Fh,KS_ACPI_SLEEP
DB 05Eh,KS_ACPI_WAKE
DB 0
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; lcd Routine
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
commwrt:
mov a,#00h
mov dptr,#0fff8h
movx @dptr,a
mov a,r0
mov dptr,#0fff9h
movx @dptr,a
ret
lcdi: mov r0,#38h
acall commwrt
acall delay
mov r0,#0eh
acall commwrt
acall delay
mov r0,#01h
acall commwrt
acall delay
mov r0,#06h
acall commwrt
acall delay
mov r0,#80h
acall commwrt
acall delay
ret
datawrt:
mov R1,A
mov a,#01h
mov dptr,#0fff8h
movx @dptr,a
MOV A,R1
mov dptr,#0fff9h
movx @dptr,a
ret
delay: mov r3,#10
here: mov r4,#255
here1: djnz r4,here1
djnz r3,here
ret
end