;Simple 'fuel gauge'
main:
SYMBOL Capacity = w0 ;Capacity holds battery capacity remaining in amp seconds (18.2 Ah max, due to 16 bit
limit)
SYMBOL Current = w1
SYMBOL Voltage = w2
SYMBOL DisplayCapacity = w3
SYMBOL DisplayCurrent = w4
SYMBOL Averagecurrent = w5
SYMBOL loopcounter = b12
startup:
;read value of Capacity stored in non-volatile memory
READ 0, WORD Capacity
;Read supply voltage (assumes divider of 120K and 10K, giving 1023 = 65V)
READADC10 1, Voltage
;Reset capacity to 10Ah (36,000 amp seconds) if reset button (which disconnects the voltage sense) is pressed at power on
IF Voltage < 50 THEN LET Capacity = 36000
ENDIF
;check for capacity over-range from misreading
IF Capacity >36000 THEN LET Capacity = 36000
ENDIF
;Wait for power to settle on power up for more accurate ADC readings and allow time for reset button to be released, 5 second delay
PAUSE 5000
mainloop:
;setloop time calibration output pulse high (use serial out pin for calibration pulse)
HIGH 0
;reset averagecurrent drawn over last second to zero
Averagecurrent = 0
measurementloop:
;take 100 measurements and sum the results to give amp seconds (mainloop time is 1 second)
FOR loopcounter = 1 TO 100
;Check for battery voltage below about 25V (indicating power going off) and not in reset mode, every 1/100 second
READADC10 1, Voltage
IF Voltage < 400 AND Voltage > 50 THEN GOTO poweroff
;Take current reading using voltage across controller shunt. A/D current reading is 321 for 50mV across 5mOhm shunt = 10 amps (~ 31mA
resolution)
READADC10 4, Current
;At this point Current can be any value between 0 and 1023 (~31.87A)
;divide current by 2 to remain within 16 bit limit during summation
Current = Current / 2
;At this point Current can be any value between 0 and 511 (for 0 to 31.87A)
;add current to averagecurrent over one second
Averagecurrent = Averagecurrent + Current
;Add loop delay time to make main loop execution 1 second
PAUSE 4
NEXT loopcounter
;At this point Averagecurrent can be any value between 0 and 51,100 (~31.87A)
backtomainloop:
;set loop time calibration output pulse low
LOW 0
;Add loop delay time to make main loop execution 1 second
PAUSE 70
;Divide Averagecurrent by 146 to convert to ~ 330 = 30A ~ full scale for Displaycurrent to drive current display mode
DisplayCurrent = Averagecurrent / 146
;Convert Averagecurrent to amp seconds, based on 1 second main loop time
Averagecurrent = Averagecurrent / 1603
;At this point Averagecurrent can be any value between 0 and 31
;Averagecurrent is in amp seconds and loop time is 1 sec, so each time around loop current x amp seconds are subtracted from capacity
Capacity = Capacity - Averagecurrent
;DisplayCapacity is used by PWM command in remaining capacity mode, where 330 equals full scale of 10Ah (36000 / 330 = 109)
DisplayCapacity = Capacity / 109
;Check for less than 10% battery capacity remaining and exit to low battery warning routine
IF Capacity < 3600 THEN GOTO batterylow
IF Capacity >=3600 THEN GOTO display
display:
;Mode switch takes pin 3 high or low, low = capacity remaining display, high = average current over last second display
;99 sets 10kHz on timer, max duty cycle range on PWM is 0 to 330 for 0 to 100% full scale on meter (400 gives overload indication)
;Check mode switch and output appropriate PWM stream to simple D/A that drives meter
IF PIN3 = 0 THEN PWMOUT 2, 99, DisplayCapacity ELSE PWMOUT 2, 99, DisplayCurrent
ENDIF
GOTO mainloop
batterylow:
;Set meter to overload display as a low battery warning (all bars flashing) when in capacity mode
IF PIN3 = 0 THEN PWMOUT 2, 99, 400 ELSE PWMOUT 2, 99, Displaycurrent
ENDIF
GOTO mainloop
poweroff:
;save value of Capacity in non-volatile storage for use on next power up
WRITE 0, WORD Capacity
END