title "Engine Fuel Monitor." subtitle "K. Grabe, Cork Ireland" __IDLOCS H'0007' ; PIC id equal to s/w revision. ;******************************************************************** ; ; Main.asm Engine Fuel Monitor main source file ; ; Revision History: ; V00 26 Jun 95 Initial ; v01 30 Jun 95 Math devide routine ; v02 ; v04 05 Jul 95 Devide fuel by 100 ; Reset counters on overflow ; v05 12 Jul 95 Fuel consumption rate display ; v06 13 Jul 95 MPG rate display, EE lib routines ; v07 18 Jul 95 Display fuel, dist >$FFFF using EE ; ; Read LCD_DATA inputs outside of read/write to display (use btfss and not ; full port read as this resets 4:7 mismatch) ; to do :speaker - drive from opposing outputs ; ;******************************************************************** LIST P=16C84, C=132, N=100, R=HEX, F=INHX8M ; (^^^^^ For Monaco font, size9, A4 @ 60%) #DEFINE RamStart h'0c' ; For '84 #DEFINE RamEnd h'2f' ; For '84 #DEFINE PAGE0 BCF STATUS, RP0 ; Page 0 #DEFINE PAGE1 BSF STATUS, RP0 ; Page 1 #DEFINE IntOn BSF INTCON, GIE ; Interrupts on #DEFINE IntOff BCF INTCON, GIE ; Interrupts off INCLUDE "P16CXX.INC" ;INCLUDE "P16CXXD.INC" __FUSES _CP_OFF&_WDT_ON&_XT_OSC&_PWRTE_ON INCLUDE MACROS.INC expand ; Macro expansion on or off ;************************************************************************* ; ; Constants ; ;************************************************************************* ;#DEFINE Debug ; No delay loops, Ports=ram for debug TRUE EQU 1 ; FALSE EQU 0 ; F_OSC EQU d'4000000' ; Oscillator frequency (timers etc) FuelRateTime equ d'2000' ; Time/ms that fuel rate counter runs MPG_RateAmount equ d'250' ; Number of fuel units to measure distance ; for instantaenous mpg readout ; ; LCD contstants ; LineEnd equ d'20' ; Where line one ends (8: LM020) LineLenght equ d'20' ; Total chars in a line FourBit EQU TRUE ; Selects 4- or 8-bit data transfers DataHi EQU FALSE ; If 4-bit transfers, Hi or Low nibble of PORT AboutDispTime EQU d'3' ; Time/sec about message is displayed ; LCD Display positions PowerUpPosn equ d'21' ; Power up conter message DistancePosn equ d'01' FuelPosn equ d'08' TimePosn equ d'15' MPGposn equ d'21' ; Bug in lcd.asm if 20 FuelRatePosn equ d'29' MPG_RatePosn equ d'36' ; Force lsd off screen page ;************************************************************************* ; ; RAM File Registers: ; ;************************************************************************* CBLOCK RamStart ; Begin data registers ; Wait10ms ; Interrupt Service I_W_S ; Interrupt W reg save I_S_S ; Interrupt STATUS reg save I_FSR_S ; Interrupt FSR reg save LastPB ; Need for <4:7> Port B interrupt TempB ; Save Port B reading ; Interrupt tick counters TICK_LO ; Interrupt Tick counter lo. Wraps at 9 TICK_HI ; ... hi. In milleseconds. Wraps at 99 TICK100 ; 1 = 100ms SECONDS ; Seconds counter SECONDS_H ; High seconds ; Interrupt sound Freq ; To store sound frequency value Freq_Cnt ; Counts down from Freq during interrupts ; Interrupt timers TMR_Flags ; Status Bits for timers - defined below: ; TMRA_LO ; Timer A - milliseconds ; TMRA_HI TMRB_LO ; Timer B - milliseconds. W_10ms TMRB_HI ; TMRC_LO ; Timer C - seconds ; TMRC_HI ; GLOBAL RAM for main Distance ; 16 bit Distance counter, lsb DistanceHi Fuel ; 16 bit Fuel counter, lsb FuelHi FuelRate ; Fuel rate counter MPG_Rate ; Intaneous MPG rate counter MPG_RateHi ; ... hi byte MPG_RateReset ; Counts fuel upto MPG_RateAmount ; Binary to BCD routines: ; count ; temp R0 ; Highest 2 display chars (one used) R1 ; Middle Scratch ; Scratch Register ; Wait_S, Warble, LCD driver Scratch1 ; Scratch Register L_byte ; H_byte ; Binary I/P R2 ; Lower 2 display chars ; LCD routines CHAR ; Save char/inst to print CHAR2 ; Save char to print TablePtr ; Table message pointer Cursor ; LCD Cursor Posn ; MsgLen ; Lenght of a table message ; WhichMsg ; Save message pointer (CenMsg) ; LCD_T2 ; Temp 4 bit xfer to port: Wh2LCDl ; LCD_T ; Reading busy flag: Busy_Q ENDC ; Re-use some of the ram ; LCD routines MsgLen equ CHAR ; Lenght of a table message WhichMsg equ CHAR2 ; Save message pointer (CenMsg) LCD_T2 EQU Scratch ; Temp 4 bit xfer to port: Wh2LCDl LCD_T EQU Scratch ; Reading busy flag: Busy_Q ; B2_BCD count equ Scratch temp equ CHAR2 ; Math routines RAM (some MUST be contigous memory): ACCaLO equ R0 ACCaHI equ R1 ACCbLO equ Scratch ; Result saved here ACCbHI equ Scratch1 ACCcLO equ L_byte ACCcHI equ H_byte ACCdLO equ R2 ACCdHI equ CHAR ;temp - see B2_BCD ; TMR_Flags: ;#define TMRA_EXP TMR_Flags, 0 ; 0 = timer A has expired. #define FuelIncEE TMR_Flags, 0 ; 1 = Increment Fuel EE data reg #define TMRB_EXP TMR_Flags, 1 ; 0 = timer B has expired. ;#define TMRC_EXP TMR_Flags, 2 ; 0 = timer B has expired. #define DistanceIncEE TMR_Flags, 2 ; 1 = Increment Distance EE data reg #define SecondsIncEE TMR_Flags, 3 ; 1 = Increment Seconds EE data reg #define Snd_On TMR_Flags, 4 ; 0 = Sound off. #define FuelRateMeasure TMR_Flags, 5 ; 1 = FuelRate counter incrementing #define MPG_RateMeasure TMR_Flags, 6 ; 1 = MPG_Rate counter incrementing #define HiFuelDistance TMR_Flags, 7 ; 1 = Fuel or Distance > $FFFF page ;************************************************************************* ; EE data File Registers: ;************************************************************************* CBLOCK d'0' ; Begin EE data registers PowerUpCount ; Number of time device powered up PowerUpCountHi ; ... Hi byte FuelEE ; Third most sig Fuel counter DistanceEE ; Third most sig Distance counter SecondsEE ; Highest seconds counter endc ; EEProm data area (PicStart doen't suppor this) ; ORG H'2100' ; DE "Automotive Fuel Monitor System KG, 1995" PAGE ; ;**************************************** ; I/O Port Usage * ;**************************************** ; ifdef Debug Port_1 equ h'2e' ; Use ram in debug mode Port_2 equ h'2f' else Port_1 equ PORTA Port_2 equ PORTB endif ; LCD data port LCD_DATA EQU Port_2 ; Connect to LCD data (4 or 8 pins) LCD_TRIS EQU Port_2 ; Change LCD_DATA i/o ; Lcd Control signals: LCD_CNTL EQU Port_1 #define LCD_E LCD_CNTL, 0 ; LCD 'E' stobe output #define LCD_RW LCD_CNTL, 1 ; LCD Hi = reading lcd data #define LCD_RS LCD_CNTL, 2 ; LCD Hi = data and not instructions #define SpeakerPos Port_1, 3 ; Speaker o/p (+ve) ;#define SpeakerNeg Port_1, 2 ; -ve of speaker if defined #define FuelSensor 7 ; Flow meter sensor, #define Odometer 6 ; Odomoter (from speedometer) #define EEclearButton 5 page ;************************************************************************* ; ; Start of code ; ;************************************************************************* ORG h'00' ; Reset 'vector' CALL INIT ; Initialise everything ; goto testing GOTO START ; Jump to start ORG h'04' ; Interrupt 'vector' GOTO S_INT ; Service Interrupt ; goto START include messages.asm ; Display message tables page ;******************************************************************** ; Start of code ;******************************************************************** START Tone d'5', d'10' call InitLCD ; Initialise the display call SplashAbout ; Display s/w info call ClearDispEE ; Clear EE Data ; Init HiFuelDistance flag CallW MovEEw, DistanceEE ; Get Hi EE byte of distance skpz ; 0, don't set flag bsf HiFuelDistance ; Use FuelEE, DistanceEE as hi bytes CallW MovEEw, FuelEE skpz bsf HiFuelDistance ; Use FuelEE, DistanceEE as hi bytes ;******************************************************************** ; Main Loop ;******************************************************************** MainLoop clrwdt ; Also cleared in Wait routine Call DisplayDistance ; Display cumulative distance Call DisplayFuel ; Display cumulated Fuel Call DisplayTime ; Display elapsed time CallW PosCurs, MPGposn ; Position LCD Cursor Call PrintMPG ; Calculate and print MPG call HandleFuelRate ; Check/Print fuel rate counter call HandleMPG_Rate ; Check/print mpg rate counter call HandleEECounters ; Increment EE counters if required ; (Fuel, Distance and Seconds) call HandleButtons ; Check/process any buttons pressed goto MainLoop page ;******************************************************************** ; ; Included Subroutine modules: include library.asm ; General purpose routines page include LCD.ASM ; LCD driver page include dbl_divs.asm ; MChip devision routines page include EELIB.ASM ; Data eeprom library routines PAGE ;************************************************************************* ; Application Specific Subroutines ;************************************************************************* ; Get Distance counters (DistanceEE, DistanceHi, Distance) ; If DistanceEE >0 then use DistanceEE and DistanceHI ; else use DistanceHi and Distance DisplayDistance CallW PosCurs, DistancePosn ; Position LCD Cursor btfsc HiFuelDistance goto DoHiDistance CallW PrintIntW, Distance ; Print journey elapsed distance return DoHiDistance CallW MovEEw, DistanceEE ; Get Hi EE byte of distance movwf H_byte MOVSD DistanceHi, L_byte ; Get 'lo' byte Call PrintInt return ; Get and display Fuel ; If FuelEE > 0 then Use FuelEE and FuelHi ; else use FuelHi and Fuel DisplayFuel CallW PosCurs, FuelPosn ; Position LCD Cursor btfsc HiFuelDistance goto DoHiFuel CallW PrintIntW, Fuel ; Print journey elapsed fuel return DoHiFuel CallW MovEEw, FuelEE ; Get Hi EE of Fuel movwf H_byte MOVSD FuelHi, L_byte ; get 'lo'byte Call PrintInt return ; Get and display time DisplayTime CallW PosCurs, TimePosn ; Position LCD Cursor CallW PrintIntW, SECONDS ; Print journey time elapsed return ; HandleButtons ; Check if user pressed a button and process event if so HandleButtons btfsc Port_2, EEclearButton ; User requests EE data clear? return ; No button pressed CallW Wait_S, d'1' ; Wait a sec btfsc Port_2, EEclearButton return ; Failed to stay pressed goto ClearDispEE ; Cleare EE, except for PoerUPCount & display ClearDispEE CallW CenMsg, EECleared-TableStart CallW MovEEw, PowerUpCount ; Save PowerUpCount movwf Scratch call ClearEE ; Clear EE data bcf HiFuelDistance ; Use low fuel and dist words Movfw Scratch ; Retrieve power up counter Call MovwEE ; Save power up counter in EE call ClearHome Return ; HandleEECounters ; Check if Fuel, Distance or Seconds have rolled over $FFFF and if so ; increment associated EE counter. HandleEECounters btfss FuelIncEE ; Requst to increment EE counter? goto NotFuelEE CallW IncEEw, FuelEE ; Increment EE counter bcf FuelIncEE ; Clear increment request bsf HiFuelDistance ; Fuel or distance > $FFFF NotFuelEE btfss DistanceIncEE ; Requst to increment EE counter? goto NotDistanceEE CallW IncEEw, DistanceEE ; Increment EE counter bcf DistanceIncEE ; Clear increment request bsf HiFuelDistance ; Fuel or distance > $FFFF NotDistanceEE btfss SecondsIncEE ; Requst to increment EE counter? goto NotSecondsEE CallW IncEEw, SecondsEE ; Increment EE counter bcf SecondsIncEE ; Clear increment request NotSecondsEE return ; Display About message and number of times powered up. ; Increment number of times powered up (in EE data) SplashAbout CallW CenMsg, AboutMsg-TableStart CallW PosCurs, PowerUpPosn CallW DispMsg, PowerUPmsg-TableStart CallW IncEEw, PowerUpCount ; Increment power up counter skpz goto NoPwrHiInc CallW IncEEw, PowerUpCountHi ; Incremet Hi byte of pwr up cntr NoPwrHiInc CallW PrintEEintW, PowerUpCount CallW Wait_S, AboutDispTime ; Leave message on screen for a while call ClearHome ; Display EE counters CallW PosCurs, DistancePosn CallW MovEEw, DistanceEE call PrintWint CallW PosCurs, FuelPosn CallW MovEEw, FuelEE call PrintWint CallW PosCurs, TimePosn CallW MovEEw, SecondsEE call PrintWint CallW Wait_S, AboutDispTime call ClearHome return ; Clear Fuel and distance counters in RAM ClearCounters clrf Fuel clrf FuelHi clrf Distance clrf DistanceHi return ; HandleMPG_Rate ; Check if MPG_RateMeasure is off (finished) and if so print MPG_Rate, ; reset MPG_Rate and start measuring again. ; HandleMPG_Rate btfsc MPG_RateMeasure ; Leave if measurement in progress return CallW PosCurs, MPG_RatePosn CallW PrintIntW, MPG_Rate clrf MPG_Rate ; Start a new measurement clrf MPG_RateHi bsf MPG_RateMeasure ; Let new count betin return ; HandleFuelRate ; Check if fuel rate time is up (Timer B) and if so ; display FuelRate, clear it and restart Timer B HandleFuelRate btfsc TMRB_EXP ; Timer B running? return ; Yes so fuel rate still counting CallW PosCurs, FuelRatePosn ; Where to print bcf FuelRateMeasure ; Stop counting fuel rate movfw FuelRate call PrintWint ; Print as 3 digits MOVLF16 TMRB_LO, FuelRateTime ; Time that fuel rate counter runs clrf FuelRate ; Start again bsf TMRB_EXP ; Timer b running bsf FuelRateMeasure ; Start measuring fuel rate return ; PrintMPG ; Devide B/A with result in A ; (Distance/(Fuel/100)) ; Then print result on LCD ; if HiFuelDistance then ; FuelEE, FuelHi & DistanceEE DistanceHi ; else ; FuelHi & Fuel, DistanceHi & Distace ; PrintMPG btfsc HiFuelDistance ; Check if EE & Hi bytes to be used goto MpgHiBytes MOVSD16 Fuel, ACCbLO MOVLF16 ACCaLO, MPG_RateAmount Call D_divS ; Fuel/MPG_RateAmount in ACCb MOVSD16 ACCbLO, ACCaLO ; B->A MOVSD16 Distance, ACCbLO call D_divS ; Result: ACCb/ACCa, Remainder: ACCc CallW PrintIntW, ACCbLO return MpgHiBytes ; Use FuelEE, FuelHi etc MOVSD FuelHi, ACCbLO CallW MovEEw, FuelEE ; Get EE most significant byte movwf ACCbHI MOVLF16 ACCaLO, MPG_RateAmount ; Devide into fuel Call D_divS ; Fuel/MPG_RateAmount in ACCb (Hi EE bytes) MOVSD16 ACCbLO, ACCaLO ; B->A MOVSD DistanceHi, ACCbLO ; Get distance CallW MovEEw, DistanceEE ; Get distance EE most sig byte movwf ACCbHI call D_divS ; Devide Distance by Fuel CallW PrintIntW, ACCbLO ; Print result in ACCb return page ;************************************************************************* ; ; Service Interrupt ; Check RTCC overflow and check Timers (A), B, (C), sound ; Check if a Fuel or Distance pulse has occurred ;************************************************************************* S_INT MOVWF I_W_S ; Save w register MOVFF I_S_S, STATUS ; Save status reg (carry, z flags etc.) MOVFF I_FSR_S, FSR ; Save FSR reg bcf STATUS, RP0 ; Make sure we're in page 0 BTFSS INTCON, T0IF ; Check RTCC overflow GOTO NotRTCC ; RTCC has overflowed (10 KHz or 100 micro seconds intervals) bcf INTCON, T0IF ; Clear rtcc overflow interrupt MOVLF TMR0, h'ff' -d'100' -d'7' ; Leave 100 cycles to overflow ; (7 cycles to figure out it's rtcc) ; ** Here every 100 micro seconds ; Test Sound On bit BTFSC Snd_On call C_Snd ; Go check if speaker needs a toggle Do_Tic INCF TICK_LO,F MOVFW TICK_LO XORLW D'9' ; Tick_lo =9 then reset SKPZ GOTO FinishedRTCC ; End here this time ; ** Here every 1ms CLRF TICK_LO INCF TICK_HI,F ; 1 ms tick counter MOVFW TICK_HI XORLW D'99' ; Reset before 100 SKPZ goto LastTimers CLRF TICK_HI ; Here every 100ms INCF TICK100,f MOVFW TICK100 XORLW D'9' SKPZ goto LastTimers CLRF TICK100 ; Here every Second INCF SECONDS,F ; Here every second SKPNZ ; Check for overflow incf SECONDS_H, f ; Hi seconds counter skpnz bsf SecondsIncEE ; Request EE seconds increment ; Decrement timer c (seconds timer) if enabled and disable if expired ; BTFSC TMRC_EXP ; Is it enabled? ; CALL C_TMRC ; Check timer C LastTimers ; Decrement remaining enabled s/w timers, disable any that have expired ; BTFSC TMRA_EXP ; Is it enabled? ; CALL C_TMRA ; Check Timer A BTFSC TMRB_EXP ; Is it enabled? CALL C_TMRB ; Check timer B ; Continue servicing Interrupt FinishedRTCC NotRTCC ; Check Port_B 7:4 pin change btfss INTCON, RBIF ; Port B 4:7 Change? goto NotPortB ; Not port b interrupt movfw Port_2 ; Read the port to remove mismatch movwf TempB ; Save for next I_LastPB xorwf LastPB, f ; Find out which bits changed btfsc LastPB, FuelSensor ; Was fuel sensor pulse? call CountFuel ; Yes. btfsc LastPB, Odometer ; Was it speedometer? call CountDistance ; Yes. movfw TempB movwf LastPB ; Save for next interrupt bcf INTCON, RBIF ; Clear port B change interrupt ; Continue servicing Interrupt NotPortB ; btfss INTCON, INTF ; Check if INT (RB0) ; goto NotInt ; Not INT pin ; bcf INTCON, INTF ; Clear the interrupt ; goto $ ; ** INT not tested ** ; Exit service interrupt routine NotInt Int_Ex MOVFF FSR, I_FSR_S ; Restor FSR register MOVFF STATUS, I_S_S ; Restore Status register swapf I_W_S, f ; Swap to get ready for retrieve swapf I_W_S, w ; Retrieve without changing STATUS RETFIE ; CountFuel ; Fuel pulse has occurred so increment Fuel counter CountFuel btfss Port_2, FuelSensor ; Count only lo to hi transition return btfsc FuelRateMeasure ; Increment fuel rate counter? incf FuelRate, f ; Fuel rate counter incf MPG_RateReset,f ; Count fuel 'till MPG_RateAmount movfw MPG_RateReset xorlw MPG_RateAmount ; Test for end of measurment skpz ; Zero if equal goto ContinueFuelCount bcf MPG_RateMeasure ; Stop measuring mpg rate clrf MPG_RateReset ; Reset fuel counter ContinueFuelCount incf Fuel, f ; Fuel consumed counter skpz return incf FuelHi, f bnz ExitFuelCount ; Check for overflow ; Call ClearCounters bsf FuelIncEE ; Request EE fuel counter increment ExitFuelCount return ; CountDistance ; Distance pulse has occurred so increment Distance counter CountDistance btfss Port_2, Odometer ; Count only lo to hi transition return btfsc MPG_RateMeasure ; Are we measuring mpg rate? incf MPG_Rate,f ; Yes so increment skpnz incf MPG_RateHi, f ; .. and hi byte if needed incf Distance, f ; Total journey distance skpnz incf DistanceHi, f bnz ExitCountDistance ; Check for overflow ; Call ClearCounters bsf DistanceIncEE ; Request Distance EE increment ExitCountDistance return ; C_TMRA ; Decrement and Clear timer bit (TMRA_EXP) if it has expired ;C_TMRA ; MOVLW TMRA_LO ; 16 bit timer to decrement ; CALL Dec16W ; Decrement 16 bit timer ; SKPNZ ; Times out? ; BCF TMRA_EXP ; Timer rolled over so mark it expired ; RETURN ; C_TMRB ; Decrement and Clear timer bit if it has expired ; (used by W_10ms) C_TMRB MOVLW TMRB_LO ; 16 bit timer to decrement CALL Dec16W ; Decrement 16 bit timer SKPNZ ; Times out? BCF TMRB_EXP ; Timer rolled over so mark it expired RETURN ; C_TMRC ; Decrement and Clear timer bit if it has expired ;C_TMRC ; MOVLW TMRC_LO ; 16 bit timer to decrement ; CALL Dec16W ; Decrement 16 bit timer ; SKPNZ ; Times out? ; BCF TMRC_EXP ; Timer rolled over so mark it expired ; RETURN ; Toggle speaker at a rate depending on Freq file register C_Snd DECFSZ Freq_Cnt, f return Call TOGGLE ; Toggle Speaker movfw Freq movwf Freq_Cnt return PAGE ;************************************************************************* ; ; Initialise ports etc ; ;************************************************************************* INIT CALL ClearRam ; Clear all file registers ;*** Page 1 BSF STATUS, RP0 ; Page 1 ; Port A Tri-State: 0=Output MOVLW B'00000000' ; PortA MOVWF TRISA - H'80' ; I/O ; Port B tri-State: 0=Output MOVLW B'11110000' ; PortB MOVWF TRISB - H'80' ; I/O ; Port B pullups, BCF = Enable bcf OPTION_REG-H'80', NOT_RBPU ; Pullups for i/p's ; RTCC (TMR0) signal source, 1=RTCC external pin (BSF) BCF OPTION_REG-H'80', T0CS ; TMR0 internal ; Prescaler assignment, BSF = 1 = wdt: ; Assigning it to RTCC already causes a devide by 2 (if PS0..2 = 0) BSF OPTION_REG-H'80', PSA ; Prescaler ; Prescaler values: BSF OPTION_REG-H'80', PS0 BCF OPTION_REG-H'80', PS1 BSF OPTION_REG-H'80', PS2 ;*** Page 0 BCF STATUS, RP0 ; Back to page 0 MOVLW b'00000000' ; Turn o/p's off MOVWF Port_1 MOVWF Port_2 clrf INTCON ; Clear all interrupts ; Enable interrupts (BSF=on) BSF INTCON, GIE ; Global interupts BSF INTCON, T0IE ; RTCC interupts for TMR0 bsf INTCON, RBIE ; Port B 4:7 interrupt ; bcf INTCON, INTE ; INT on PORTB pin RB0 movfw Port_2 ; Read the port to remove mismatch movwf LastPB ; Init last port b read ; Init Timers CLRF TMR_Flags ; Pre-expire all timers RETURN DE "Karl Grabe, Kerry Pike, Cork Ireland" DE "Tel +353 21 284357" END