;EXAM11
;DS1307
SDA		BIT	P1.0		; SDA I2C Bus
SCL		BIT	P1.1		; SCL I2C Bus

RTCID		EQU	11010000B 	; RTC Slave Address
FLAG		EQU	02FH		; User FLAG
I2CACK		BIT	FLAG.0		; Define I2C Acknowledge as bit
MAXBUFFER	EQU	8

	ORG	30H

SEC:	DS	1	;Seconds
MIN:	DS	1	;Minutes
HOUR:	DS	1	;Hours
DAY:	DS	1	;Day
DATE:	DS	1	;Date
MONTH:	DS	1	;Month
YEAR:	DS	1	;Year
CTRL:	DS	1	;Control Byte

I2CADR:	DS	1	;I2C Address
I2CDAT: DS	1	;I2C Data

REGADR:	DS	1
REGDAT:	DS	1
StrBuff:DS	1		;Restore char form RS232
buffer: DS      MAXBUFFER	;Command Buffer


	ORG	0000H		; Reset Vector

;*** Power up delay ***
;Wait for other Device
RES:	MOV	R2,#40H
RES1:	MOV	R3,#0
RES2:	DJNZ	R3,RES2
	DJNZ	R2,RES1

	SETB	SDA		; CLear I2C bus
	SETB	SCL

MAIN:	LCALL	InitUART	;Initial UART 9600,n,8,1 no parity

	MOV	DPTR,#Hello
	LCALL	SendSROM

ScanStr:
	MOV	R0,#buffer	;point to buffer
	LCALL	GetStr

	MOV	R0,#buffer	;load buffer Ptr
	LCALL	GetCmd		;found = 1...n
	JZ	ScanEx		; 0 = isn't Command

	MOV	StrBuff,A	;store result in StrBuff

;Check Command No.
;Check Command 1
	XRL	A,#01		;?Compare A=1
	JZ	Cmd1		;switch to x

;Check Command 2
	MOV	A,StrBuff	;Restore
	XRL	A,#02		;?Compare A=2
	JZ	Cmd2

;Check Command 2
	MOV	A,StrBuff	;Restore
	XRL	A,#03		;?Compare A=2
	JZ	Cmd3
	
	JMP	ScanStr

ScanEx:	MOV	DPTR,#ErrMsg1
	LCALL	SendSROM
	LCALL	LineFeed

	JMP	ScanStr
;Treat Command
Cmd1:	
	LCALL	LineFeed	
	MOV	R0,#buffer
	LCALL	Strlen
	XRL	A,#07h
	JNZ	Cmd1X
	
; Convert ASC to BCD
;Register Address
	MOV	A,buffer+2
	CLR	C
	SUBB	A,#30H
	SWAP	A
	MOV	REGADR,A

	MOV	A,buffer+3
	CLR	C
	SUBB	A,#30H
	ORL	A,REGADR
	MOV	REGADR,A
		;LCALL	SBYTEH

;Register Data
	MOV	A,buffer+5
	CLR	C
	SUBB	A,#30H
	SWAP	A
	MOV	REGDAT,A


	MOV	A,buffer+6
	CLR	C
	SUBB	A,#30H
	ORL	A,REGDAT
	MOV	REGDAT,A
		;LCALL	SBYTEH

	LCALL	RTCWB

	LCALL	LineFeed
	MOV	R0,#REGADR
	LCALL	DumpI

	SJMP	ScanStr

Cmd1X:	MOV	DPTR,#ErrMsg3
	LCALL	SendSROM
	SJMP	ScanStr

Cmd2:	
	LCALL	LineFeed
	LCALL	RDRTC		;Read RTC
	MOV	R0,#SEC
	LCALL	DumpI

	JMP	ScanStr

Cmd3:	MOV	SEC,#80H
	MOV	MIN,#00H
	MOV	HOUR,#00
	MOV	DATE,#01
	MOV	MONTH,#01
	MOV	YEAR,#00
	

	LCALL	LineFeed
	LCALL	RTCWR		;Write RTC

	LCALL	RDRTC		;Read RTC
	LCALL	DISPLAY
	;LCALL	LineFeed

	JMP	ScanStr




