⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kbd9.asm

📁 一个PS2键盘单片机, 使用Philips的接口+8051,写的不错,非常值得学习.
💻 ASM
📖 第 1 页 / 共 4 页
字号:
;----------------------------------------
;OUT_PHILIPS:
;	MOV	I2C_BUFFER,#WRITE_BUFFER
;	MOV	I2C_BUFFER+1,#0
;	MOV	I2C_BUFFER+2,#8
;	MOV	I2C_BUFFER+3,#0FDH
;	MOV	I2C_BUFFER+4,#50H	    ;'P'
;	MOV	I2C_BUFFER+5,#68H	    ;'h'
;	MOV	I2C_BUFFER+6,#69H	    ;'i'
;	MOV	I2C_BUFFER+7,#6CH	    ;'l'
;	MOV	I2C_BUFFER+8,#69H	    ;'i'
;	MOV	I2C_BUFFER+9,#70H	    ;'p'
;	MOV	I2C_BUFFER+10,#73H    ;'s'
;	MOV	RW_COUNTER,#10
;	LCALL	WRITE_N_BYTE
;	RET
;----------------------------------------
;=================================
READ_FROM_d11:
	MOV	SLV_ADR,#036H		;WRITE COMMAND
	MOV	CNT_BYTE,#1		;NUMBER OF BYTES TO BE SENT
	LCALL	WRITE_d11_POINT 	;READ 1 BYTES
;-----
	MOV	SLV_ADR,#035H		;READ DATA
	MOV	CNT_BYTE,RW_COUNTER
	ACALL	READ_d11
	RET


;---------------------------------------
; WRITE DATA INTO ENDPOINT 0 INPUT
;---------------------------------------
WRITE_TO_d11:
;-----------
	CLR	VALIDATE_FLAG			    ;IS WRITE BUFFER COMMAND?
	MOV	A,I2C_BUFFER
	XRL	A,#WRITE_BUFFER
	JNZ	WRITE_TO_d11_1
	SETB	VALIDATE_FLAG
;
	MOV	I2C_BUFFER,#SEL_EPT_EMBF_IN	   ;SELECT EMBED IN BUFFER
	AJMP	SEL_EPT_COMMAND
SEL_EPT_COMMAND:
	LCALL	WRITE_COMMAND
	MOV	I2C_BUFFER,#WRITE_BUFFER
;-----------
WRITE_TO_d11_1:
	MOV	SLV_ADR,#036H		;WRITE COMMAND
	MOV	CNT_BYTE,#1		;NUMBER OF BYTES TO BE SENT
	ACALL	WRITE_d11_POINT 	;READ 1 BYTES
;----------
	MOV	SLV_ADR,#034H		;WRITE DATA
	MOV	CNT_BYTE,RW_COUNTER
	ACALL	WRITE_d11
;-----
	JNB	VALIDATE_FLAG,WRITE_RET ;ONLY WRITE BUFFER NEED VALIDATE BUFFER
	MOV	I2C_BUFFER,#VALIDATE_BUF    ;READY DATA TO SEND
	LCALL	WRITE_COMMAND
;----
WRITE_RET:
	RET
;----------------------------------------

;***************************************************************
;*   Function = Read_d11
;*	Input = SlvAdr (d11 slave address);
;*		CNT_Byte (Number of Bytes to be sent);
;*
;*     Return = I2C_BUFFER Buffer
;*     Change = R0,R3
;****************************************************************
READ_d11:
	MOV	BYTE_CNT,CNT_BYTE
;----
	ACALL	GOMASTER		;ACQUIRE BUS AND SEND SLAVE ADDRESS.
	JB	I2C_FAIL,READ_NOK	;CHECK FOR SLAVE NOT RESPONDING.
;---
	MOV	R0,#I2C_BUFFER		    ;SET FIRST RECEIVE DATA BUFFER ADDRESS
READ_DATA_LOOP:
	ACALL	RCV_BYTE		;RECEIVE DATA BYTE
	MOV	@R0,A			;PUT RECEIVED DATA TO BUFFER
	INC	R0			;PREPARE NEXT BYTE
	DJNZ	BYTE_CNT,READ_DATA_LOOP ;REPEAT UNTIL ALL BYTES RECEIVED
