;This code is for a fuel flow sensor calibrator. It was written to convert 
;the signal from a FloScan 20B fuel flow sensor to drive a Ford Tripminder
;trip computer. 
;
;When using a mechanical fuel pump with built-in vapor
;return, and the flow sensor on the suction side of the pump, the calibrator
;can be configured to subtract the bleed flow from the signal sent to the
;trip computer. Will only work with fixed orifice return, not for return-
;style pressure regulators.
;
;To configure the bleed return value, temporarily block fuel flow to the
;carburetor with the engine running then click the calibration button
;(pull GP0 low). The calibrator will measure the bleed flow then save the
;value to the EEPROM. GP0 becomes a low output while the calibration routine
;is running. With an LED for the pull-up on GP0, the LED will light during 
;the bleed calibration and go out when it is finished.
;
;If used without a vapor return, apply power to the calibrator but no flow
;sensor signal (key-on engine-off) then click the calibration button.
;
;Written by Brett Riggs (mrriggs), www.gofastforless.com




	list      p=12F675 
	#include <p12f675.inc> 
	errorlevel  -302               	; suppress message 302 from list file
	
	__CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT  

;### CALIBRATION CONSTANTS ###
#define	OutputConstH	0xEF		;OutputConst=(FFFFFF*PPGin)/PPGout
#define	OutputConstM	0xFF
#define OutputConstL	0xFF		;45000 ppg in, 48000 ppg out
;#############################

	cblock 0x20
WTEMP         	
STATUSTEMP									 
CountInL
CountInH
CountOutL
CountOutH
ClkInH	
BleedConstL
BleedConstH
Flags
X_var:3
Y_var:3
Z_var:3
counter
	endc

#define SIG_IN	GPIO,2 			;Signal Input from Flow Sensor
#define SIG_OUT	GPIO,4 			;Signal Output to Tripminder
#define Cal_Sw	GPIO,0 			;switch Input from calibration button
#define	InRise	Flags,0			;set high on rising edge of input signal
#define	No_Flow	Flags,1			;set high if output too low to count
#define	Is_Zero	Flags,2			;low if test not zero
#define	BANK1	banksel 0x80		;Select BANK1
#define	BANK0	banksel 0x00		;Select BANK0
#define ClkInL	TMR0		
#define	BleedL	0x00			;EEPROM address for BleedL
#define	BleedH	0x01			;EEPROM address for BleedH
	
;_________Reset__________________________
	ORG     0x000             	; processor reset vector
	nop				; Inserted For ICD2 Use
	goto    Init              	; go to beginning of program


;_________Interupt_______________________
	ORG     0x004       		;Interrupt vector location
Isr
	movwf   WTEMP         		;Save off current W register contents
	swapf	STATUS,w
	clrf	STATUS			;Force to page0
	movwf	STATUSTEMP									 
	
_Timer0Int
	btfss	INTCON,T0IF		;Is T0IF Set?
	goto	_GP2_INT		
	bcf	INTCON,T0IF		;Clear TMR0 Interrupt Flag
	incf	ClkInH,f
	bnz	_GP2_INT
	movlw	0xFF
	movwf	CountInL
	movwf	CountInH		;set to max value if overflow
	
_GP2_INT	
	btfss	INTCON,INTF		;Is INTF Set?
	goto	_Timer1Int		
	movf	ClkInL,w
	movwf	CountInL
	movf	ClkInH,w
	movwf	CountInH		;save clock count values
	btfsc	INTCON,T0IF		;check if overflow after interrupt
	incf	CountInH,f		;inc if ovflw, bug fix 477Hz crash
	clrf	ClkInL
	clrf	ClkInH			;clear clock counter
	bcf	INTCON,T0IF		;clear flag to prevent inc after clear
	bcf	INTCON,INTF		;clear INTF interrupt flag

_Timer1Int
	btfss	PIR1,TMR1IF		;Is TMR1IF Set?
	goto	_EndIsr			
	movf	CountOutL,w
	movwf	TMR1L
	movf	CountOutH,w
	movwf	TMR1H			;reset timer with new count
	bcf	PIR1,TMR1IF		;clear timer 1 interrupt flag
	btfsc	No_Flow
	goto	_EndIsr
	movlw	0x10
	xorwf	GPIO,f			;invert output pin
	
_EndIsr
	swapf	STATUSTEMP,w
	movwf	STATUS			;Restore STATUS
	swapf	WTEMP,f			  
	swapf	WTEMP,w			;Restore W without corrupting STATUS bits
	retfie                    	;Return from interrupt	