;*** Get String ***
;IN R0 pointer to String Buffer
;R3 count n of Str
;
GetStr:	MOV	R3,#0
GetSnx:	CLR	A
	LCALL	RBYTE		;READ -> A

	MOV	StrBuff,A	;Restore char in StrBuff

;check end of str
	XRL	A,#0Dh		;Carriage Return <CR>
	JZ	ChkStr

	MOV	A,StrBuff	;Restore char in StrBuff
	XRL	A,#0Ah		;line feed  LF
	JZ	ChkStr

	MOV	A,StrBuff	;Restore char in StrBuff
	XRL	A,#1Bh		;line feed  LF
	JZ	GetESC

	MOV	A,StrBuff	;Restore char in StrBuff
	LCALL	SBYTE		;A    -> Send ECho
	MOV	@R0,StrBuff	;store in buffer
	INC	R0		;next point
	INC	R3		;count str

;@Test buffer full
	MOV	A,R3
	XRL	A,#MAXBUFFER	;Compare with MAXBUFFER
	JZ	Sendfull	;>= MAXBUFFER

	SJMP	GetSnx
ChkStr:	MOV	A,R3
	JZ	GetDis
	MOV	@R0,#0		;end of String
	RET

;@
GetDis:
	LCALL	RDRTC		; Read RTC
	LCALL	DISPLAY
	MOV	R0,#buffer	;Point to buffer
	SJMP	GetStr

GetESC:
	MOV	DPTR,#Abortx
	LCALL	SendSROM
	MOV	R0,#buffer	;Point to buffer
	SJMP	GetStr


Sendfull:
	MOV	DPTR,#ErrMsg2
	LCALL	SendSROM
	MOV	R0,#buffer	;Point to buffer
	SJMP	GetStr

DISPLAY:
	MOV	A,DATE
	LCALL	SBYTEH
	MOV	A,#'/'
	LCALL	SBYTE
	MOV	A,MONTH
	LCALL	SBYTEH
	MOV	A,#'/'
	LCALL	SBYTE

	MOV	A,YEAR
	LCALL	SBYTEH
	MOV	A,#' '
	LCALL	SBYTE

	MOV	A,HOUR
	LCALL	SBYTEH
	MOV	A,#':'
	LCALL	SBYTE

	MOV	A,MIN
	LCALL	SBYTEH
	MOV	A,#':'
	LCALL	SBYTE

	MOV	A,SEC
	LCALL	SBYTEH

	LCALL	LineFeed
	
	RET


;*** Get Command ***
;R0    point to Str buffer
;DPTR  point to command
;R2    save
;R7    result
;return command in	A
;	found		1...n
;	not found	0
;
;REG change = R0,R2,R7
;
GetCmd:	MOV	R7,#01		;count
	MOV	A,R0		;save R0->R2
	MOV	R2,A		;Restore Ptr

	MOV	DPTR,#Command1
	LCALL	StrCmp
	JZ	CmdEQU		;A=0 Equ

;If not Equ next Cmp

	INC	R7		;inc result
	MOV	A,R2		;get ptr
	MOV	R0,A		;Reload	Ptr

	MOV	DPTR,#Command2
	LCALL	StrCmp
	JZ	CmdEQU


	INC	R7		;inc result
	MOV	A,R2		;get ptr
	MOV	R0,A		;Reload	Ptr

	MOV	DPTR,#Command3
	LCALL	StrCmp
	JZ	CmdEQU

;not found
	MOV	R7,#0		;result	is NULL

CmdEQU:	MOV	A,R7		;result	in R7
	RET

;StrCmp(@R0,DPTR);
;R0    point to Str buffer
;DPTR  point to command
;reg change  = R0,DPTR
;result in A  0   = Equ
;             FFh = nEqu
StrCmp:	CLR	A
	MOVC	A,@A+dptr
	JZ	StrEq		;end of	str
	XRL	A,@R0		;Compare A=@R0 ?
	JNZ	StrNEq
	       
	INC	R0		;next char in buffer
	INC	dptr		;next command
	JMP	StrCmp
	       
