;========================================================================
;Timer0 mode2 250us
;Int1 為下緣觸發,接收外部信號
;========================================================================
COUNT	EQU	20H		;計算掃描位元用
BUFFER	EQU	21H		;7-SEG 顯示用儲存區 21H~24H
TI_H	EQU	26H		;計算週期用,每1ms 加 1
TI_L	EQU	27H
RPM_H	EQU	28H		;儲存轉換完畢的轉速
RPM_L	EQU	29H
TIMES1	EQU	2AH		;決定掃描時間用(累計1ms)
NORPM	EQU	2BH		;無轉速

	ORG	00H
	JMP	START

	ORG	13H		;int1 中斷向量
	JMP	EXINT1		;啟動/停止 Counter0,換算為頻率

	ORG	0BH		;Timer0 中斷向量(25us)
	JMP	TIMER0
	
START:
	MOV	TMOD,#00010010B	;Counter/Timer模式控制器,Timer1 mode1,Timer0 mode2
	MOV	TCON,#00000100B	;Counter/Timer控制器,設定 Int1 為邊緣觸發
	MOV	IP,#00000100B	;中斷優先權控制器,設定 int1 優先
	MOV	IE,#10000110B	;中斷致能器,啟動 Int1,Timer0
	MOV	SP,#30H		;設定 SP 堆疊器從 40H 開始
	MOV	TH0,#(256-25)	;Time0 25us 發生一次中斷
	MOV	TL0,#(256-25)
	MOV	TH1,#0		;歸零 Counter1
	MOV	TL1,#0
	MOV	COUNT,#0	;初始每個暫存器
	MOV	BUFFER,#0
	MOV	BUFFER+1,#0
	MOV	BUFFER+2,#0
	MOV	BUFFER+3,#0
	MOV	TI_H,#0
	MOV	TI_L,#0
	MOV	RPM_H,#0
	MOV	RPM_L,#0
	MOV	TIMES1,#0
	MOV	NORPM,#0
	MOV	P1,#11111111B		;初始輸出
	MOV	P3,#11111111B
	SETB	TR0

LOOP:

	JMP	LOOP

;========= Timer0 中斷 =======================================
; 25us 一次,TIMES1計算是否要掃描(1ms),TI_HL計算累積的
; TR0 = 1 時 TI_HL 加 1
;=============================================================
TIMER0:				
	INC	TIMES1
	MOV	A,TIMES1
	CJNE	A,#40,TI_GO
	MOV	TIMES1,#0
	CALL	SCAN
TI_GO:
	JNB	TR1,TI_FINISH	;若 TR1 = 0(Timer1)則跳 TI_FINISH
	MOV	A,TI_L
	ADD	A,#1
	MOV	TI_L,A
	JNC	TI_FINISH	;C 等於 0 則跳(TI_H不加 1)
	ADDC	A,TI_H
	MOV	TI_H,A
	JNC	TI_FINISH
	INC	NORPM

TI_FINISH:
	RETI

;========== Int1 中斷 ============================================
; 高速 RPM (9999~916 RPM) 公式 = 60000000/THL1=03 93 87 00h/THL1
;=================================================================
EXINT1:
;	CPL	TR0		;啟動/關閉 TR1,要更換為 TCON
	CPL	TR1
	JNB	TR1,EXINT_FIN	; TR1 = 0 則跳, 作為啟動計時器用
	JB	TF1,LOW_SPEED	; TF1溢位,轉速LOW於 916 轉,跳到LOW速計算公式

;------------ 32 bit 除法器----------------------------------------
; subroutine UDIV32
; 32-Bit / 16-Bit to 32-Bit Quotient & Remainder Unsigned Divide
; input:    r3, r2, r1, r0 = Dividend X
;           r5, r4 = Divisor Y
; output:   r3, r2, r1, r0 = quotient Q of division Q = X / Y
;           r7, r6, r5, r4 = remainder
;------------------------------------------------------------------
	MOV	R3,#03H
	MOV	R2,#93H
	MOV	R1,#87H
	MOV	R0,#0H
	MOV	R5,TH1
	MOV	R4,TL1
	CALL	UDIV32

	MOV	RPM_H,R1	;只選擇低二位元(太高用不到,最高可得 65504 RPM)
	MOV	RPM_L,R0

	MOV	TH1,#0		;歸零 Counter1
	MOV	TL1,#0

	JMP	SCAN_1