;_________Initialization___________________
Init	
	call    0x3FF      		; retrieve factory calibration value
					; comment instruction if using simulator
	BANK1					  
	movwf   OSCCAL      		; update register with factory cal value 
	BANK0
	clrf	GPIO			;Clear Port
	BANK1
	clrf	ANSEL			;PIC12F675 Only
	movlw	b'00000101'
	movwf	TRISIO			;Tri-State GP0 & GP2
	clrf	VRCON			;Vref Off
	BANK0				
	movlw	0x07		
	movwf	CMCON			;Comparator Off
	BANK1				
	movlw	b'10000010'	
	movwf	OPTION_REG		;TIMER0 Prescale 8:1
	movlw	b'01110000'
	movwf	INTCON			;disable/configure interrupts
	bsf	PIE1,TMR1IE		;Enable Tmr1 interrupt on rollover
	BANK0				
	movlw	b'00100001'
	movwf	T1CON			;TIMER1 Prescale 4:1
	clrf	ClkInL			;clear TMR0
	clrf	ClkInH
	clrf	CountOutL
	clrf	CountOutH
	movlw	0xFF
	movwf	CountInL
	movwf	CountInH		;set counters high
	BANK1
	movlw	BleedL
	movwf	EEADR
	bsf	EECON1,RD		;get BleedL from EEPROM
	movf	EEDATA,w
	movwf	BleedConstL		;set BleedL
	movlw	BleedH
	movwf	EEADR
	bsf	EECON1,RD		;get BleedH from EEPROM
	movf	EEDATA,w
	movwf	BleedConstH		;set BleedH

	bsf	INTCON,GIE		;enable interrupts


;___________Main Loop______________________
Main		
	BANK0
	btfss	Cal_Sw
	call	BleedCal		;call bleed calibration if switch pressed

	movlw	0xFF
	movwf	Z_var+2
	;movlw	0xFF
	movwf	Z_var+1
	;movlw	0xFF
	movwf	Z_var
	clrf	X_var+2
	movf	CountInH,w
	movwf	X_var+1
	movf	CountInL,w
	movwf	X_var
	call	Divide			;calculate input flow

	movf	BleedConstH,w
	subwf	Y_var+1,f		;subtract bleed flow
	bc	_not_over_1
	movlw	0x01
	subwf	Y_var+2,f	
	bnc	_no_Out			;jump if flow less than bleed
_not_over_1	
	movf	BleedConstL,w
	subwf	Y_var,f
	bc	_not_over_2
	movlw	0x01
	subwf	Y_var+1,f
	bc	_not_over_2
	movlw	0x01
	subwf	Y_var+2,f
	bnc	_no_Out			;jump if flow less than bleed
	
_not_over_2	
	bsf	Is_Zero 
	tstf	Y_var+2
	skpz	
	bcf	Is_Zero 
	tstf	Y_var+1
	skpz
	bcf	Is_Zero 
	tstf	Y_var
	skpz
	bcf	Is_Zero
	nop
	btfsc	Is_Zero
	goto	_no_Out			;jump if div by zero

	movlw	OutputConstH
	movwf	Z_var+2
	movlw	OutputConstM
	movwf	Z_var+1
	movlw	OutputConstL
	movwf	Z_var
	movf	Y_var+2,w
	movwf	X_var+2
	movf	Y_var+1,w
	movwf	X_var+1
	movf	Y_var,w
	movwf	X_var
	call	Divide			;calculate output period

;Removed div/2, set output prescale to 1/2 input prescale
;	clrc
;	rrf	Y_var+2,f
;	rrf	Y_var+1,f
;	rrf	Y_var,f			;divide by 2, 50% duty

	tstf	Y_var+2
	bnz	_no_Out			;jump if count exceeds 2 bytes

	tstf	Y_var+1
	bnz	_not_low		;jump if high byte > zero

	movlw	0x20
	subwf	Y_var,w
	bc	_not_low		;jump if count >= 32
	
	movlw	0x20
	movwf	Y_var			;set to 32 to prevent interrupt loop 

_not_low
	comf	Y_var+1,f
	comf	Y_var,f
	incf	Y_var,f
	skpnz	
	incf	Y_var+1,f		;negate value, clock counts up

	movf	Y_var,w
	movwf	CountOutL
	movf	Y_var+1,w
	movwf	CountOutH		;save new value for next count
		
	bcf	No_Flow			;clear flag to turn on output

	goto	Main

_no_Out	
	clrf	CountOutL
	clrf	CountOutH		;set new value to maximum
		
	bsf	No_Flow			;set flag to turn off output

	goto	Main
	

;__________Divide__________________________
	;Z_var/X_var=Y_var; zz_zz_zz / xx_xx_xx = yy_yy_yy
Divide	
	clrf	counter
	clrc
_dloop		
	rlf	X_var,f
	rlf	X_var+1,f
	rlf	X_var+2,f
	incf	counter,f
	bnc	_dloop
	rrf	X_var+2,f
	rrf	X_var+1,f
	rrf	X_var,f
	clrf	Y_var
	clrf	Y_var+1
	clrf	Y_var+2