StrNEq:	MOV	A,#0FFh		;not equal
	RET    
StrEq:	CLR	A		;equal ret 0
	RET    


;*** I2C RTC Read***
RDRTC:	MOV	I2CADR,#RTCID	; Set RTC as I2C Write Slave
	LCALL	I2CSLAVE	; Connect Slave
	
	MOV	I2CDAT,#00H	;Set Slave Address 00H
	LCALL	I2CWrDat	;Write Data to Slave

	MOV	I2CADR,#RTCID+1	;Set RTC as I2C Read Slave
	LCALL	I2CSLAVE	;Connect Slave
	LCALL	I2CRdDat	;Read Data from Slave

	MOV	SEC,I2CDAT	;Read Data to SEC
	LCALL	I2CAckBit	;Send Acknowledge

	LCALL	I2CRdDat	;Read Data from Slave
	MOV	MIN,I2CDAT	;Read Data to MIN
	LCALL	I2CAckBit	;Send Acknowledge

	LCALL	I2CRdDat	;Read Data from Slave
	MOV	HOUR,I2CDAT	;Read Data to HOUR
	LCALL	I2CAckBit	;Send Acknowledge

	LCALL	I2CRdDat	;Read Data from Slave
	MOV	DAY,I2CDAT	;Read Data to DAY
	LCALL	I2CAckBit	;Send Acknowledge

	LCALL	I2CRdDat	;Read Data from Slave
	MOV	DATE,I2CDAT	;Read Data to DATE
	LCALL	I2CAckBit	;Send Acknowledge

	LCALL	I2CRdDat	;Read Data from Slave
	MOV	MONTH,I2CDAT	;Read Data to MONTH
	LCALL	I2CAckBit	;Send Acknowledge

	LCALL	I2CRdDat	;Read Data from Slave
	MOV	YEAR,I2CDAT	;Read Data to YEAR
	LCALL	I2CAckBit	;Send Acknowledge

	LCALL	I2CRdDat	;Read Data from Slave
	MOV	CTRL,I2CDAT	;Read Data to CTRL
	LCALL	I2CNackBit	;Send Not Acknowledge

	LCALL	I2CSTOP	;Send Stop Condition
	RET			;Return


;*** I2C RTC Write ***
RTCWR:	MOV	I2CADR,#RTCID	; Set RTC as I2C Write Slave
	LCALL	I2CSLAVE	; Connect Slave

	MOV	I2CDAT,#00H	; Set Slave Address 00H
	LCALL	I2CWrDat	; Write Data to Slave

	MOV	I2CDAT,SEC	; Write SEC to RTC
	LCALL	I2CWrDat

	MOV	I2CDAT,MIN	; Write MIN to RTC
	LCALL	I2CWrDat

	MOV	I2CDAT,HOUR	; Write HOUR to RTC
	LCALL	I2CWrDat;

	MOV	I2CDAT,DAY	; Write DAY to RTC
	LCALL	I2CWrDat;

	MOV	I2CDAT,DATE	; Write DATE to RTC
	LCALL	I2CWrDat;

	MOV	I2CDAT,MONTH	; Write MONTH to RTC
	LCALL	I2CWrDat;

	MOV	I2CDAT,YEAR	; Write YEAR to RTC
	LCALL	I2CWrDat;

	MOV	I2CDAT,CTRL ; Write CTRL to RTC
	LCALL	I2CWrDat;

	LCALL	I2CSTOP	; Send Stop Condition
	RET			; Return

;*** RTC write 1 Byte ***
;IN   REGADR=Address,REGDAT=DATA

RTCWB:	MOV	I2CADR,#RTCID	; Set RTC as I2C Write Slave
	LCALL	I2CSLAVE	; Connect Slave

	MOV	I2CDAT,REGADR	; Set Slave Address
	LCALL	I2CWrDat	; Write Data to Slave

	MOV	I2CDAT,REGDAT	; Set Slave Address
	LCALL	I2CWrDat	; Write Data to Slave


	LCALL	I2CSTOP	; Send Stop Condition
	RET			; Return