READ_NOK:
READ_OK:
	ACALL	SEND_STOP		;DONE, SEND AN I2C STOP.
	RET
;========================================
RCV_BYTE:
	MOV	BITCNT,#8		;SET BIT COUNT.
RCV_LOOP:
	ACALL	SCLHIGH 		;READ ONE DATA BIT.
	ACALL	BITDLY
	MOV	C,SDAPIN		;GET DATA BIT FROM PIN.
	RLC	A			;ROTATE BIT INTO RESULT BYTE.
	CLR	SCLPIN
	ACALL	BITDLY
	DJNZ	BITCNT,RCV_LOOP 	;REPEAT UNTIL ALL BITS RECEIVED.
;---
	PUSH	ACC			;SAVE ACCUMULATOR
	MOV	A,BYTE_CNT
	CJNE	A,#1,SRBACK		;CHECK FOR LAST BYTE OF FRAME.
	SETB	SDAPIN			;SEND NO ACKNOWLEDGE ON LAST BYTE.
	SJMP	SRBACLK 		;NO ACK WHEN IT'S LAST BYTE
;----
SRBACK:
	CLR	SDAPIN			;SEND ACKNOWLEDGE BIT.
SRBACLK:
	ACALL	SCLHIGH 		;SEND ACKNOWLEDGE CLOCK.
	POP	ACC			;RESTORE ACCUMULATOR
	ACALL	BITDLY
	CLR	SCLPIN
	SETB	SDAPIN			;CLEAR ACKNOWLEDGE BIT.
	ACALL	BITDLY
	RET

;****************************************************************************
;*   Function = WRITE_d11
;*	Input = SLV_ADR (d11 SLAVE ADDRESS)
;*		SUB_ADR (d11 COMMAND);
;*		CNT_Byte (Number of Bytes to be sent);
;*		@I2C_BUFFER (Output Buffer, Data to be sent, starts from RAM
;*			  location sI2C_BUFFER)
;*     Return = None
;*     Change = R0,R3
;*****************************************************************************
WRITE_d11_POINT:
	MOV	R0,#I2C_BUFFER		    ;SET FIRST RECEIVE DATA BUFFER ADDRESS
WRITE_d11:
	MOV	BYTE_CNT,CNT_BYTE
;----
	ACALL	GOMASTER		;ACQUIRE BUS AND SEND SLAVE ADDRESS.
	JB	I2C_FAIL,WRITE_NOK	;CHECK FOR SLAVE NOT RESPONDING.
;-----
;;;	MOV	R0,#I2C_BUFFER		    ;SET FIRST RECEIVE DATA BUFFER ADDRESS
WRITE_DATA_LOOP:
	MOV	A,@R0			;GET DATA BYTE FROM BUFFER.
	ACALL	SEND_BYTE		;SEND NEXT DATA BYTE.
	INC	R0			;ADVANCE BUFFER POINTER.
	JB	I2C_FAIL,WRITE_NOK	   ;CHECK FOR SLAVE NOT RESPONDING.
	DJNZ	BYTE_CNT,WRITE_DATA_LOOP ;ALL BYTES SENT?
WRITE_NOK:
WRITE_OK:
	ACALL	SEND_STOP		;DONE, SEND AN I2C STOP.
	RET


;========================================
;	SEND SLAVE ADDRESS TO d11
;----------------------------------------
GOMASTER:
	CLR	I2C_FAIL		;CLEAR ERROR STATUS FLAGS.
;---
	JNB	SCLPIN,FAULT		;CHECK FOR BUS CLEAR.
	JNB	SDAPIN,FAULT
	CLR	SDAPIN			;BEGIN I2C START.
	ACALL	BITDLY
	CLR	SCLPIN
	ACALL	BITDLY			;COMPLETE I2C START.
	MOV	A,SLV_ADR		;GET SLAVE ADDRESS.
	ACALL	SEND_BYTE		;SEND SLAVE ADDRESS.
	RET