_ddloop		
	tstf	counter
	bz	_ddone
	clrc
	rlf	Y_var,f
	rlf	Y_var+1,f
	rlf	Y_var+2,f
	movf	X_var+2,w
	subwf	Z_var+2,w
	bnc	_ddloop1
	movf	X_var+2,w
	subwf	Z_var+2,w
	bnz	_dfinish
_dequal	
	movf	X_var+1,w
	subwf	Z_var+1,w
	bnc	_ddloop1
	movf	X_var+1,w
	subwf	Z_var+1,w
	bnz	_dfinish
_equalx		
	movf	X_var,w
	subwf	Z_var,w
	bnc	_ddloop1
_dfinish	
	movf	X_var+2,w
	subwf	Z_var+2,f
	movf	X_var+1,w
	subwf	Z_var+1,f
	skpc
	decf	Z_var+2,f
	movf	X_var,w
	subwf	Z_var,f
	skpc
	decf	Z_var+1,f
	incf	Y_var,f
	skpnz
	incf	Y_var+1,f
	skpnz
	incf	Y_var+2,f

_ddloop1
	decf	counter,f
	clrc
	rrf	X_var+2,f
	rrf	X_var+1,f
	rrf	X_var,f
	goto	_ddloop

_ddone		
	return


;_________Bleed Calibration___________________
BleedCal
	BANK0	
	bcf	Cal_Sw
	BANK1
	bcf	TRISIO,0		;disable switch and turn on LED
	BANK0

	clrf	counter
	clrf	Y_var+2
	clrf	Y_var+1
	clrf	Y_var

_bl_loop
	comf	CountInH,w
	bnz	_not_stopped
	comf	CountInL,w
	skpnz				;if CountIn = FFFF
	goto	_no_flow		;then no bleed flow

_not_stopped
	btfsc	SIG_IN
	goto	_is_hi
	bcf	InRise			;clear rise flag 
	goto	_bl_loop		;and loop if sig low
_is_hi	btfsc	InRise
	goto	_bl_loop		;loop if not rising
	nop
	bsf	InRise			;set flag if rising

	movf	CountInH,w
	addwf	Y_var+1,f
	skpnc
	incf	Y_var+2,f
	movf	CountInL,w
	addwf	Y_var,f
	bnc	_done_add
	incf	Y_var+1,f
	skpnz
	incf	Y_var+2,f		;add CountIn to total
_done_add
	incfsz	counter,f		;inc counter
	goto	_bl_loop		;loop if no overflow

	movlw	0xFF
	movwf	Z_var+2
	movlw	0xFF
	movwf	Z_var+1
	movlw	0xFF
	movwf	Z_var
	clrf	X_var+2
	movf	Y_var+2,w		;shift right 1 byte, div by 256
	movwf	X_var+1
	movf	Y_var+1,w
	movwf	X_var
	call	Divide			;calculate input flow

	movf	Y_var+1,w
	movwf	BleedConstH
	movf	Y_var,w
	movwf	BleedConstL		;set bleed flow

	goto	_end_cal

_no_flow
	clrf	BleedConstL
	clrf	BleedConstH		
	
	movlw	0x4C
	movwf	Y_var+2
	clrf	Y_var+1
	clrf	Y_var

_db_loop
	decfsz	Y_var,f
	goto	_db_loop
	decfsz	Y_var+1,f
	goto	_db_loop
	decfsz	Y_var+2,f
	goto	_db_loop		;time delay

_end_cal
	bcf	INTCON,GIE		;disable interrupts
	
	BANK1
	movlw	BleedL
	movwf	EEADR
	movf	BleedConstL,w
	movwf	EEDATA
	bsf	EECON1,WREN
	movlw	0x55
	movwf	EECON2
	movlw	0xAA
	movwf	EECON2
	bsf	EECON1,WR		;write BleedL to EEPROM
	bcf	EECON1,WREN
_wrL1	btfsc	EECON1,WR
	goto	_wrL1			;loop until write complete
	
	movlw	BleedH
	movwf	EEADR
	movf	BleedConstH,w
	movwf	EEDATA
	bsf	EECON1,WREN
	movlw	0x55
	movwf	EECON2
	movlw	0xAA
	movwf	EECON2
	bsf	EECON1,WR		;write BleedH to EEPROM
	bcf	EECON1,WREN
_wrL2	btfsc	EECON1,WR
	goto	_wrL2			;loop until write complete

	movlw	BleedL
	movwf	EEADR
	bsf	EECON1,RD		;get BleedL from EEPROM
	movf	EEDATA,w
	xorwf	BleedConstL,w		;check saved BleedL
	bnz	_end_cal		;start over if error

	movlw	BleedH
	movwf	EEADR
	bsf	EECON1,RD		;get BleedH from EEPROM
	movf	EEDATA,w
	xorwf	BleedConstH,w		;check saved BleedH
	bnz	_end_cal		;start over if error

	bsf	INTCON,GIE		;enable interrupts

	bsf	TRISIO,0		;enable switch and turn off LED

	return	

	END