;*** I2C Data Write ***
; IN		I2CDAT
; REG:	R5

I2CWrDat:
	PUSH	ACC		;Push ACC.
	SETB	I2CACK		;Set ACK. bit
	MOV	A,I2CDAT	;Get Data
	MOV	R5,#008		;Set loop 8 times
I2CWrD1:RLC	A		;Rotate ACC. to Left with Carry
	MOV	SDA,C		;Move Carry Flag to SDA
	ACALL	I2CCLK		;Pulse I2C Clock
	DJNZ	R5,I2CWrD1	;Do until 8 times
	SETB	SDA		;Set SDA
	ACALL	I2CDELAY	;Delay
	SETB	SCL		;Set SCL
	ACALL	I2CDELAY	;Delay
	JB	SDA,I2CWrD2	;Check Acknowledge from Slave
	CLR	I2CACK		;Clear ACK. bit
I2CWrD2:CLR	SCL		;Clear SCL
	POP	ACC		;Pop ACC.
	RET			;Return

;*** I2C Data Read ***
; OUT	I2CDAT
; REG:	R5
I2CRdDat:
	PUSH	ACC		;Push ACC.
	CLR	A		;Clear ACC.
	MOV	R5,#08		;Set loop 8 times
I2CRdD1:ACALL	I2CDELAY	;Delay
	SETB	SCL		;Set SCL
	ACALL	I2CDELAY	;Delay
	MOV	C,SDA		;Get SDA to Carry Flag
	RLC	A		;Rotate ACC. to Left with Carry
	CLR	SCL		;Clear SCL
	DJNZ	R5,I2CRdD1	;Do until 8 times
	MOV	I2CDAT,A	;Move Data to I2CDAT
	POP	ACC		;Pop ACC.
	RET			;Return

;*** I2C Slave Connect ***
;IN		I2CADR
;OUT Flag:	I2CACK
;REG:	R5

I2CSLAVE:
	PUSH	ACC		;Push ACC.
	SETB	I2CACK		;Set ACK. bit
	MOV	A,I2CADR	;Get Slave Address
	ACALL	I2CSTART	;Send Start Condition
	MOV	R5,#008		;Set loop 8 times
I2CSLA1:RLC	A		;Rotate ACC. to Left with Carry
	MOV	SDA,C		;Move Carry Flag to SDA
	ACALL	I2CCLK		;Pulse I2C Clock
	DJNZ	R5,I2CSLA1	;Do until 8 times

	SETB	SDA		;Set SDA
	ACALL	I2CDELAY	;Delay
	SETB	SCL		;Set SCL
	ACALL	I2CDELAY	;Delay
	JB	SDA,I2CSLA2	;Check Acknowledge from Slave
	CLR	I2CACK		;Clear ACK.
I2CSLA2:CLR	SCL		;Clear SCL
	POP	ACC		;Pop ACC.
	RET			;Return

;*** I2C Start Condition ***
I2CSTART:
	JNB	SCL,I2CST1	;Check current SCL set?
	CLR	SCL		;Clear SCL

I2CST1:	SETB	SDA		;Set SDA
	SETB	SCL		;Set SCL

	ACALL	I2CDELAY	;Delay
	CLR	SDA		;Clear SDA during SCL set
	ACALL	I2CDELAY	;Delay
	CLR	SCL		;Clear SCL
	RET			;Return


;*** I2C Stop Condition ***

I2CSTOP:JNB	SCL,I2CSTP1	;Check current SCL set?
	CLR	SCL		;Clear SCL

I2CSTP1:CLR	SDA		;Clear SDA
	ACALL	I2CDELAY	;Delay
	SETB	SCL		;Set SCL
	ACALL	I2CDELAY	;Delay
	SETB	SDA		;Set SDA during SCL set
	RET			;Return

;*** I2C Clock ***
I2CCLK:	ACALL	I2CDELAY	;Pulse SCL
	SETB	SCL		
	ACALL	I2CDELAY	
	CLR	SCL		
	RET			;Return

;*** I2C Acknowledge***
I2CAckBit:
	CLR	SDA		;Clear SDA
	ACALL	I2CDELAY	;Delay
	ACALL	I2CCLK		;Pulse I2C Clock
	SETB	SDA
	RET			;Return