;-------------
FAULT:
	SETB	I2C_FAIL		;SET FAULT STATUS
	RET				;AND EXIT.
;-------------
BITDLY:
	RET				;NOPS TO DELAY 5 MICROSECONDS (MINUS 4
;========================================
SEND_BYTE:
	MOV	BITCNT,#8		;SET BIT COUNT.

SBLOOP:
	RLC	A			;SEND ONE DATA BIT.
	MOV	SDAPIN,C		;PUT DATA BIT ON PIN.
	ACALL	SCLHIGH 		;SEND CLOCK.
	ACALL	BITDLY
	CLR	SCLPIN
	ACALL	BITDLY
	DJNZ	BITCNT,SBLOOP		;REPEAT UNTIL ALL BITS SENT.

	SETB	SDAPIN			;RELEASE DATA LINE FOR ACKNOWLEDGE.
	ACALL	SCLHIGH 		;SEND CLOCK FOR ACKNOWLEDGE.
	ACALL	BITDLY
	JNB	SDAPIN,SBEX		;CHECK FOR VALID ACKNOWLEDGE BIT.
	SETB	I2C_FAIL		;SET STATUS FOR NO ACKNOWLEDGE.
SBEX:
	CLR	SCLPIN			;FINISH ACKNOWLEDGE BIT.
	ACALL	BITDLY
	RET
;=======================================
SCLHIGH:
	SETB	SCLPIN			;Set SCL from our end.
	JNB	SCLPIN,$		;Wait for pin to actually go high.
	RET
;-----------------------------------
SEND_STOP:
	CLR	SDAPIN			;Get SDA ready for stop.
	ACALL	SCLHIGH 		;SET CLOCK FOR STOP.
	ACALL	BITDLY
	SETB	SDAPIN			;SEND I2C STOP.
	ACALL	BITDLY
	RET				;BUS SHOULD NOW BE RELEASED.
;---
DELAY_20MS:
	PUSH	ACC
	MOV	R7,#20
	AJMP	DELAY_1MS
;========================================
DELAY_100MS:
	PUSH	ACC
	MOV	R7,#100
;----
DELAY_1MS:
	MOV	A,#200		;200*5us=1ms
DY:
	NOP
	NOP
	NOP
	DEC	A
	JNZ	DY
	DJNZ	R7,DELAY_1MS
;DY_RET:
	POP	ACC
	RET
;;
;==============================
; For Interrupt Pipe
;==============================

EMB_ED1_INPUT:

;	JNB	PS2_BUFFER_CHANGED,INT_RET	;NO CHANGE, NO NEED TO RESEND
;	CLR	PS2_BUFFER_CHANGED

	MOV	I2C_BUFFER,#READ_LAST_EMBF_INT_ST	;CLEAR INTERUPT BIT AND LINE
	LCALL	READ_ONE_BYTE
;------
	MOV	I2C_BUFFER,#SEL_EPT_EMBF_INT	;SELECT EMB EPT0 IN
	LCALL	READ_ONE_BYTE
	MOV	A,I2C_BUFFER
	ANL	A,#00000001B			;IS BUFFER EMPTY?
	JNZ	INT_RET				;not empty, return

head_fill:
	MOV	RW_COUNTER,#10		;TOTAL BYTES TO SEND = data length plus 2
	MOV	R0,#I2C_BUFFER
	MOV	@R0,#WRITE_BUFFER		;COMMAND
	INC	R0
	MOV	@R0,#0 			;FIRST BYTE SHOULD BE ZERO
	INC	R0
	MOV	@R0,#8			;DATA LENGTH 8 BYTES

	JNB	PS2_ERROR_ROLLOVER,NORMAL_DATA_FILL
	CLR	PS2_ERROR_ROLLOVER

;REPORT PHANTOM STATE
	INC	R0
	MOV	@R0,KBD_MODIFIER		;SET MODIFIER BYTE
	INC	R0
	MOV	@R0,#0			;SET RESERVED BYTE
	MOV	R7,#6
ERROR_data_fill:
	INC	R0
	MOV	@R0,#01H
	DJNZ	R7,ERROR_data_fill
	AJMP	INT_WRITE_N_BYTE

NORMAL_DATA_FILL:
	MOV	I2C_BUFFER+3,KBD_MODIFIER		;SET MODIFIER BYTE
	MOV	I2C_BUFFER+4,#0				;SET RESERVED BYTE
	MOV	I2C_BUFFER+5,PS2_BUFFER			;SET HID KEYCODE #1
	MOV	I2C_BUFFER+6,PS2_BUFFER+1		;SET HID KEYCODE #2
	MOV	I2C_BUFFER+7,PS2_BUFFER+2		;SET HID KEYCODE #3
	MOV	I2C_BUFFER+8,PS2_BUFFER+3		;SET HID KEYCODE #4
	MOV	I2C_BUFFER+9,PS2_BUFFER+4		;SET HID KEYCODE #5
	MOV	I2C_BUFFER+10,PS2_BUFFER+5		;SET HID KEYCODE #6

INT_WRITE_N_BYTE:					;INTERRUPT PIPE TO HOST
	MOV	I2C_BUFFER,#SEL_EPT_EMBF_INT
	LCALL	WRITE_COMMAND
	MOV	I2C_BUFFER,#WRITE_BUFFER
INT_WRITE_TO_d11_1:
	MOV	SLV_ADR,#036H			;WRITE COMMAND
	MOV	CNT_BYTE,#1				;NUMBER OF BYTES TO BE SENT
	LCALL	WRITE_d11_POINT			;READ 1 BYTES

	MOV	SLV_ADR,#034H			;WRITE DATA
	MOV	CNT_BYTE,RW_COUNTER
	LCALL	WRITE_d11

	MOV	I2C_BUFFER,#VALIDATE_BUF	;READY DATA TO SEND
	LCALL	WRITE_COMMAND

	JNB	PAUSE_FLAG,INT_RET
	CLR	PAUSE_FLAG				;REMOVE <PAUSE> KEY FROM BUFFER AFTER SENT
	MOV	A,#48H
	ACALL	BREAK_KEY

INT_RET:
	RET		;END OF EMD_ED1_INPUT
;;
;;====================================================================================
;;	MCU begins to receive ps2 data byte through external interrupt pin INT1(pin 12).
;;	PS2 clk signal was connected to INT1 pin(pin 12). For the very first time, INT1
;;	interrupt was enabled and falling-edge active. Then uP read one complete byte 
;;	(10 bits) with polling. During this time, interrupt was disabled until the whole 
;;	byte(or several bytes for extra keycodes) was completely received. 
;;
;;	According to PS2 specification, the data must have existed on the PS2-SDA before
;;	PS2_CLK become low. So uP doesn't read the SDA until SCL goes low.
;;
;;	Before return, interrupt was enabled again.
;;======================================================================================
;;
PS2_INF:
	push	acc
	push	psw
	SETB	RS0
	clr	ex1				;disable external interrupt INT1

GET_ONE_KEY:
	CLR	E0_FLAG
	LCALL	READ_PS2_BYTE		;READ IN ONE PS/2 BYTE
	CJNE	A,#0CCH,EXTRA_KEYCODE	;'CC', NO MORE CODE IN
	AJMP	END_PS2_INF
;-------------------------------------------------------------------------------
; EXTRA KEYCODES
;-------------------------------------------------------------------------------
EXTRA_KEYCODE:
;	CJNE	A,#84H,E1_KEYCODE
;	MOV	A,#46H			;'84', <ALT> + <PRINT SCREEN> DOWNCODE
;	SETB	E0_FLAG
;	AJMP	EXIT_MAKE_KEY
;E1_KEYCODE:
	CJNE	A,#0E1H,E0_KEYCODE
	SETB	E0_FLAG
	LCALL	READ_PS2_BYTE		;CODE STREAM BEGINS WITH 'E1'
	LCALL	READ_PS2_BYTE
	LCALL	READ_PS2_BYTE
	LCALL	READ_PS2_BYTE
	LCALL	READ_PS2_BYTE
	LCALL	READ_PS2_BYTE
	LCALL	READ_PS2_BYTE
	MOV	A,#77H			;'E1 14 77 E1 F0 14 F0 77', <PAUSE> DOWNCODE
	SETB	PAUSE_FLAG
	AJMP	EXIT_MAKE_KEY
BASIC_KEYCODE_1:
	AJMP	BASIC_KEYCODE
E0_KEYCODE:				
	CJNE	A,#0E0H,BASIC_KEYCODE_1
	SETB	E0_FLAG
	LCALL	READ_PS2_BYTE		;CODE STREAM BEGINS WITH 'E0'
	CJNE	A,#0F0H,E0_11
;E0_F0_KEYCODE:
	LCALL 	READ_PS2_BYTE		;CODE STREAM BEGINS WITH 'E0 F0'
E0_F0_11:
	CJNE	A,#11H,E0_F0_14
	CLR	KBD_R_ALT			;'E0 F0 11', RIGHT ALT UPCODE
	AJMP	EXIT
E0_F0_14:
	CJNE	A,#14H,E0_F0_27
	CLR	KBD_R_CTRL			;'E0 F0 14', RIGHT CTRL UPCODE
	AJMP	EXIT
E0_F0_27:
	CJNE	A,#27H,E0_F0_1F
	CLR	KBD_R_GUI			;'E0 F0 27', RIGHT GUI UPCODE
	AJMP	EXIT
E0_F0_1F:
	CJNE	A,#1FH,E0_F0_2F
	CLR	KBD_L_GUI			;'E0 F0 1F', LEFT GUI UPCODE
	AJMP	EXIT
E0_F0_2F:
	CJNE	A,#2FH,E0_F0_12
	CLR	E0_FLAG			;'E0 F0 2F', RIGHT APP UPCODE
	AJMP	EXIT_BREAK_KEY
E0_F0_12:
	CJNE	A,#12H,E0_F0_59
	AJMP	END_PS2_INF
E0_F0_59:
	CJNE	A,#59H,E0_F0_XX
	AJMP	END_PS2_INF
E0_F0_XX:
	AJMP	EXIT_BREAK_KEY
;-------------------------------------------------------------------------------
; RIGHT KEYBOARD KEYCODES(UPCODE) AND SOME SPECIAL KEYCODES
;-------------------------------------------------------------------------------
E0_11:
	CJNE	A,#11H,E0_14
	SETB	KBD_R_ALT			;'E0 11', RIGHT ALT DOWNCODE
	AJMP	EXIT
E0_14:
	CJNE	A,#14H,E0_27
	SETB	KBD_R_CTRL			;'E0 14', RIGHT CTRL DOWNCODE
	AJMP	EXIT
E0_27:
	CJNE	A,#27H,E0_1F
	SETB	KBD_R_GUI			;'E0 27', RIGHT GUI DOWNCODE
	AJMP	EXIT
E0_1F:
	CJNE	A,#1FH,E0_2F
	SETB	KBD_L_GUI			;'E0 1F', LEFT GUI DOWNCODE
	AJMP	EXIT
E0_2F:
	CJNE	A,#2FH,E0_84
	CLR	E0_FLAG			;'E0 2F', <APPLICATION> DOWNCODE
	AJMP	EXIT_MAKE_KEY
E0_84:
	CJNE	A,#84H,E0_12
	CLR	E0_FLAG			;'E0 84', <ALT> + <PRINT SCREEN> UPCODE
	AJMP	EXIT_BREAK_KEY
E0_12:
	CJNE	A,#12H,E0_59
	AJMP	END_PS2_INF
E0_59:
	CJNE	A,#59H,E0_7E
	AJMP	END_PS2_INF
E0_7E:
	CJNE	A,#7EH,E0_XX
	LCALL	READ_PS2_BYTE
	LCALL	READ_PS2_BYTE
	LCALL	READ_PS2_BYTE
	SETB	PAUSE_FLAG
	AJMP	EXIT_MAKE_KEY
E0_XX:
	AJMP	EXIT_MAKE_KEY
;-------------------------------------------------------------------------------
; LEFT KEYBOARD AND KEYPAD KEYCODES 
;-------------------------------------------------------------------------------
BASIC_KEYCODE:
	CJNE	A,#0F0H,DOWNCODE	;'F0 ##', BASIC UPCODE
	LCALL	READ_PS2_BYTE
UP_LEFT_CTRL:
	CJNE	A,#14H,UP_LEFT_SHIFT
	CLR	KBD_L_CTRL		;'F0 14', <LEFT CTRL> UPCODE
	AJMP	EXIT
UP_LEFT_SHIFT:
	CJNE	A,#12H,UP_LEFT_ALT
	CLR	KBD_L_SHIFT		;'F0 12', <LEFT SHIFT> UPCODE
	AJMP	EXIT
UP_LEFT_ALT:
	CJNE	A,#11H,UP_RIGHT_SHIFT
	CLR	KBD_L_ALT		;'F0 11', <LEFT ALT> UPCODE
	AJMP	EXIT
UP_RIGHT_SHIFT:
	CJNE	A,#59H,UP_OTHERS
	CLR	KBD_R_SHIFT		;'F0 59', <RIGHT SHIFT> UPCODE
	AJMP	EXIT
UP_OTHERS:
;	MOV	@R0,#0			;CLEAR KEYCODE IN PS2_BUFFER(KEY RELEASED)
	AJMP	EXIT_BREAK_KEY
DOWNCODE:
	CJNE	A,#14H,DN_LEFT_SHIFT	;'##', (## != 'E0' OR 'F0') BASIC DOWNCODE
	SETB	KBD_L_CTRL		;'14', LEFT CTRL DOWNCODE'
	AJMP	EXIT
DN_LEFT_SHIFT:
	CJNE	A,#12H,DN_LEFT_ALT
	SETB	KBD_L_SHIFT		;'12', LEFT SHIFT DOWNCODE
	AJMP	EXIT
DN_LEFT_ALT:
	CJNE	A,#11H,DN_RIGHT_SHIFT
	SETB	KBD_L_ALT		;'11', LEFT ALT DOWNCODE
	AJMP	EXIT
DN_RIGHT_SHIFT:
	CJNE	A,#59H,DN_OTHERS
	SETB	KBD_R_SHIFT		;'59', RIGHT SHIFT DOWNCODE
	AJMP	EXIT
DN_OTHERS:
	AJMP	EXIT_MAKE_KEY

EXIT_MAKE_KEY:
	ACALL	FIND_HID_KEYCODE
	JZ	EXIT
	ACALL	MAKE_KEY
	SJMP	END_PS2_INF
EXIT_BREAK_KEY:
	ACALL	FIND_HID_KEYCODE
	JZ	EXIT
	ACALL	BREAK_KEY
	SJMP	END_PS2_INF
EXIT:
	SETB	PS2_BUFFER_CHANGED
;	INC	R0
;	AJMP	GET_ONE_KEY
END_PS2_INF:
;	CLR	IT1
	CLR	RS0
	pop	psw
	pop	acc
	SETB	EX1
	reti

;*******************************************************************************
;ROUTINE :
;FUNCTION:
;INPUTS  :
;OUTPUTS :
;CHANGED :
;---------------------------------------
FIND_HID_KEYCODE:
	JB	E0_FLAG,E0_KEYS
	JB	KBD_SELECT_SCANSET_3,PS3_KEYS
	MOV	DPTR,#TBL_PS2_TO_HID			;BASIC KEYCODE TABLE
	SJMP	LOOK_UP
  PS3_KEYS:
	MOV	DPTR,#TBL_PS3_TO_HID
	SJMP	LOOK_UP
  E0_KEYS:
	MOV	DPTR,#TBL_PS2EXTRA_TO_HID		;EXTRA KEYCODE TABLE
	CLR	C
	SUBB	A,#4AH
	CLR	E0_FLAG
  LOOK_UP:
	MOVC	A,@A+DPTR
END_FIND_HID_KEY:
	RET
;*******************************************************************************
;ROUTINE :
;FUNCTION:
;INPUTS  :
;OUTPUTS :
;CHANGED :
;---------------------------------------
MAKE_KEY:
	MOV	R2,A
	DEC	A
	JZ	ROLLOVER				;'01', ERROR ROLLOVER CONDITION

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -