;EXAM10.ASM
;Matrix KeyBoard 4x3
;
MAXCOL		EQU	3		;Max Column = 3
KEYMARK		EQU	00000111B	;Mark bit Use input bit
;User internal ram area

	ORG     30H
KeyBuff:	DS	1	;
KeyRow:		DS	1	;Hold Key Row
KeyCol:		DS	1	;Hold Key Col
Key:		DS	1

	ORG	0000H

;*** Power up delay ***
;Wait for other Device
RES:	MOV	R2,#40H
RES1:	MOV	R3,#0
RES2:	DJNZ	R3,RES2
	DJNZ	R2,RES1

;*** MAIN ***
MAIN:	LCALL	InitUART	;Initial UART 9600,n,8,1 no parity

	MOV	DPTR,#Hello
	LCALL	SendSROM

Next:	LCALL	ScanKey		;Read Key Board
	MOV	A,KEY		;Test Key
	XRL	A,#00		;if key = 0
	JZ	Next		;   Yes Scan Next
	
	MOV	A,KEY		;Get Key value
	LCALL	SNDASCII	;Display Key Code
	LCALL	LineFeed	;Send Line Feed

	SJMP	Next		;Scan Next
;End Main


;*** Scan Key Board ***
;IN no
;Out	KEY =0 not key press
;	KEY = 1-n Key press
;
ScanKey:
;ROW0
	MOV	KeyRow,#00H	;KeyRow = 0
	MOV	P1,#10111111B	;Test Row0 P1.6 =0
	LCALL	CHKCOL		;Check Column at Row=0
	XRL	A,#00H		;Check Key Press
	JNZ	ScanKX		;Yes Calculate Key Code
;ROW1
	MOV	KeyRow,#01H	;KeyRow = 1
	MOV	P1,#11011111B	;Test Row0 P1.5 =0
	LCALL	CHKCOL		;Check Column at Row=1
	XRL	A,#00H		;Check Key Press       
	JNZ	ScanKX		;Yes Calculate Key Code

;ROW2
	MOV	KeyRow,#02H	;KeyRow = 2
	MOV	P1,#11101111B	;Test Row0 P1.4 =0
	LCALL	CHKCOL		;Check Column at Row=2
	XRL	A,#00H		;Check Key Press       
	JNZ	ScanKX		;Yes Calculate Key Code

;ROW3
	MOV	KeyRow,#03H	;KeyRow = 3
	MOV	P1,#11110111B	;Test Row0 P1.3 =0
	LCALL	CHKCOL		;Check Column at Row=3
	XRL	A,#00H		;Check Key Press       
	JNZ	ScanKX		;Yes Calculate Key Code

	MOV	Key,#00H	;Return 0 no Key Press
	RET

ScanKX:	
;Calculate Key Code
;KEY = (ROW*MAXCOL)+COL+1 when Key Code =1 to n
	MOV	A,KeyRow	;A=ROW
	MOV	B,#MAXCOL	;B=MAXCOL
	MUL	AB		;A = ROW*MAXCOL
	ADD	A,KeyCol	;A = (ROW*MAXCOL)+COL
	ADD	A,#01H		;A = (ROW*MAXCOL)+COL+1

	MOV	Key,A		;Save Result to A
	RET

;*** Check Column ***
;Scan Colume
;if Key Press
;	A=1;
;	KeyCol=Column
;	KeyRow=Row

CHKCOL:
	MOV	A,P1		;Read P1
	ANL	A,#KEYMARK	;Clear not use bit
	MOV	KeyBuff,A	;Save to KeyBuff
	XRL	A,#KEYMARK	;Compare with no Key Conts
	JZ	CHKCEX		;not Key Press Exit
	
	MOV	DPTR,#KDown	;Display Key Down
	LCALL	SendSROM

;Check Debounce
	MOV	R2,#10		;Wait for Read again
	LCALL	DMSEC

;Read Key again
	MOV	A,P1		;Read P1
	ANL	A,#KEYMARK	;Clear not use bit
	XRL	A,KeyBuff	;Compare with Old Key
	JNZ	CHKCEX		;Not same exit

;Release Key
CHKWT:	MOV	A,P1		;Read P1
	ANL	A,#KEYMARK	;Clear not use bit
	XRL	A,KeyBuff	;Compare with Old Key
	JZ	CHKWT

	MOV	DPTR,#KUp	;Display Key UP
	LCALL	SendSROM

