

        $MOD51GB

        EOC     equ     P4.0
        SS      equ     P4.1
        MS      equ     P4.2
        RESET   equ     P4.3
        SCLK    equ     P4.4
        SDO     equ     P4.5
        POLL    equ     P4.6
        POW     equ     P4.7


	org	8000h

	setb	POW
        setb    POLL
	setb	SS
	setb	RESET
	setb	SCLK
	setb	SDO
	setb	EOC

        clr     POW             ;turn power on

        call   delay10         ;wait for it to stabalize

	clr	RESET		;reset compass

        call   delay10        ;wait 10msec

	setb	RESET		;clear reset

        call   lngDelay       ;wait .5secs

        setb    MS

ComRd:  call    Print
        db      '\n     Press the g key to get a compass heading\n',0,

start:  call    cin     
        cjne    A,#'g',start

        clr     POLL              ;clr POLL          

        call   delay10

        setb    POLL              ;set POLL

waitEOC: jnb    EOC, waitEOC    ;wait for EOC to reset

        call   delay10         ;wait >10msecs

	clr	SS		; set slave select for data recovery

        call   delay5         ;wait >5msecs

	mov	R5,#02
SDOrd:  mov     R6,#08

ReadSDO: clr    SCLK     
        call   clkdelay
	setb	SCLK
        mov     A, #020h          ;set A.5
	anl	A,P4		;compare A.3 with P4.3
	jz	zero		;jump if P4.3 is not set

	mov	A, R4		;load R4 into A
	setb	C		;set the carry bit
	rlc	A		;roll A left with carry
	mov	R4, A		;put contents of A back into R4
	ajmp	rdDone		; done with read
	
zero:	mov	A, R4		;load R4 into A
	clr	C		;clear the carry bit
	rlc	A		;roll A left with carry
	mov	R4, A		;put contents of A back into R4

rdDone: call   clkdelay                ;delay for low clock
	djnz	R6, ReadSDO

done8:	djnz	R5, hlfdelay	; Read second half of data 

	setb	SS		; Slave select off

        mov     DPH, R7
        mov     DPL, R4
        call    pint16u

        ljmp    ComRd


hlfdelay: call delay5         ;Wait >5msecs 
	mov	A, R4		;transfer MSB to R7
	mov	R7, A		;      "    "
        ljmp    SDOrd          ;Start next 8 bits

clkdelay: mov   R0,#073h
clk:	djnz	R0,clk
	ret

delay10: mov    R0,#025h
delay:	mov	R1,#0FFh
delay1:	djnz	R1, delay1		;wait >10 msec
	djnz	R0, delay
	ret

delay5: mov    R0,#012h
del:  mov     R1,#0FFh
del1: djnz    R1, del1              ;wait >5 msec
        djnz    R0, del
	ret



lngDelay: mov   R0,#00Ah
delay2:	mov	R1,#035h
delay3:	mov	R2,#0FFh
delay4:	djnz	R2, delay4		;wait >500msec
	djnz	R1, delay3
	djnz	R0, delay2
	ret


cin:    JNB     RI,$             ; WAIT FOR THE RI FLAG TO SET
        CLR     RI               ; CLEAR THE RECEIVE FLAG ONCE RECIEVED
        MOV     A,SBUF           ; PLACE RECEIVED BYTE IN REGISTER A
        RET



cout:   JNB     TI,$            ;Wait until transmission completed.
        CLR     TI              ;Clear interrupt flag.
	MOV     SBUF,A          ;Write out character.
        RET

PRINT:  PUSH    ACC      ; push the A and DPTR registers so their contents  
        PUSH    DPH      ; don't get lost in case they are being used
        PUSH    DPL      ; before calling this function. 

; move the stack pointer down low in order to pop the first string's byte
; address
        MOV     A,SP     
        ADD     A,#0FDH
        MOV     SP,A
        POP     DPH
        POP     DPL

; send (PRINT) the string back to the PC computer
READ_TX:
        CLR     A
        MOVC    A,@A+DPTR
        INC     DPTR             

        CJNE    A,#'\',SND

        CLR     A
        MOVC    A,@A+DPTR
        INC     DPTR             

        CJNE    A,#'n',SND

        MOV     A,#0DH
        ACALL   cout
        MOV     A,#0AH

SND:    ACALL   cout
        CJNE    A,#0,READ_TX

; place the new return addres in stack
        PUSH    DPL
        PUSH    DPH

; move the stack pointer up high in order to pop the A and DPTR registers 
        MOV     A,SP
        ADD     A,#3
        MOV     SP,A
        POP     DPL
        POP     DPH
        POP     ACC
        RET

UTIL_BINTOASC:  anl	a,#00fh 		; Keep Only Low Bits
		add	a,#090h 		; Add 144
		da	a			; Decimal Adjust
		addc	a,#040h 		; Add 64
		da	a			; Decimal Adjust
		ret				; Return To Caller

	;print 16 bit unsigned integer in DPTR, using base 10.
pint16u:	;warning, destroys r2, r3, r4, r5, psw.5
	push	acc
	mov	a, r0
	push	acc
	clr	psw.5
	mov	r2, dpl
	mov	r3, dph

pint16a:mov	r4, #16	;ten-thousands digit
	mov	r5, #39
	acall	pint16x
	jz	pint16b
	add	a, #'0'
	lcall	cout
	setb	psw.5

pint16b:mov	r4, #232	;thousands digit
	mov	r5, #3
	acall	pint16x
	jnz	pint16c
	jnb	psw.5, pint16d
pint16c:add	a, #'0'
	lcall	cout
	setb	psw.5

pint16d:mov	r4, #100	;hundreds digit
	mov	r5, #0
	acall	pint16x
	jnz	pint16e
	jnb	psw.5, pint16f
pint16e:add	a, #'0'
	lcall	cout
	setb	psw.5

pint16f:mov	a, r2		;tens digit
	mov	r3, b
	mov	b, #10
	div	ab
	jnz	pint16g
	jnb	psw.5, pint16h
pint16g:add	a, #'0'
	lcall	cout

pint16h:mov	a, b		;and finally the ones digit
	mov	b, r3
	add	a, #'0'
	lcall	cout

	pop	acc
	mov	r0, a
	pop	acc
	ret

;ok, it's a cpu hog and a nasty way to divide, but this code
;requires only 21 bytes!  Divides r2-r3 by r4-r5 and leaves
;quotient in r2-r3 and returns remainder in acc.  If Intel
;had made a proper divide, then this would be much easier.

pint16x:mov	r0, #0
pint16y:inc	r0
	clr	c
	mov	a, r2
	subb	a, r4
	mov	r2, a
	mov	a, r3
	subb	a, r5
	mov	r3, a
	jnc	pint16y
	dec	r0
	mov	a, r2
	add	a, r4
	mov	r2, a
	mov	a, r3
	addc	a, r5
	mov	r3, a
	mov	a, r0
	ret

        END
