;--------------------------------------------------------------------
; Main Program Starts Here!
;
Start:
clrf PORTA
clrf PORTB
bsf STATUS,RP0 ; bank 1
ifdef __16F88
movlw B'11101111' ; PortA directions (16F88)
movwf TRISA
movlw B'11000001' ; PortB directions (16F88)
movwf TRISB
movlw B'01100000' ; 4MHz internal osc (16F88)
movwf OSCCON
else
movlw B'11111111' ; PortA directions (16F870)
movwf TRISA
movlw B'00000000' ; PortB directions (16F870)
movwf TRISB
movlw B'11111111' ; PortC directions (16F870)
movwf TRISC
endif
movlw B'01010111' ; Weak pullups enabled, Timer0 src = clkout/256
movwf OPTION_REG
bcf STATUS,RP0 ; bank 0
; Set up Interrupts
clrf INTCON ; clear any pending ints
clrf PIR1
bsf INTCON,PEIE ; enable peripheral ints
bsf INTCON,GIE ; enable interrupts
; set up LCD Display
movlw 25 ; wait 500mS
call waitx20k
call LCDinit ; Set up the LCD display
call show_signon ; show signon message
movlw 50 ; wait 1 second
call waitx20k
; set up A/D convertor
bsf STATUS,RP0 ; bank 1
ifdef __16F88
movlw b'10110000' ; right-justify, ext vref (16F88)
movwf ADCON1
movlw b'00001111'
movwf ANSEL ; Analog inputs on RA0~RA3 (16F88)
else
movlw b'10001101' ; right-justify, ext vref, RA1/RA0 (16F870)
movwf ADCON1
endif
bcf STATUS,RP0 ; bank 0
movlw b'01000000' ; CLK/8
movwf ADCON0
; Start Timer0
movlw REFRESH_DELAY
movwf TMR0
; initialize variables
clrf Flags
clrf Flags2
movlw 0
movwf pagenum
clrf Page_Timer
clrf Blade_Timer
clr16 CCPR
clr16 Period
clr32 AmpSum
clr32 rpm
movlw 2
movwf NumBlades
; Set up CCP1 and Timer1 for rpm capture
clrf TMR1L
clrf TMR1H ; clear Timer1
movlw b'00100001'
movwf T1CON ; 4:1 prescaler, Timer1 ON
bcf PIR1,TMR1IF
bcf PIR1,CCP1IF ; clear Int flags
banksel PIE1
bsf PIE1,CCP1IE ; enable CCP1 Ints
bsf PIE1,TMR1IE ; enable TMR1 Ints
banksel 0
movlw b'00000111' ; capture every 16th leading edge
movwf CCP1CON ; enable Capture
ReadInputs:
clr16 Volts
clr16 Amps
clr16 Watts
movlw 64 ; 64 times oversampling
movwf Readings
NextRead:
movlw b'01000001' ; CLK/8, select RA0 (Volts), A/D on
movwf ADCON0
call wait100 ; wait 100uS to stabilize analog input
bsf ADCON0,GO_DONE ; start A/D conversion
waitv: btfsc ADCON0,GO_DONE
goto waitv ; wait until conversion Done
movf ADRESH,w
movwf Temp1
addwf Volts
bsf STATUS,RP0
movf ADRESL,w ; add 10 bit A/D result to Volts
bcf STATUS,RP0
movwf Temp2
addwf Volts+1
skpnc
incf Volts
bcf Flags,MAX_VOLTS
movf Temp1,w
xorlw b'00000011'
skpnz
bsf Flags,MAX_VOLTS ; Volts overloaded ?
movf Temp2,w
xorlw b'11111111'
skpz
bcf Flags,MAX_VOLTS
movlw b'01001001' ; CLK/8, select RA1 (Amps), A/D on
movwf ADCON0
call wait100 ; wait 100uS to stabilize analog input
bsf ADCON0,GO_DONE ; start A/D conversion
waita: btfsc ADCON0,GO_DONE
goto waita ; wait until conversion Done
movf ADRESH,w
movwf Temp1
addwf Amps
bsf STATUS,RP0
movf ADRESL,w ; get 10 bit A/D result
bcf STATUS,RP0
movwf Temp2
addwf Amps+1
skpnc
incf Amps
bcf Flags,MAX_AMPS
movf Temp1,w
xorlw b'00000011'
skpnz
bsf Flags,MAX_AMPS ; Amps overloaded ?
movf Temp2,w
xorlw b'11111111'
skpz
bcf Flags,MAX_AMPS
decfsz Readings
goto NextRead ; accumulate readings
clrc
rr16 Volts ; Volts / 2
movlw Volts
call Divx12 ; Volts / 12.8
movlw Amps
call Divx12 ; Amps / 12.8
btfsc Flags,GOT_ZERO ; have Amps been zeroed ?
goto sub_zero
get_zero:
mov16 Amps,ZeroAmps ; record zero Amps value
bsf Flags,GOT_ZERO
sub_zero:
bcf Flags,NEG_AMPS
sub16 ZeroAmps,Amps ; subtract zero value from Amps
skpnc
goto got_amps
bsf Flags,NEG_AMPS
com16 Amps ; Amps = -0 to -0.99
got_amps:
mov16 Amps,aa
mov16 Volts,bb
call Mult16 ; Watts = Volts * Amps
movi16 1000,aa
call Div32 ; Watts = Watts / 1000
subi16 500,bb
skpc ; remainder > 0.5 ?
goto store_watts
inc16 dd+2 ; yes, round up
store_watts:
mov16 dd+2,Watts
calc_Ah:
add1632 Amps,AmpSum ; AmpSum = accumulated Amps
mov32 AmpSum,dd
movi16 3600*3,aa ; 3 reads per second, 3600 seconds per hour
call Div32 ; AmpHours = AmpSum / (reads per hour)
store_Ah:
mov16 dd+2,AmpHours
; CCPR is a copy of the CCPR1 register. It is updated from the Interrupt
; routine. This may happen at any time, so we must prevent it from being
; updated while copying it. We cannot disable interrupts while copying
; because it could upset capture timing.
;
bsf Flags,LOCK_P ; lock CCPR
mov16 CCPR,Period ; get period (1/rpm)
bcf Flags,LOCK_P ; unlock CCPR
; reduce rpm jitter by averaging this and previous measurement
tst16 Period
skpz ; got good rpm ?
goto sp_good
clr16 OldPeriod ; no, old period = 0
goto sp_done
sp_good:
tst16 OldPeriod
skpnz ; got previous good rpm ?
goto sp_done ; no
mov1632 Period,dd
add1632 OldPeriod,dd
rr32 dd ; dd = (Period+OldPeriod)/2
mov16 Period,OldPeriod ; old period = current period
mov16 dd+2,Period ; Period now averaged
sp_done:
; show results on LCD screen
do_display:
movlw 6 ; 6 * 55.555mS = 3 readings per second
movwf ref_timer
display_page:
movlw 0
call Set_Cursor ; set cursor to start of line
movf pagenum,w
skpnz ; page 0 ?
goto page0
addlw -1
skpnz ; page 1 ?
goto page1
ifdef LCD8x2
; 8x2 or 16x1 display, 3 pages
addlw -1
skpnz ; page 2 ?
goto page2
page0: call Show_Volts
movlw LCDLINE2
call Set_Cursor ; "99.99V 99.99A"
call Show_Amps
goto ref_delay
page1: call Show_Watts ; "9999.9W 99.99Ah"
movlw LCDLINE2
call Show_AmpHours
goto ref_delay
page2: call Show_rpm
movlw LCDLINE2
call Set_Cursor ; "99999rpm x 9"
call Show_Blades
else
; 16x2 display, 2 pages
page0: call Show_Volts
call Show_Amps ; "99.99V 99.99A"
movlw LCDLINE2
call Set_Cursor
call Show_Watts
call Show_AmpHours ; "9999.9W 99.99Ah"
goto ref_delay
page1: call Show_Volts
call Show_Amps ; "99.99V 99.99A"
movlw LCDLINE2
call Set_Cursor
call Show_rpm ; "99999rpm x 9"
call Show_Blades
endif
; Wait 1/3 second (3 readings per second)
; Check buttons while waiting
ref_delay:
btfss INTCON,TMR0IF
goto ref_delay ; wait for Timer0 overflow (55.555mS)
movlw REFRESH_DELAY
addwf TMR0 ; recharge Timer0
bcf INTCON,TMR0IF
call page_button ; handle page button
call blade_button ; handle blades button
decfsz ref_timer
goto display_page ; 6 Timer0 overflows = 333.3mS (1/3 Second)
check_hold:
btfss HDBTN ; hold switch on ?
goto do_display ; yes, hold last readings
goto ReadInputs ; no, get new readings
END