;Get Key Code
	MOV	A,KeyBuff
	ANL	A,#KEYMARK	;Clear not use bit
	LCALL	SNDASCII
	MOV	A,#'H'
	LCALL	SBYTE
	MOV	A,#' '
	LCALL	SBYTE

;Get Column
	MOV	A,KeyBuff
	ANL	A,#KEYMARK	;Clear not use bit
	LCALL	GetColNo
	MOV	KeyCol,A	;Save Colunm

	MOV	A,#'('
	LCALL	SBYTE

	MOV	A,KeyCol	;Restore Column for print
	LCALL	SNDASCII

	MOV	A,#','
	LCALL	SBYTE

;Get Row
	MOV	A,KeyRow
	LCALL	SNDASCII

	MOV	A,#')'
	LCALL	SBYTE
	MOV	A,#'='
	LCALL	SBYTE

	MOV	A,#01H		;Key Press A=1
	RET

CHKCEX:	CLR	A		;No Key Press A=0
	RET

;*** Get Column in Count Number 0-n***
GetColNo:
	MOV	R2,#00H		;Start with 0
GCNX:	
	RRC	A		;Rotage A to Carry
	JNC	GCEXIT		;Test C=0 (Key Press)
	INC	R2		;Increment R2 
	SJMP	GCNX		; and Check nect bit

GCEXIT:
	MOV	A,R2		;Store R2 to A
	RET

;*** Send ASCII 2 Byte ***
;IN A
;REG R2,R3
SNDASCII:
	LCALL	HTOA
	MOV	A,R2
	LCALL	SBYTE
	MOV	A,R3
	LCALL	SBYTE
;	LCALL	LineFeed
	
	RET

;*** Send String in Program Memory ***
;Input 	DPTR
SendSROM:
	CLR	A
	MOVC	A,@A+DPTR	;load char
	JZ	EndStr		;yes end
	LCALL	SBYTE		;send 1	byte
	INC	DPTR		;point to next char
	SJMP	SendSROM		;load next char

EndStr:	RET

;*** Send String in RAM ***
;Input 	R0
SendSRAM:
	MOV	A,@R0
	XRL	A,#00
	JZ	EndRStr		;yes end
	MOV	A,@R0
	LCALL	SBYTE		;send 1	byte
	INC	R0		;point to next char
	SJMP	SendSRAM	;load next char

EndRStr:
	RET


;*** Initial UART ***
InitUART:
	MOV	SCON,#01010010B	;Set SCON Serial Control Mode 1: 8-bit UART (Timer-Based). 
	MOV	TMOD,#00100000B	;Set Mode 2  8-bit Auto-Reload
	MOV	TH1,#0FDH	;Set Baud Rate 9600
	SETB	TR1		;Enable Timer 1
	RET

; ********** SBYTE SUB **********
;SEND BYTE
;IN  =	A
;REG =	NO
SBYTE:	JNB	TI,SBYTE	;Wait For Sending done
	CLR	TI
	MOV	SBUF,A
	RET

; ********** RBYTE SUB **********
;OUT =	A
;REG =	A
RBYTE:	JNB	RI,RBYTE	;Wait For Receive already
	CLR	RI
	MOV	A,SBUF
	RET

;*** Send line feed ***
LineFeed:
	MOV	A,#0Dh
	LCALL	SBYTE
feed:	MOV	A,#0Ah
	LCALL	SBYTE
	RET

;*** HTOA SUB ***
;CONVERT HEX TO ASCII
;IN  = A
;OUT = R2,R3
;REG = A,R2,R3

HTOA:	PUSH	ACC
	SWAP	A
	LCALL	HTOAS
	MOV	R2,A
	POP	ACC
	LCALL	HTOAS
	MOV	R3,A
	RET

HTOAS:	ANL	A,#0FH
	CJNE	A,#0AH,$+3
	JNC	HTOAS1
	ORL	A,#30H
	RET
HTOAS1:	SUBB	A,#9
	ORL	A,#40H
	RET

;*** DMSEC SUB ***
;DELAY 1/1000 SECOND
;IN  = R2
;REG = R2,R3
DMSEC:   MOV    R3,#230
DMSEC1:  NOP
	 NOP
	 DJNZ   R3,DMSEC1
	 DJNZ   R2,DMSEC
	 RET


Hello:	DB	0DH,"*** KeyBoard ***",0DH,0AH,00
KDown:	DB	"KeyDown",00
KUp:	DB	",KeyUp   ",00

END
