;----------------------------------------------------------------------;
; bike3.asm Combines: Time , Dist, Av velocity, Inst Vel
; Fred Maher 1st March 2002
; BASIC BICYCLE COMPUTER WITH THESE FUNCTIONS
;----------------------------------------------------------------------;
; 1 Trip Time HRS:MIN:SEC
; 2 Trip Dist 000km 00m
; 3 Trip AvSpd 00.00km/hr
; 4 Speed 00.00km/hr
;---------------------------------------------------------------------
;------- HEADER ----------
;---------------------------------------------------------------------
; LCD MESSAGES
; position at beginning of 1st line col 0 movlw H'80
; position at beginning of second line movlw H'C0'
LIST P=16F84 ; 16F84 Runs at 4.096 MHz
INCLUDE "p16f84A.inc"
__CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON
ERRORLEVEL -224 ; suppress annoying message because of tris
ERRORLEVEL -302 ; suppress message because of page change
; Define Information
#DEFINE RS PORTA, 2
#DEFINE E PORTA, 3
;#DEFINE TOGGLESW PORTB, 6 ; not used at the moment
;#DEFINE LED PORTB, 5
; Macro
;---------------------------------------------------------------
CBLOCK 0CH ; 0C to 4F = 67
;---------------------------------------------------------------
; MATH ROUTINES
; 16 X16 Mult , --> 32
; mah mal x mbh mbl = mq4 mq3 mq2 mq1 ( mq4 highest)
mq4
mq3
mq2
mq1
mbh
mbl
mah
mal
; 16 / 16 Div --> 16
denlo
denhi
numlo
numhi
rmdrlo
rmdrhi
reshi
reslo
;temp also used in nybble
; Addition 16+16 out max 65536 (no carry)
; Subtraction q1_16-q2_16 out r_16; neg numbers not allowed
q1hi
q1lo
q2hi
q2lo
rhi
rlo
;------------ Distance -----------------------
dtotlo ; total trip distance in metres
dtothi ; dtothi/lo hold a max of 65km 536m,
dtothi2 ; with this added max now 16777km
dist54 ; corrects +2m every 54m (27x2.0747 =56)
dm
dm1000
dm10000
dm100000
;------------ Average velocity Vav -------------------
;vavhi
;vavlo
;divrat
;stemphi ;second info passed to stemphi/lo
;stemplo
;dtemphi ;dist info passed to dtemphi/lo
;dtemplo
m
m10
m100
m1000
;--------- Time and trip time --------------------
;
sectotlo ; total trip seconds
sectothi ; max 65536 = aprox 18hrs
sec ; seconds digit
sec10 ; 10's of second digit
min ; minutes digit
min10 ; 10's of minutes digit
hr ; hours digit
hr10 ; 10's of hours digit
oldsec ; holds last value of sec
cntmsec ; count ms
TMR18 ; TMR0 217* TMR18 18 = 1 SEC
;---- isr interrupt service routine push pop -------
w_temp ; W isr var
status_temp ; STATUS isr var
fsr_temp ; FSR isr var
; --------- Instantaneous Velocity Vin --------------------
vinhi
vinlo
sectemp
oldtemp
totmslo
totmshi
totms2lo
totms2hi
mshi
mslo
spdflg ; 1st pass =0 2nd pass =1, diff is time between pulses
;-------- Miscellaneous ------------------
temp ; a temporary used in divide and nybble
count
menu
ENDC ; end of definition block
;-------------------------------------------------------------------
ORG 0 ; start at location 0
goto main ; jump over to main routine
ORG 4
goto Isr ; jump to interrupt routine
;----------------------------------------------------------------------;
; The Main routine ;
;----------------------------------------------------------------------;
; -------- THE MAIN MODULES ---------
; Isr stores elapsed TRIP time and generates hr:min:sec
; Disptime TRIP time, to max 99:59:59
; Dist Calculates total TRIP distance
; Dispdist TRIP distance to a max of 999km 999m
; Velav Average velocity, Totdist/totsecs max 99km/hr
; Dispvav Average TRIP speed up to 99.99 km/hr
; Velocity Speed 2m/(time diff of pulse2-pulse1)
; Dispd Speed up to 99.99km/hr
; NOTE. Speed is your calculated velocity every second
; -------- more to come??? NO, running out of space ---------
;-----------------------------------------------------------------------
; M A I N
;-----------------------------------------------------------------------
main:
call Init ; Initialize ports, set up timer
call Initlcd ; Initialize the LCD DUMMY
Initend:
;------------------------------------------------------------------
; Changesec Changewhlpulse wait for interrupts newsec or newwheelpulse
; -----------------------------------------------------------------
clrf menu ; initially set to 0 menu loop
clrf spdflg ; Initially = 0 2nd = sub for time zero
; every new sec, set to zero
; CHANGESEC LOOPS TILL SEC CHANGES
;clrw ;DUMMY
;xorwf sec,w ;DUMMY
;btfsc STATUS,2 ;DUMMY
;incf sec,f ;DUMMY
Changesec: ;loops checking new sec and new wheel pulse
movf oldsec, w
xorwf sec,w
; if equal, w= 0 and Z bit=1
btfsc STATUS,2 ; test Z bit
goto Changesec ; no change, loop
movf sec,w ; sec has increased, update
movwf oldsec ; sec and oldsec are = again
incf menu,f ; increases menu every sec
; Note1, sectotlo/hi are updated every sec in ISR module
; Note2, Decimal time also created in ISR module
; but time display for LCD controlled
; the automatic menu below
call Disptime ;TRIP time, will appear on LCD top line
Changewhp: ; 1st detected wheelpulse starts menu sequence
clrf PORTB
bcf PORTB,5 ; start with green LED off
loop:
btfss PORTB, 4 ;(PUT BTFSC FOR TEST); i/p hi,?DUMMY
goto loop ; not yet
; i/p hi detected
;green LED flashes with every wheel pulse
bsf PORTB, 5 ; LED on
; wait a while to make sure switch has
; settled
movlw D'10' ; wait about 10 msec
call nmsec
btfsc PORTB, 4 ; will be lo (0) when finished
goto $ -1 ; still low
; now must wait a make sure bouncing stopped
movlw D'10' ; 10 milliseconds
call nmsec
; and check again
btfsc PORTB, 4 ; if set, not finished
goto $ -5 ; still hi start debounce wait again
Tp1: ; green LED ready for next wheel pulse
bcf PORTB,5 ; i.e. LED off
movf PORTB,w ; reading to clear
; AUTOMATIC MENU: (LCD Top line always time)
; --------------
; menu s at 10sec intervals in rotation
; Speed menu 1 to 10
; Dist ance menu 11 to 20
; Velav Avg vel menu 21 to 30
; MENU 0 TO 10
; as speed ( Speed) is stand alone, no sense in calculating it
; if it is not going to be displayed when menu is >10.
; BUT if SPEED AVERAGING IS TO BE USED, kill off the lines below that bypass
; the SPEED calc module
Menucheck:
movlw 0x0A ;check menu > 10 (to meet >10 AND =<20)
subwf menu,w
btfss STATUS,C ;compare with 10
goto $+2 ;menucount =< 10 not yet got to 11 jump to Speed
goto Distblk
call Speed ; Calculates instant speed,(time between pulses)
movlw 0x0A ; DUMMY, was movlw 0xA
subwf menu,w
btfss STATUS,C ;compare with 10
call Spdflgcheck ;menucount =< 10 ; also see 0-1 spdflg
goto Distblk
Spdflgcheck:
clrw
xorwf spdflg,w
btfsc STATUS,Z
call Dispd ;menucount =< 10 AND spdflg =1
Return
Distblk:
call Dist ;menucount > 10 skip Dispd update Dist
; MENU 11 TO 20
movlw 0x0A ;check menu > 10 (to meet >10 AND =<20)
subwf menu,w
btfss STATUS,C ;compare with 10
goto $+5 ;menucount =< 10 not yet got to 11 jump to velav
movlw 0x14
subwf menu,w
btfss STATUS,C ;compare with 20
call Dispdist ;menucount =< 20
call Velav ;menucount > 20 skip dispdist update Velav
; MENU 20 TO 30
movlw 0x14 ;check menu > 20 (to meet >20 AND =<30)
subwf menu,w
btfss STATUS,C ;compare with 20
goto $+5 ;menucount =< 20 not yet got to 21 jump to NEXT
movlw 0x1E
subwf menu,w
btfss STATUS,C ;compare with 30
call Dispvav ;menucount =< 30
movlw 0x1F ;if it has reached 31 reset menu, before return
xorwf menu,w
btfss STATUS,Z
goto $ +2 ; not 31 goto changewhp1 direct
clrf menu ; is 31, reset menu before changewhp1
Menuend:
; before changewhp jump, check that sec has not updated
; if it has , jump back to changesec routine
movf oldsec, w
xorwf sec,w ; if equal, w= 0 and Z bit=1
btfsc STATUS,2 ; test Z bit
goto Changewhp ; no sec change, check whpulse change
goto Changesec ; a new sec starts measurements
; loop while NOT newsec
; ---------------------------------------------------------------
; End Main
; ----------------------------------------------------------------
;----------------------------------------------------------------------;
; ISR, increments TMR0 by 1 every 256 ľsec. Basically just ;
; reset the INTCON and TMR0 bits. The FSR,w, STATUS push pop kept ;
;----------------------------------------------------------------------;
Isr:
movwf w_temp ; save W
swapf STATUS,W ; save status
movwf status_temp ; without changing flags
swapf FSR,W ; save FSR
movwf fsr_temp ; without changing flags
;256us * 217 * 18 = 0.999936 sec.
;1hr_err = 0.23sec or 1 sec in 4hr
;The time loop starts with TMR0 loaded with (256-217)=39 After 217
;steps interrupt is set, TMR0 rolls to zero and the TMR18 inc +1
movlw D'39' ;39 = 0x27
movwf TMR0
incf TMR18,f
movlw D'18' ; DUMMY18 = 0x12
xorwf TMR18,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto restore ; NOT 18 so pop stack and return to main
Firstsec:
clrf TMR18 ; is 18. set TMR18 to zero and INC sec
incf sec,f ; also inc sectot (eventually lo and hi)
incf sectotlo,f ; check sectot lo 00->inc hi
clrw
xorwf sectotlo,w ; if equal, w= 0 and Z bit=1
btfsc STATUS,2
incf sectothi,f ; increases every 256 x sectotlo
movlw 0xA ; check if =10
xorwf sec,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto restore ; NOT 10 so pop stack and return to main
clrf sec ; is 10. set sec to zero and inc sec10
incf sec10,f
movlw 0x6 ; = 0x6
xorwf sec10,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto restore ; NOT 6 so pop stack and return to main
clrf sec10 ; is 6. set sec10 to zero and INC min
incf min,f
movlw 0xA ; check if =10
xorwf min,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto restore ; NOT 10 so pop stack and return to main
clrf min ; is 10. set sec to zero and inc min10
incf min10,f
movlw 0x6 ;= 0x6
xorwf min10,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto restore ; NOT 6 so pop stack and return to main
clrf min10 ; is 6. set min10 to zero and INC hr
incf hr,f
movlw 0xA ;check if =10
xorwf hr,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto restore ; NOT 10 so pop stack and return to main
clrf hr ; is 10. set hr to zero and inc hr10
incf hr10,f
movlw 0xA ;= 10
xorwf hr10,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto restore ; NOT 10 so pop stack and return to main
clrf sec ; is ten (99hr 59min 59sec +1sec) we are at MAX
clrf sec10 ;all reset to zero and start again
clrf min
clrf min10
clrf hr
clrf hr10
clrf TMR18
clrf oldsec
goto restore
restore:
swapf status_temp,W ; get original status back
movwf STATUS ; into status register
swapf fsr_temp,W ; get original fsr back
movwf FSR ; into status register
swapf w_temp,f ; old no flags trick again
swapf w_temp,W ; to restore W
bcf INTCON,T0IF ; clear the TMR0 interrupt flag
retfie ; finished, reset GIE
;----------------------------------------------------------------------;
; Initialize the ports ;
;----------------------------------------------------------------------;
Init:
clrf PORTA
clrf PORTB
movlw B'00000000' ; Porta all outputs
tris PORTA
movlw B'01010000' ; 7o 6i-Wire 5o-LED 4i-multivib,
tris PORTB ; 0to3lcd
movlw B'00000111' ; opt pull-ups enabled
; opt prescaler assigned to TMR18
; opt prescaler set to 1:256
option ; opt rolls over each 125th second
movlw 0 ; zero out all registers
clrf m
clrf m10
clrf m100
clrf m1000
clrf dm
clrf dm1000
clrf dm10000
clrf dm100000
clrf totmshi
clrf totmslo
clrf totms2hi
clrf totms2lo
clrf dist54
clrf hr10
clrf hr
clrf min10
clrf min
clrf oldsec
clrf sec10
clrf sec
clrf sectotlo
clrf dtotlo
clrf dtothi
clrf sectotlo
clrf sectothi
clrf TMR18 ; when this reaches 18, 1 sec has elapsed
; TMR0 has to start at 256-217 :39, so that the first rollover
; with prescaler 256, happens in 217*256us =0.055552sec
; The TMR18 incs each roll and after 18 1 sec has elapsed
movlw 0x27 ; D39
movwf TMR0 ; set to D39 217 counts later 256,
; TMR0 resets and inc TMR18 in Isr loop
clrf INTCON ; START WITH ALL AT 0
; movlw B'10100000' ; GIE set T0IE set, T0IF cleared
movlw B'10100000' ; Set:GIE,T0IE,RBIE Clrd:T0IF,RBIF
movwf INTCON ; ready to detect interrupts in ISR
return
;----------------------------------------------------------------------;
; Initialize the LCD ;
;----------------------------------------------------------------------;
Initlcd:
movlw D'40'
call nmsec ; Wait 40 msecs before Reset
bcf RS ; send an 8 bit instruction
movlw 0x03 ; Reset Command
call NybbleOut ; Send the Nybble
call Dlay5 ; Wait 5 msecs before Sending Again
call EStrobe
call Dlay160 ; Wait 160 usecs before Sending 2nd Time
call EStrobe
call Dlay160 ; Wait 160 usecs before Sending 3rd Time
bcf RS ; send an 8 bit instruction
movlw 0x02 ; Set 4 Bit Mode
call NybbleOut
call Dlay160
movlw 0x028 ; 4 bit, 2 Line, 5x7 font
call SendINS
movlw 0x010 ; display shift off
call SendINS
movlw 0x001 ; Clear the Display RAM
call SendINS
call Dlay5 ; Note, Can take up to 4.1 msecs
movlw 0x006 ; increment cursor
call SendINS
movlw 0x00C ; display on cursor off
call SendINS
return
;----------------------------------------------------------------------;
; Send the character in W out to the LCD ;
;----------------------------------------------------------------------;
SendASCII
addlw '0' ; Send nbr as ASCII character
SendCHAR: ; Send the Character to the LCD
movwf temp ; Save the temporary Value
swapf temp, w ; Send the High Nybble
bsf RS ; RS = 1
call NybbleOut
movf temp, w ; Send the Low Nybble
bsf RS
call NybbleOut
return
;-------------------------------------------------------------
; ES strobe
;-------------------------------------------------------------
EStrobe: ; Strobe the "E" Bit
bsf E
bcf E
return
;----------------------------------------------------------------------;
; Send an instruction in W out to the LCD ;
;----------------------------------------------------------------------;
SendINS: ; Send the Instruction to the LCD
movwf temp ; Save w
swapf temp, w ; send Hi Nybble
bcf RS ; RS to 0
call NybbleOut
movf temp, w ; Send Lo Nybble
bcf RS
call NybbleOut
return
;----------------------------------------------------------------------;
; Send the nibble in W out to the LCD ;
;----------------------------------------------------------------------;
NybbleOut: ; Send a Nybble to the LCD
movwf PORTB
call EStrobe ; Strobe out the LCD Data
bsf E
call Dlay160 ; delay for 160 usec
return
;----------------------------------------------------------------------;
; Output the message on the LCD ;
;----------------------------------------------------------------------;
OutMessage1:
movwf FSR ; Point at first letter
OutLoop:
movf FSR, w ; Get pointer into W
incf FSR, f ; Set up for next letter
call Dispmsg1 ; Get character to output
iorlw 0 ; At the End of the Message?
btfsc STATUS, Z ; Skip if not at end
return ; Yes - Equal to Zero
call SendCHAR ; Output the ASCII Character
goto OutLoop ; Get the next character
;----------------------------------------------------------------------;
; Data for message to be output ;
;----------------------------------------------------------------------;
Dispmsg1: ; Message to Output
addwf PCL, f ; Output the Characters
dt "Bike Computer", 0
Dispmsg2: ; Message to Output
addwf PCL, f ; Output the Characters
dt "Dist", 0
Dispmsg3:
addwf PCL,f ; message to output
dt " Av speed:",0 ; output characters
;----------------------------------------------------------------------;
; time delay routines ;
;----------------------------------------------------------------------;
;Note . The original application needed precise times the delay code that
; follows. But the Simple Bike application does NOT use the routines for
; any CRITICAL time measurement.
Dlay160:
movlw D'41' ; delay about 160 usec
micro4:
addlw H'FF' ; subtract 1 'W'
btfss STATUS,Z ; skip when you reach zero
goto micro4 ; more loops
return
Dlay5:
movlw 5 ; delay for 5 milliseconds
goto $ + 2
msec250:
movlw D'250' ; delay for 250 milliseconds
; --- N millisecond delay routine ---
nmsec:
movwf cntmsec ; delay for N (you put in W) millisec
msecloop:
movlw D'254' ; load takes .9765625 microsec
call micro4 ; by itself CALL takes ...
; about 1ms
nop ; 1usec
decfsz cntmsec, f ; .98 skip not taken, else 1.95
goto msecloop ; 1.95 here: total ~1000 / loop
return ; final time through ~999 to here
; overhead in and out ignored
; this block is functional for tests, but not used in bike
Dlay1sec: ; this is a marker routine to see where
call msec250 ; the prg is at.
; bsf LED
call msec250 ;flash led on portb pin6
;bcf LED
call msec250
; bsf LED
call msec250 ; finishes with green led lit
return
;----------------------------------------------------------------------;
; Display the Time ;
;----------------------------------------------------------------------;
Disptime:
movlw H'80' ; position at beginning of first line
call SendINS
movf hr10, W ; tens of hours
call SendASCII
movf hr, W ; hours
call SendASCII
movlw ":"
call SendCHAR
movf min10, W ; tens of minutes
call SendASCII
movf min, W ; minutes
call SendASCII
movlw ":"
call SendCHAR
movf sec10, W ; tens of seconds
call SendASCII
movf sec, W ; seconds
call SendASCII
movlw " "
call SendCHAR ; the h m s really not needed
movlw "h"
call SendCHAR
movlw "m"
call SendCHAR
movlw "s"
call SendCHAR
movlw " "
call SendCHAR
Dispend:
RETURN
;----------------------------------------------------
; End of display time
;----------------------------------------------------
;----------------------------------------------------------------------;
; Display the Distance , (trip distance at moment) ;
;----------------------------------------------------------------------;
Dispdist:
movlw H'C0' ; position at beginning of second line
call SendINS
movf dm100000, W ; 0 of 065km 536m
call SendASCII
movf dm10000, W ; 6 of 065km 536m
call SendASCII
movf dm1000, W ; 5 of 065km 536m
call SendASCII
movlw "k" ; k of 065km 536m
call SendCHAR
movlw "m" ; m of 065km 536m
call SendCHAR
movlw " " ; " " of 065km 536m
call SendCHAR
movf
dm100,W ;
5 of 065km 536m
call SendASCII
movf
dm10,W ;
3 of 065km 536m
call SendASCII
movf dm, W ; 6 of 065km 536m
call SendASCII
movlw "m" ; m of 065km 536m
call SendCHAR
movlw " " ; " "
call SendCHAR
movlw "D" ; "D "
call SendCHAR
movlw "i" ; " i"
call SendCHAR
movlw "s" ; "s "
call SendCHAR
movlw "t" ; " t"
call SendCHAR
movlw " " ; " " ( to wipe screen)
call SendCHAR
Distend:
RETURN
;
;---------------------------------------------------------------------*
; Multiplication 16x16 Out32
;---------------------------------------------------------------------*
Mult16x16:
clrf mq4
clrf mq3
clrf mq2
clrf mq1
bsf mq2, 7
Mu1:
rrf mah, f
rrf mal, f
skpc
goto Mu2
movf mbl, w
addwf mq3, f
movf mbh, w
skpnc
incfsz mbh, w
addwf mq4, f
Mu2:
rrf mq4, f
rrf mq3, f
rrf mq2, f
rrf mq1, f
skpc
goto Mu1
Endmult16:
clrf mbh
clrf mbl
clrf mah
clrf mal
Return
;---------------------------------------------------------------------*
; End Multiplication 16x16 Out32
;---------------------------------------------------------------------*
;---------------------------------------------------------------------*
; New routine Division 16/16 Out 16
; ---------------------------------------------------------------------*
; Finally:- Result 000AH in reshi/lo, remainder 0096H in rmdrhi/lo
; so, checking end of division A=10 and 96H/E1H= 150/225 =0.666 OK
Div:
call D_divS ; remainder in Rmdr.
Divend:
nop
return
D_divS:
call setup
clrf rmdrhi
clrf rmdrlo
dloop:
bcf STATUS,C
rlf reslo, f
rlf reshi, f
rlf rmdrlo, f
rlf rmdrhi, f
movf denhi,w
subwf rmdrhi,w ;check if a>c
btfss STATUS,Z
goto nochk
movf denlo,w
subwf rmdrlo,w ;if msb equal then check lsb
nochk:
btfss STATUS,C ;carry set if c>a
goto nogo
movf denlo,w ;c-a into c
subwf rmdrlo, f
btfss STATUS,C
decf rmdrhi, f
movf denhi,w
subwf rmdrhi, f
bsf STATUS,C ;shift a 1 into b (result)
nogo:
rlf numlo,f
rlf numhi,f
decfsz temp, f ;loop untill all bits checked
goto dloop
setup:
movlw .16 ; for 16 shifts
movwf temp
movf numhi,w ;move Num to Res
movwf reshi
movf numlo,w
movwf reslo
clrf numhi
clrf numlo
retlw 0
;--------------------------End Div 16 by 16----------------------------
return
;---------------------------------------------------------------------*
; END DIVISION 16/16 OUT 16
;---------------------------------------------------------------
;---------------------------------------------------------------------*
; START Addition 16-16 OUT 16
;---------------------------------------------------------------
Add: ; R = q1 + q2
movf q1lo, W
addwf q2lo, W
movwf rlo
movf q1hi, W
btfsc STATUS, C
addlw .1 ; If A Carry Occurred, Add 1
addwf q2hi, W
movwf rhi
;clrf q1hi ; added this to stop next user summing;
;clrf q1lo
;clrf q2hi
;clrf q2lo
Return
;---------------------------------------------------------------------*
; END Addition 16-16 OUT 16
;---------------------------------------------------------------
;---------------------------------------------------------------------*
; START Subtraction 16-16 OUT 16
;---------------------------------------------------------------
Sub: ; R = q1 - q2
movf q2lo, W
subwf q1lo, W ; W = q1lo - q2lo
movwf rlo
btfss STATUS, C
Goto Borrow
Goto Sub1
Borrow:
Decf q1hi, F
Sub1:
movf q2hi, W
subwf q1hi, W ; W = q1hi - q2hi
movwf rhi
Return
;---------------------------------------------------------------
; END Subtraction 16-16 OUT 16
;---------------------------------------------------------------
;---------------------------------------------------------------
; Dist = counting wheel pulses
;---------------------------------------------------------------
Dist: ; whlcirc = 2.0747, for initial test =2
;
; movlw 0x2 ; <-- don't forget, this is just for 26"wheel
; movwf whlcirc ; start count at 0 and inc till same as whlcirc
; (range will be 1 to 4 m)
clrf count ; count can be 2 or 4 in this 26" case
Whloop: ; although the distance pulses ( in this example) jump in steps of 2m
; the m counter has to increase in 1's to catch the
; decimal rollover 10 to 0
; so count, here, is stepped 0 to 2 (whlcirc)
; Also, when the dist54 var increases 54m, COUNT adds an extra 2m
; to the hex and decimal totals, before resetting to zero.
; Note that as dist54 is in the loop it will also receive
; the 2m increase so it really counts to 56 (54 +2).
movlw 0x2 ; wheel circumference of 26 inch
xorwf count,w ; if equal, w= 0 and Z bit=1
btfsc STATUS,2 ; test Z bit
goto DistanceEnd ; they are the same, so jump distanceEnd and return
goto Mcount ; NOT yet = whlcirc, so inc mcount by 1 and return
Mcount: ; Distance to decimal for display , i/p m, o/p 000km 000m
; starts with m, m10, m100, m1000 , m10000, m100000 = 0
; Later correct m every 54m (add 2m ???? )
incf dm,f
movlw D'10'
xorwf dm,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto Mcountend ; NOT 0 so return
clrf dm
movlw D'10'
xorwf
dm10,w ;
if equal, w=
0 and Z bit=
1
btfss STATUS,2 ; test Z bit
goto Mcountend ; NOT 0 so return
movlw D'10'
xorwf
dm100,w ;
if equal, w=
0 and Z bit=
1
btfss STATUS,2 ; test Z bit
goto Mcountend ; NOT 0 so return
incf dm1000,f
movlw D'10'
xorwf dm1000,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto Mcountend ; NOT 0 so return
clrf dm1000
incf dm10000,f
movlw D'10'
xorwf dm10000,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto Mcountend ; NOT 0 so return
clrf dm10000
incf dm100000,f
movlw D'10'
xorwf dm100000,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto Mcountend ; NOT 0 so return
clrf dm ; is distmax, reset to 0
clrf dm1000
clrf dm10000
clrf dm100000
goto Mcountend ; see if whpl update is now finished
Mcountend: ;update the hex counters dtot /lo/hi/hi2
incf dtotlo,f
clrw
xorwf dtotlo,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto Dtotend ; dtotlo NOT 0
incf dtothi,f ; add 1, dtotlo is 0
clrw
xorwf dtothi,w ; if equal, w= 0 and Z bit=1
btfss STATUS,2 ; test Z bit
goto Dtotend ; dtothi NOT 0
incf dtothi2,f ; add 1, dtothi is 0
Dtotend:
movlw D'54'
movwf numhi ; not in use here, use to store 54
movf dist54,w
subwf numhi,w
btfsc STATUS,C
goto Noextra ; dist54=< 53, don't freeze COUNT
movlw D'56' ; dist54>53 add 2 extra counts
movwf numhi ; not in use here to store 56
movf dist54,w
subwf numhi,w
btfsc STATUS,C
goto Extra ; dist54=< 56, freeze COUNT
clrf dist54
goto Noextra
Noextra:
incf dist54,f
incf count,f
goto Whloop
Extra: ; an extra loop BUT count is NOT increased
incf dist54,f
goto Whloop
DistanceEnd: ; All conversion loops have executed and
; only left to display in decimal, when ed
;
return ; BACK TO MAIN
;--------------------------------------------------------------------------
; End of Trip Distance calculation Module
;--------------------------------------------------------------------------
;----------------------------------------------------------
; Calculate Average velocity Velav = totdist/totsec
;-----------------------------------------------------------
; 1st time round distto = 0 and sectot =0.
; Disttot lo/hi zero is prob OKbut test sec=0. If zero return
Velav:
clrw
xorwf sectotlo,w
btfss STATUS,Z
goto Spdstart ; not 0, onto Avspeed calc
clrw ; lo was 0, but hi byte may not be
xorwf sectothi,w
btfss STATUS,Z
goto Spdstart ; was not 0, onto Avspeed calc
;incf sectotlo,f ; DUMMY
;goto Spdstart ; DUMMY
return ; was also 0, abort module wait for sec inc
; to slow down the number of whpul in the test we add Dummies
Spdstart: ; for test delay incf sec and sectot, gives 7.2km/hr
;incf sec,f ; DUMMY
;incf sectotlo,f ; DUMMY
;Lpstart:
movlw 0x07 ; 1800 comp hi bytes
subwf dtothi,w
btfsc STATUS,C
goto Divratio ; dtothi is > 1800hi and needs dividing
; we suppose that the hibyte test is sufficient,
; it may not be true. e.g hi's the same but lo's diff
; pass dtot to m1000,m100
movf dtothi,w ; dtothi <1800
movwf m1000
movf dtotlo,w
movwf m100 ; m1000,m100 hold dtothi/lo ( no div needed)
movf sectothi,w
movwf m10
movf sectotlo,w
movwf m ; m10,m hold sectothi/lo ( no div needed)
; note, this is dtot to m1000,m100 not needing division
goto Ratend ; if divratio is needed, then m1000,m100 is used there
Divratio: ; enter variables and 1800
movf dtothi,w
movwf numhi
movf dtotlo,w
movwf numlo
movlw 0x07
movwf denhi
movlw 0x08
movwf denlo
call Div
incf reslo,w ; reslo holds INT of Divratio +1
movwf count ; not used at the moment
movf dtothi,w ; divide dtothi/lo by count
movwf numhi
movf dtotlo,w
movwf numlo
clrf denhi
movf count,w ; e.g. D 37
movwf denlo
call Div ; we need parking space for results, REuse the m1000 etc
movf reshi,w
movwf m1000 ;
movf reslo,w
movwf m100 ; m1000, m100 =dtot/count
; repeat for sectot
movf sectothi,w
movwf numhi
movf sectotlo,w
movwf numlo
clrf denhi
movf count,w ; e.g D 37
movwf denlo
call Div
movf reshi,w
movwf m10
movf reslo,w
movwf m ; m10, m =sectot/count
Ratend:
; WE CAN NOW DO DTOT/SECTOT x3.6 as we have SCALED TO AVOID OVERFLOW
; m1000,m100 x 36 (top line)
; Vav= ------------------------- = Average speed in km/hr
; m10,m x 10 (bottom line) ; 36(24H), 10(AH)
movf m1000,w ; MULT dtot, top line, by 24H
movwf mah
movf m100,w
movwf mal
clrf mbh
movlw 0x24
movwf mbl
call Mult16x16 ; ( store top line result in the same variables)
movf mq2,w
movwf m1000
movf mq1,w
movwf m100 ; dtot x 36
movf m10,w ; MULT sectot, bottom line, by AH
movwf mah
movf m,w
movwf mal
clrf mbh
movlw 0xA
movwf mbl
call Mult16x16 ; ( store bottom line result in the same variables)
movf mq2,w
movwf m10
movf mq1,w
movwf m ; sectot x 10
Tp3:
; As we are reusing variables, trying to show where the results to here are being held
; m1000,m100
; We now have as Average speed ----- --------- km/hr
; m10,m
;the AVERAGE SPEED AT LAST
movf m1000,w ; dtotx36/sectotx10
movwf numhi
movf m100,w
movwf numlo
movf m10,w
movwf denhi ; needed below for decimal place
movf m,w
movwf denlo ; needed below for decimal place
call Div
; denhi/lo can chanfge as the div routine reuses bits
; so we reestablish previous denom values before losing
movf m10,w
movwf denhi
movf m,w
movwf denlo ; we can now write over m and m10
movf reshi,w ;will be zero
;(bikes don't exceed 256km/hr normally)
movf reslo,w ; reuse variables m10 INT and later m FRAC
movwf m10 ;we have integer part of Vav Average speed
; rmdrhi/lo holds decimal fraction.we will only use 1 decimal place.
; so mult the rmdrhi,lo x10 before dividing by denhi/lo
movf rmdrhi,w ; mult top by 10
movwf mah
movf rmdrlo,w
movwf mal ; rmdr in tot storage
clrf mbh
movlw 0xA
movwf mbl
call Mult16x16 ; rmdrhi,lo x 10
; top line is now mq2,mq1 ( nothing in mq4,mq3)
; Bottom line..remember we already have loaded
; the denominator above which says
; " needed below for decimal place"
Tp4:
movf mq2,w ;rmdrhi,w
movwf numhi
movf mq1,w ;rmdrlo,w
movwf numlo
call Div ; div for the decimal( just 1 place), in reslo
; reshi,reslo holds decimal place results
; m10+m are av speed as INT+DEC but in hex
; now change to decimal.
; m10 and m are going to be wiped, but there is no
;divide routine so for INT +FRAC we use reshi reslo
movf m10,w
movwf reshi ; OK? yes reshi +reslo = INT+FRAC in hex, convert
Vavh2d:
clrf m
clrf m10
clrf count
Vavloh2d: ; m is 2nd dec, use m10
movf count,w
xorwf reslo,w
btfsc STATUS,Z
goto Vavloend
incf count,f
incf m10,f
movlw 0xA
xorwf m10,w
btfss STATUS,Z
goto Vavloh2d
clrf m10
incf m,f
goto Vavloh2d
Vavloend:
clrf m100
clrf m1000
clrf count
Vavhih2d:
movf count,w
xorwf reshi,w
btfsc STATUS,Z
goto Vavhiend
incf count,f
incf m100,f
movlw 0xA
xorwf m100,w
btfss STATUS,Z
goto Vavhih2d
clrf m100
incf m1000,f
goto Vavhih2d
Vavhiend: ; We have Vav as: INT m1000,m100 and FRAC m10,m with Frac
Vavend:
nop
return
;----------------------------------------------------------------------;
; Display the Average velocity ;
;----------------------------------------------------------------------;
Dispvav:
movlw H'C0' ; position at beginning of second line
call SendINS
movf m1000, W ; x0 tens of km
call SendASCII
movf m100,W ; 0x ones of km
call SendASCII
movlw "." ; "." punto decimal
call SendCHAR
movf m10,W ; "0.x0" decimal
call SendASCII
movf m, W ; "0.0x" decimal
call SendASCII
movlw "k" ; k
call SendCHAR
movlw "m" ; m
call SendCHAR
movlw "/" ; /
call SendCHAR
movlw "h" ; h
call SendCHAR
movlw "r" ; r
call SendCHAR
movlw " " ; " "
call SendCHAR
movlw "V" ; V
call SendCHAR
movlw "e" ; e
call SendCHAR
movlw "l" ; l
call SendCHAR
movlw "A" ; A
call SendCHAR
movlw "v" ; v
call SendCHAR
movlw "g" ; g
call SendCHAR
movlw " " ; " "
call SendCHAR
Dispvavend:
Return ; to change seconds for next second
;--------------END OF AV SPEED-------------------
; ---------------------------------------------------------------
; Instantaneous Speed
;-----------------------------------------------------------------
; Previous time values are subtracted the present
; sec, TMR18, TMR0 values.
; This time difference is the time between
; wheel pulses. This in turn for 26" wheel is a distance of 2.0747m
; is covered in totms
; ---------------------------------------------------------------
; Instantaneous Speed
;-----------------------------------------------------------------
; Note sec can only move between 0 and 9, 10 is a new 0
; We start by reading sec, TMR18, TMR0 TO GET START TIME
Speed:
Spdflg0: ; FIRST TIMEwith spdflg=0, second time with spdflg=1
; First time captures timezero 0 in ms in totms
clrw
xorwf spdflg,w
btfss STATUS ,Z
goto Spdflg1 ; spdflg is not 0, this is the second time
call Summs
movf mshi,w
movwf totmshi
movf mslo,w
movwf totmslo
incf spdflg,f ; (spdflg = 1 for SECOND TIME)
return ;jump back to main menu
Summs: ; this routine is common to the first and second time
movf sec,w ; spdflg = 0
movwf mbl ; sec can only be in range 0 to 9
clrf mbh
movlw 0x03 ; 1000 = 03E8
movwf mah
movlw 0xE8 ; 1000 = 03E8
movwf mal
call Mult16x16 ;
movf mq2,w ; hi byte
movwf mshi
movf mq1,w ; lo byte
movwf mslo
movf TMR18,w
movwf mal
clrf mah
movlw D'56'
movwf mbl
clrf mbh
call Mult16x16 ; after themult we add
movf mshi,w
movwf q1hi
movf mslo,w
movwf q1lo
movf mq2,w
movwf q2hi
movf mq1,w
movwf q2lo
call Add
movf rhi,w
movwf mshi
movf rlo,w
movwf mslo ; sum (sec +TMR18)
;TMR0 is a little more complex as we have to subtract39
; before we can calculate ms in TMR0
movf TMR0,w
movwf q1lo
clrf q1hi
movlw D'39'
movwf q2lo
clrf q2hi
call Sub
movf rlo, w
movwf numlo
clrf numhi
movlw 0x4
movwf denlo
clrf denhi
call Div
movf mshi,w
movwf q1hi
movf mslo,w
movwf q1lo
movf reshi,w
movwf q2hi
movf reslo,w
movwf q2lo
call Add
movf rhi,w
movwf mshi
movf rlo,w
movwf mslo ; ( SEC +TMR18+ TMR0) in ms mshi/lo
RETURN ; Summs
Summsend:
Spdflg1: ; SECOND TIME is with spdflg =1
; Second time captures timezero to 2nd Pulse
; in ms, store in totms2
; for test we add 250ms to simulate time between
; wheel pulses
; 250ms delay
;movlw D'63' ; DUMMY FOR TEST
;call nmsec ; DUMMY FOR TEST
call Summs
movf mshi,w ;
movwf totms2hi ;
movf mslo,w ;
movwf totms2lo ;
; totms2 should be larger than totms,however if totms2 has just rolled,
; then add 10000 to tot2
Testtot2:
movf totms2hi,w
subwf totmshi,w
btfss STATUS,C ;compare for greater
goto Diffms ;totms2 > totms no add 10000 needed
movlw 0xA ;totms2 < totms, add 10000, hex 2710
movlw 0x27
movwf q1hi
movlw 0x10
movwf q1lo
movf totms2hi,w
movwf q2hi
movf totms2lo,w
movwf q2lo
call Add ; tot2 +10000
movf rhi,w
movwf totms2hi
movf rlo,w
movwf totms2lo ; tot2 = tot2+10000
Diffms:
; sub (tot2-tot1)for time between wheel pulses
movf totms2hi,w ;
movwf q1hi
movf totms2lo,w
movwf q1lo
movf totmshi,w
movwf q2hi
movf totmslo,w
movwf q2lo
call Sub ; result is time diff, stored in rhi, rlo
tp2:
; we are almost ready to divide dist/time for speed
; complete equation is dist/time x3.6
; to avoid as far as possible fractions we multiply before divide
; but this time, better divide first.
; 2000 36 <--- this is more than 65536
; ---- x --------
; denhi/lo 10 ( denhi/lo is sub result rhi/lo)
; so we can divide by 10 and x by 36 ( always,)
; so top line is simply 7200.
; we finally have 7200/(denhi/lo) , SPEED IN HEX
movf rhi,w
movwf denhi
movf rlo,w
movwf denlo ; denom is time in hex
movlw 0x1C ; 7200, hex 1C20
movwf numhi
movlw 0x20 ; 7200, hex 1C20
movwf numlo
call Div
; the result , res, is more than 1
;and a remainder rmdr/den
;we now have 6 free variables
; mshi/lo for INT hex speed lo is enough
; totmshi/lo
; totms2hi/lo
;we will reuse to convert hex to decimal
movf reslo,w
movwf mshi ; INT part of hex speed ( hi, because FRAC will be in lo)
;we will only use 1 decimal of
;the hex speed remainder, so 1st rmdrx10
; so next calculation is
; 10 x rmdrhi/lo
; ---------------
; denhi/lo
movf rmdrhi,w
movwf mah
movf rmdrlo,w
movwf mal
clrf mbh
movlw 0x0A
movwf mbl
call Mult16x16 ;( ten times top)
movf mq2,w
movwf numhi
movf mq1,w
movwf numlo ; the den is previously loaded so divide for
; decimal part of speed ( still in hex)
call Div ; we only use 1 decimal, so just use lo of Div result
movf reslo,w
movwf mslo ; FRAC of speed in hex
; now convert speed to decimal form
; i.e. mshi, mslo --> 99.9 km/hr
Spdh2d:
clrf m
clrf m10
clrf m100
clrf m1000
clrf count
Spdlo:
movf count,w
xorwf mslo,w
btfsc STATUS,Z
goto Spdhicnt
incf count,f
incf m10,f
movlw 0xA
xorwf m10,w
btfss STATUS,Z
goto Spdlo
clrf m10
incf m,f
goto Spdlo
Spdhicnt:
clrf m100
clrf m1000
clrf count
Spdhi:
movf count,w
xorwf mshi,w
btfsc STATUS,Z
goto Spdhiend
incf count,f
incf m100,f
movlw 0xA
xorwf m100,w
btfss STATUS,Z
goto Spdhi
clrf m100
incf m1000,f
goto Spdhi
Spdhiend:; We have filled m1000,m100 with INT and m10,m with Frac, of Vin.
; Note we only need m10 ( 1 decimal place)
clrf spdflg ; reset to 0 for next pair of pulses
; incf spdflg,f ; (spdflg = 1 for SECOND TIME)
return
; ---------------------------------------------------------------**
; End of Instantaneous Speed
; ---------------------------------------------------------------**
Dispd:
;----------------------------------------------------------------------;
; Display the Instantaneous Speed (Speed) ;
;----------------------------------------------------------------------;
movlw H'C0' ; position at beginning of second line
call SendINS
movf m1000, W ; x0 tens of km
call SendASCII
movf m100,W ; 0x ones of km
call SendASCII
movlw "." ; "." punto decimal
call SendCHAR
movf m10,W ; "0.x0" decimal
call SendASCII
movf m, W ; "0.0x" decimal
call SendASCII
movlw "k" ; k
call SendCHAR
movlw "m" ; m
call SendCHAR
movlw "/" ; /
call SendCHAR
movlw "h" ; h
call SendCHAR
movlw "r" ; r
call SendCHAR
movlw " " ; " "
call SendCHAR
movlw "S" ; S
call SendCHAR
movlw "p" ; p
call SendCHAR
movlw "e" ; e
call SendCHAR
movlw "e" ; e
call SendCHAR
movlw "d" ; d
call SendCHAR
Dispdend:
Return ; to change seconds for next second
;--------------END OF Inst SPEED-------------------
end
;-----------------------------------------------------
; bike computer program end ....enjoy
;-----------------------------------------------------
; WORK IN HAND
; CLEAN UP SPEED, readout still a little jumpy,
; can try integrating but need more space. Next version
; Coventions used in the program text.
;Variables all small letters , exceptions, those defined
; by microchip. e.g. STATUS
;Labels: First letter always a Capital, exceptions imported
; routines
; Test points. These have a comment DUMMY, the value of the code
; has/had been changed for testing or simulating. If YOU want
;to polish these points should be useful for value changes
; example. In ISR the D'18' value to reach a sec is very slow.
;Use for test , say 2, and you get going about 10 times faster.
;Also LCD INIT: can be bypassed to debug quicker
;------------------------------------------------------------------------
; End of the Simple Bike Computer
;------------------------------------------------------------------------