;*** I2C Not Acknowledge ***
I2CNackBit:
	SETB	SDA		;Set SDA
	ACALL	I2CDELAY	;Delay
	ACALL	I2CCLK		;Pulse I2C Clock
	SETB	SCL
	RET			;Return

;*** Dummy Delay time I2CDELAY, LCD_DELAY, 10m, 100m, 1s ***
I2CDELAY:	MOV	R6,#00CH	; Each loop = 50 us
I2C_DELAY_1:	NOP
		NOP
		DJNZ	R6,I2C_DELAY_1
		RET


DELAY_10ms:	MOV	R7,#010		;Do 10 times
DELAY_10ms_1:	MOV	R6,#0E6H	;Each loop = 1 ms
DELAY_10ms_2:	NOP
		NOP
		DJNZ	R6,DELAY_10ms_2
		DJNZ	R7,DELAY_10ms_1
		RET

DELAY_100ms:	MOV	R7,#100		;Do 100 times
DELAY_100ms_1:	MOV	R6,#0E6H	;Each loop = 1 ms
DELAY_100ms_2:	NOP
		NOP
		DJNZ	R6,DELAY_100ms_2
		DJNZ	R7,DELAY_100ms_1
		RET

DELAY_1s:	MOV	R5,#100		;Do 100 times
DELAY_1s_1:	ACALL	DELAY_10ms
		DJNZ	R5,DELAY_1s_1
		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
	LCALL	SBYTE		;send 1	byte
	INC	R0		;point to next char
	DJNZ	R7,SendSRAM
	;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

;*** DUMP table	in InternalRAM	8 Byte ***
;R0 Ptr	to table in internal RAM
;
;R0,R6,R7
DumpI:	MOV	A,R0
	MOV	R7,A		;store Ptr in R7

	MOV	R6,#8
Dumpx:	MOV	A,@R0
	LCALL	SBYTEH
	INC	R0

	MOV	A,#' '		;separate with ' '
	LCALL	SBYTE

	DJNZ	R6,Dumpx

	MOV	R6,#8
Dspc:	MOV	A,#' '		;separate with ' '
	LCALL	SBYTE
	DJNZ	R6,Dspc

	MOV	A,R7		;Restore Ptr
	MOV	R0,A
	MOV	R6,#8
DASC:	MOV	A,@R0
	MOV	R7,A
	SUBB	A,#' '
	JC	Dmark
	MOV	A,R7
	LCALL	SBYTE
	JMP	Dloop

Dmark:	MOV	A,#'.'
	LCALL	SBYTE

Dloop:	INC	R0
	DJNZ	R6,DASC

	LCALL	LineFeed
	RET
;*** Send line feed ***
LineFeed:
	MOV	A,#0Dh
	LCALL	SBYTE
feed:	MOV	A,#0Ah
	LCALL	SBYTE
	RET
; ********** SBYTEH SUB **********
; SEND 2 BYTE HEX FROM A
; IN  = A
; REG = A,R2,R3
SBYTEH:	LCALL	HTOA
	MOV	A,R2
	LCALL	SBYTE
	MOV	A,R3
	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

;*** String LEN ***
;IN R0
;OUT A
Strlen:	MOV	R2,#0

StrLNx:	MOV	A,@R0
	XRL	A,#0
	JZ	StrLEX
	INC	R0
	INC	R2
	SJMP	StrLNx

StrLEX:	MOV	A,R2
	RET

Hello:		DB	0DH,"*** RTC DS1307 ***",0DH,0AH,00
ErrMsg1:	DB	0Dh,0Ah,'Invalid Command',00
ErrMsg2:	DB	0Dh,0Ah,'buffer full',0Dh,0Ah,00
ErrMsg3:	DB	0Dh,0Ah,'Lenght Error',0Dh,0Ah,00
Abortx:		DB	0Dh,0Ah,'*** Abort ***',0Dh,0Ah,00

Command1:	DB	'w',00
Command2:	DB	'r',00
Command3:	DB	'x',00

	END