LOW_SPEED:
	MOV	A,NORPM
	CJNE	A,#1,LOW_GO
	MOV	RPM_H,#0	;將輸出歸零
	MOV	RPM_L,#0
	MOV	TI_H,#0		;將LOW速計數器歸零
	MOV	TI_L,#0
	MOV	NORPM,#0
	JMP	SCAN_1
;========== LOW 速計算公式 ============================================
; LOW速 RPM (914~22 RPM) 公式 = 1500000/THL1=16 13 60h/THL1
;=================================================================
LOW_GO:
	MOV	R3,#00H
	MOV	R2,#16H
	MOV	R1,#13H
	MOV	R0,#60H
	MOV	R5,TI_H
	MOV	R4,TI_L
	CALL	UDIV32
	MOV	RPM_H,R1
	MOV	RPM_L,R0

	MOV	TI_H,#0		;歸零 TI_HL
	MOV	TI_L,#0

	JMP	SCAN_1

SCAN_1:
	MOV	R1,RPM_L
	MOV	R2,RPM_H
	CALL	HEXTODEC	;將16bit的轉速轉換為10bit,
				;Input => R2,R1
				;Output => R7,R6,R5,R4,R3
	MOV	BUFFER,R3	;個位數儲存區
	MOV	BUFFER+1,R4	;十位數
	MOV	BUFFER+2,R5	;百位數
	MOV	BUFFER+3,R6	;千位數
EXINT_FIN:
	RETI

SCAN:
	MOV	P3,#11111111B
	MOV	A,COUNT
	ADD	A,BUFFER
	MOV	R0,A
	MOV	A,@R0
	MOV	P1,A

	MOV	A,COUNT
	MOV	P3,A
	INC	COUNT
	MOV	A,COUNT
	CJNE	A,#4,SKIP
	MOV	COUNT,#0
SKIP:
	RET
	
;====================================================================
;	2 BYTE HEX TO 5 DIGITS BCD
; 149 cycles for 2 bytes,  77 cycles for 1 byte
; Input : R2,R1
; Output :R7,R6,R5,R4,R3
;=====================================================================
HEXTODEC:
	MOV	r1,#0AFH	; 175d
	MOV	r2,#91H		; 91AFH = 37295d
	MOV	R5,#0
	MOV	R6,#0
	MOV	R7,#0

	MOV	A,R1
	MOV	B,#10
	DIV	AB
	
	MOV	R3,B		; Lower byte, in R1, is transformed into 2 decade digits,
	MOV	R4,A		; it's OK that the higher one can be greater than 9

	MOV	A,R2		; Higher byte is in R2
	JZ	SPRING		; Spring over if 0
	MOV	B,#10
	DIV	AB

	MOV	R5,B		; Same as for lower byte
	MOV	R6,A

; Value in R5 is 256 times higher than value standing in R3, R4. Mply R5 with 6,
; add to R3, mply R5 with 5, add to R4, mply R5 with 2 and replace itself in R5

	MOV	R0,#05		; Point to R5
	ACALL	TRANSF		; Transform R5 to 3 lower positions

	INC	R0		; Repeat from R6, now all registers are 1 higher
	ACALL	TRANSF		; Transform R6 to 3 higher positions

SPRING:	MOV	R0,#03		; Point to lowest digit

; Adjust to decimal, everything higher than 9 should be, as 1 tenth, added to higher.
; Starting from the lowest digit, divide with 10, keep the rest, and add the 1/10th to
; first higher place (eg. 145, leave 5 and add 14 to the next higher)

	ACALL	DECADJ

	SJMP	$

