;*********************************************************************
; DESCRIBTION :	THIS PROGRAM IS ROTATE RIGHT OF PCF8574 
; FILE NAME   : TWI_PCF8574A.ASM
; COMPILER    : SXA51
; SUPPORT     : AT89C5131
; DATE        : 7 August 2004
;*********************************************************************
;	DEFINE SFRs
;*********************************************************************
;-----------    OTHER SFRs ---------------
CKCON0          EQU     8FH

;-----------    TWI SFRs ---------------
SSCON           EQU     93H
SSCS            EQU     94H
SSDAT           EQU     95H
SSADR           EQU     96H

;-----------    INTERRUPT SFRs ---------------
IEN1            EQU     0B1H

;-----------    BAUDRATE GENERATOR SFRs ---------------
BRL             EQU     9AH
BDRCON          EQU     9BH 

;*********************************************************************
;	DEFINE BYTE SECTION
;*********************************************************************
;
SLAVE_ADR	EQU	21H
ADR_H		EQU	22H
ADR_L		EQU	23H
B_TWI_BUSY	EQU	25H	; BIT TYPE
TWI_DATA_I	EQU	26H
STOP_BACKUP	EQU	27H
TWI_DATA	EQU	28H
;*********************************************************************
;	DEFINE BIT SECTION
;*********************************************************************
RW		EQU	00H	; 0=WRITE, 1=READ  ; BIT TYPE
;*********************************************************************

		ORG	0000H		; Reset vector
START:		LJMP	BEGIN

;************************************************
;		INTERRUPT SECTION
;************************************************
		ORG	0043H
		LJMP	TWI_IT

;************************************************
		ORG	0100H
;*************************************************		
;		INITIALIZE PCF8574A
;*************************************************		
BEGIN:		ORL	CKCON0,#00000001B	; 6 CLK PERIOD/MACHINE
		ORL	SSCON,#01000000B	; enable TWI */
		ANL	SSCON,#01000100B	; 
		SETB	EA			; interrupt enable */
		ORL	IEN1,#02h		; enable TWI interrupt */
		CLR	B_TWI_BUSY
		MOV	TWI_DATA,#0FH		; data example to send */**
		MOV	ADR_H,#00H
		MOV	ADR_L,#00H
		MOV	STOP_BACKUP,#00H
		MOV	R0,#00H
		MOV	P0,#0FH

LOOP_W:		MOV	ACC,STOP_BACKUP		; FIND STOP BIT, IF '1' JUMP
		JB	ACC.4,CONT_W

		JB	B_TWI_BUSY,END_IF_W	; jump if b_TWI_busy bit = '1'*/
		MOV	ACC,SSCON
		JB	ACC.4,END_IF_W		; jump if acc.4 bit = '1' "STOP FLAG"
						; usually not jump*/
		SETB	B_TWI_BUSY		; flag busy =1 , now, I'm not Empty.*/
		MOV	SLAVE_ADR,#01110000B	; slave adresse example 
		CLR	RW			; 0= WRITE
		MOV	SSDAT,#00h		; clear buffer before sending data
		ORL	SSCON,#00100000B	; TWI start sending */ after that SI bit is set '1'
						; and  the status code in SSCS will be 08h.

		JMP	LOOP_W
; ************************************************
CONT_W:		MOV	STOP_BACKUP,#00H
		MOV	P0,#55H
		SJMP	$
END_IF_W:	JMP	LOOP_W

; ************************************************
;		INTERRUPT SERVICE ROUTINE
; ************************************************
TWI_IT:		MOV	R7,SSCS

; ************* TWI status tasking ***************
   
CASE_00:	CJNE	R7,#00h,CASE_08		; A start condition has been sent 
						; SLR+R/W are transmitted, ACK bit received
		CLR	B_TWI_BUSY		; TWI is free 
		ORL	SSCON,#10H		; SEND STOP
		LJMP	end_switch

CASE_08:	CJNE	R7,#08h,CASE_10		; A start condition has been sent
						; SLR+R/W are transmitted, ACK bit received  
		ANL	SSCON,#11011111B	; clear start condition 

; 		send slave adress and read/write bit 

		MOV	ACC,slave_adr
		MOV	C,RW
		MOV	ACC.0,C
		MOV	SSDAT,ACC
		LJMP	end_switch
		
CASE_10:	CJNE	R7,#10h,CASE_18		; A repeated start condition has been sent
						; SLR+R/W are transmitted, ACK bit received
		ANL	SSCON,#11011111B	; clear start condition 

;		send slave adress and read/write bit 

		MOV	ACC,slave_adr
		;=========
		SETB	RW
		;=========
		MOV	C,RW
		MOV	ACC.0,C
		MOV	SSDAT,ACC
		JMP	end_switch

CASE_18:	CJNE	R7,#18h,case_20		; SLR+W was transmitted, ACK bit received 

		ANL	SSCON,#11110111B	; clear SI 
		MOV	SSDAT,TWI_data		; Transmit data byte, ACK bit received 
		JMP	end_switch

CASE_20:	CJNE	R7,#20h,case_28		; SLR+W was transmitted, NOT ACK bit received 
		ORL	SSCON,#10h		; Transmit STOP
		CLR	b_TWI_busy		; TWI is free 
		JMP	end_switch

CASE_28:	CJNE	R7,#28h,case_30		; DATA was transmitted, ACK bit received
		;ANL	SSCON,#11110111B	; clear SI 
		ORL	SSCON,#10h		; send STOP 
		MOV	STOP_BACKUP,SSCON	; BACKUP
		CLR	b_TWI_busy		; TWI is free
		JMP	end_switch

CASE_30:	CJNE	R7,#30h,case_38		; DATA was transmitted, NOT ACK bit received 
		ORL	SSCON,#10h		; Transmit STOP 
		CLR	b_TWI_busy		; TWI is free
		JMP	end_switch

CASE_38:	CJNE	R7,#38h,case_40		; Arbitration lost in SLA+W or DATA. 
		ORL	SSCON,#10h		; Transmit STOP
		CLR	b_TWI_busy		; TWI is free 
		JMP	end_switch

CASE_40:	CJNE	R7,#40h,case_58		; As soon as, the DATA will move to SSDAT SFR.
		ANL	SSCON,#11110111B	; clear SI
S40:		MOV	ACC,SSCON
		JNB	ACC.3,S40		; JUMP IF SI = '0'
		MOV	TWI_DATA_I,SSDAT	; Master will send ACK or NACK to slave

		;================================
		;ORL SSCON,#00000100B		; set AA  */ SENT ACK
		ANL SSCON,#11111011B		; CLR AA  */ SENT NACK  ( DEFAULT USED )
		;================================
		LJMP	end_switch

CASE_58:	CJNE	R7,#58h,case_5X	
		ORL	SSCON,#00010000B	; send STOP 
		MOV	STOP_BACKUP,SSCON	; BACKUP
		CLR	b_TWI_busy		; TWI is free
		JMP	end_switch

CASE_5X:
end_switch:	ANL	SSCON,#11110111B	; clear SI flag 
		RETI

; ************************************************
;		DELAY   
; ************************************************
DELAY:		MOV	R7,#9
D1:		MOV	R6,#5
D2:		NOP
		NOP	
		DJNZ	R6,D2
		DJNZ	R7,D1
		RET

; ************************************************
;		DELAY 
; ************************************************
DELAYS:		MOV	R7,#25
D1S:		MOV	R6,#20
D2S:		NOP
		NOP	
		DJNZ	R6,D2S
		DJNZ	R7,D1S
		RET
		END