TRANSF:	MOV	A,@R0
	MOV	B,#6
	MUL	AB
	DEC	R0
	DEC	R0
	ADD	A,@R0
	MOV	@R0,A

	INC	R0
	INC	R0
	MOV	A,@R0
	MOV	B,#5
	MUL	AB
	DEC	R0
	ADD	A,@R0
	MOV	@R0,A

	INC	R0
	MOV	A,@R0
	RL	A		; Mply with 2
	MOV	@R0,A

	RET

DECADJ:	MOV	A,@R0
DECLOP:	MOV	B,#10
	DIV	AB
	MOV	@R0,B
	INC	R0
	ADD	A,@R0
	MOV	@R0,A
	
	CJNE	R0,#7,DECLOP
	RET

;====================================================================
; subroutine UDIV32
; 32-Bit / 16-Bit to 32-Bit Quotient & Remainder Unsigned Divide
;
; input:    r3, r2, r1, r0 = Dividend X
;           r5, r4 = Divisor Y
;
; output:   r3, r2, r1, r0 = quotient Q of division Q = X / Y
;           r7, r6, r5, r4 = remainder
;;
; alters:   acc, flags
;====================================================================

UDIV32:        push    08              ; Save Register Bank 1
               push    09
               push    0AH
               push    0BH
               push    0CH
               push    0DH
               push    0EH
               push    0FH
               push    dpl
               push    dph
               push    B
               setb    RS0             ; Select Register Bank 1
               mov     r7, #0          ; clear partial remainder
               mov     r6, #0
               mov     r5, #0          
               mov     r4, #0
               mov     B, #32          ; set loop count

div_lp32:      clr     RS0             ; Select Register Bank 0
               clr     C               ; clear carry flag
               mov     a, r0           ; shift the highest bit of the
               rlc     a               ; dividend into...
               mov     r0, a
               mov     a, r1
               rlc     a
               mov     r1, a
               mov     a, r2
               rlc     a
               mov     r2, a
               mov     a, r3
               rlc     a
               mov     r3, a
               setb    RS0             ; Select Register Bank 1
               mov     a, r4           ; ... the lowest bit of the
               rlc     a               ; partial remainder
               mov     r4, a
               mov     a, r5
               rlc     a
               mov     r5, a
               mov     a, r6
               rlc     a
               mov     r6, a
               mov     a, r7
               rlc     a
               mov     r7, a
               mov     a, r4           ; trial subtract divisor from
               clr     C               ; partial remainder
               subb    a, 04
               mov     dpl, a
               mov     a, r5
               subb    a, 05
               mov     dph, a
               mov     a, r6
               subb    a, #0
               mov     06, a
               mov     a, r7
               subb    a, #0
               mov     07, a
               cpl     C               ; complement external borrow
               jnc     div_321         ; update partial remainder if
                                       ; borrow
               mov     r7, 07          ; update partial remainder
               mov     r6, 06
               mov     r5, dph
               mov     r4, dpl
div_321:       mov     a, r0           ; shift result bit into partial
               rlc     a               ; quotient
               mov     r0, a
               mov     a, r1
               rlc     a
               mov     r1, a
               mov     a, r2
               rlc     a
               mov     r2, a
               mov     a, r3
               rlc     a
               mov     r3, a
               djnz    B, div_lp32

               mov     07, r7          ; put remainder, saved before the
               mov     06, r6          ; last subtraction, in bank 0
               mov     05, r5
               mov     04, r4
               mov     03, r3          ; put quotient in bank 0
               mov     02, r2
               mov     01, r1
               mov     00, r0
               clr     RS0
               pop     B
               pop     dph
               pop     dpl
               pop     0FH             ; Retrieve Register Bank 1
               pop     0EH
               pop     0DH
               pop     0CH
               pop     0BH
               pop     0AH
               pop     09
               pop     08
               ret

	END
