This MPPT solar charge controller works for 12V panels approximately 120W and 24V panels about 240W. It includes Optimum Power Point Tracking (MPPT) and 3-stage battery charging. It functions with any specific 12V panel from 40W up to 120W (3.3-10A) which enables you to also run with 24V panels in the 80W to 240W range, together with a 24V battery.
Wouldn’t it be great if you could possibly hook up a solar panel (or panels) to a battery or two and let it rest at that? Regrettably, for most except the smallest solar panels, this could be an incredibly poor strategy. The battery is going to be overcharged on summery seasons and on overcast weeks the battery may well not charge in anyway, regardless that the panel could harvest power. So you have no preference - you absolutely need a charge controller.
This Charge Controller would work for charging Flooded Lead Acid, Gel-Cell (Sealed Lead Acid or SLA) and AGM (Absorbed Glass Mat) type batteries. Essentially, any battery employed in a solar technique needs to be a “deep discharge” type. Car batteries are not deep discharge categories which makes them not best suited.
The current/voltage waveform for a standard 120W solar panel. Maximum current, with the output shorted, is Isc and maximum voltage, with the output open circuit, is Voc. For better efficiency, the solar panel is applied at its maximum power point.
For loads which must run continuously to operate a certain system, a solar panel and charge controller is the sole approach. For this usage we advise, no less than, a 12V 40W solar panel with a 12V 12Ah SLA battery.
For continuous operations, the MPPT solar charger circuit could consume approximately about 200mA. Over a 24-hour period this results to 4.8Ah or 60Wh each day from the 12V battery. This implies in case a 40W panel produces optimal power for 1.5 hours or higher every day, this could be adequate for any relevant load to operate. In spite of this, if you happen to be worried about automatic running of bilge pumps etc, a 40W panel could possibly be the ideal choice. The motive we have stipulated a larger solar panel and battery than precisely required is twofold.
While Q1 is on, current (I1) passes through inductor L1 and into capacitor C2 and the battery. In case Q1 switches off, the stored energy in L1 is appllied to the battery by means of diode D2 (current path I2).
MPPT & charge optimisation
Considering the fact that the solar panel is installed horizontally, it is reasonably crucial that you absorb the maximum electricity as possible from it so this is where the Charge Controller’s MPPT (Maximum Power Point Tracking) makes its way in.
As demonstrated in Fig.1, for a standard solar panel subjected to maximum sunlight, the output stoves from optimum current while the output leads is shorted (Isc) to highest voltage while the output is open circuit (Voc). For a regular 120W 12V panel, Isc is 7.14A and Voc is 21.8V. However the optimum power from a 120W panel is at 6.74A and 17.8V that could be barely an ideal blend for a lead-acid battery.
If we were to link up that 120W solar panel straight away to the battery, the charge current is likely to be approximately 7.1A at 12V (85.2W), 7.05A at 13V (91.7W) and 7A at 14.4V (101W), ie, significantly less than the 120W offered by the solar panel at 17.8V.
By contrast, MPPT helps keeping the solar panel current and voltage at the maximum power point while charging the battery, granting that the battery voltage is below the solar panel voltage.
This is accomplished by a smart switchmode step-down voltage converter. To learn how this implements, check with the block diagram of Fig.2 below. Current from the solar panel streams by way of diode D1 and Mosfet Q1. When Q1 is on, current (I1) runs via inductor L1 into capacitor C2 and the battery. This gathers energy within the inductor’s magnetic field.
PCB design and track layout for the proposed MPPT soar charger circuit with 3 step charger
Programming source code for the proposed 12V/24V solar MPPT circuit using PIC16F88
; 100W MPPT Solar Charger
; upgraded with a supplementary bulk charge restart feature after a 4hr break when sunlight returns to panel
; Option set when RB0 low
; Supplementary bulk restart anytime power demanded for float charging. Option set when RB1 low
; Added switch to float mode if bulk charging takes less than 60s. ie if the battery is fully charged
list P=16F88
#include p16f88.inc
ERRORLEVEL -302
ERRORLEVEL -306
;Program Configuration Register 1
__CONFIG _CONFIG1, _CP_ALL & _CCP1_RB3 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_ON & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _INTRC_IO
;Program Configuration Register 2
__CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF
; Bank 0 RAM
DIGITAL equ H'20' ; storage
FIRST equ H'21' ; first run
CUT_M equ H'22' ; cutout voltage high byte
CUT_L equ H'23' ; cutout voltage low byte
FLOAT_H equ H'24' ; float voltage high byte
FLOAT_L equ H'25' ; float voltage low byte
COMP equ H'26' ; compensation (temperature)
BATT_HI equ H'27' ; battery volts high byte
BATT_LO equ H'28' ; battery low byte
DELCNT equ H'29' ; delay counter
FLASHER equ H'2A' ; LED flasher timer
TEMPERATURE equ H'2B' ; temperature reading deg C
THERMISTOR equ H'2C' ; thermistor flag for LED
CUT_COMP_M equ H'2D' ; cutout temp. compensated voltage high byte
CUT_COMP_L equ H'2E' ; cutout temp. compensated voltage low byte
FLOAT_COMP_M equ H'2F' ; float temp. compensated voltage high byte
FLOAT_COMP_L equ H'30' ; float temp. compensated voltage low byte
NEGATIVE equ H'31' ; subtract negative flag
VALUE_1 equ H'32' ; delay counter
VALUE_2 equ H'33' ; delay counter
HOUR0 equ H'34' ; hour counter
HOUR1 equ H'35' ; 14 seconds counter for hour counter (256 x 14s=1hour)
SENSOR_COUNT equ H'36' ; sensor counter for periodic checking
SENSOR_COUNT1 equ H'37' ; sensor counter for periodic checking
CELL_LO equ H'38' ; solar cell voltage ls byte
CELL_HI equ H'39' ; solar cell voltage ms byte
CELL_I_LO equ H'3A' ; solar cell current ls byte
CELL_I_HI equ H'3B' ; solar cell current ms byte
CHARGE_STATE equ H'3C' ; 0 charge, 1 float
CHARGE_FLAG equ H'3D' ; flag for charge
CHRG_RATE equ H'3E' ; charge change rate
CELL_V equ H'3F' ; solar cell voltage 8-bit
CELL_I equ H'40' ; solar cell current 8-bit
PERIOD equ H'41' ; power calculation rate
CCPR1_STORE equ H'42' ; CCPR1L storage value
POWERH equ H'43' ; power ms byte
POWERL equ H'44' ; power ls byte
VALUE1 equ H'45' ; temporary value
VALUE2 equ H'46' ; temporary value
VALUE3 equ H'47' ; temporary value
VALUE4 equ H'48' ; temporary value
EQ_FLAG equ H'49' ; equalisation flag
EQ_LO equ H'4A' ; ls byte EQ battery voltage
EQ_HI equ H'4B' ; ms byte EQ battery voltage
EQ_LO_COMP equ H'4C' ; ls byte temp. compensated EQ battery voltage
EQ_HI_COMP equ H'4D' ; ms byte temp. compensated EQ battery voltage
EQ_LEVEL equ H'4E' ; equalisation input (RB4) level store
BATT_IND equ H'4F' ; battery indicator flag when error
BURST_FLG equ H'50' ; burst flag
HOUR3 equ H'51' ; 4 hour counter
HOUR2 equ H'52' ; 56 seconds counter for hour counter (256 x 56s=1hour)
BULK_TIMER equ H'53' ; bulk charge timer (60s)
BULK_TIMER_END equ H'54' ; bulk timer ended flag
; math routines
TEMP1 equ H'5C'
TEMPB0 equ H'5D'
TEMPB1 equ H'5E'
TEMPB2 equ H'5F'
TEMP equ H'60'
REMB3 equ H'61'
REMB2 equ H'62'
REMB1 equ H'63'
REMB0 equ H'64'
AARGB5 equ H'65'
AARGB4 equ H'66'
AARGB3 equ H'67'
AARGB2 equ H'68'
AARGB1 equ H'69'
AARGB0 equ H'6A' ; most significant byte of argument A
BARGB3 equ H'6B'
BARGB2 equ H'6C'
BARGB1 equ H'6D'
BARGB0 equ H'6E' ; most significant byte of argument B
LOOPCOUNT equ H'6F' ; division counter
; All Banks RAM
; Interrupt store registers
W_TMP equ H'70' ; storage of w before interrupt
STATUS_TMP equ H'71' ; status storage before interrupt
; start at memory 0
org 0
goto SETUP
org 4
goto INTERRUPT
; position the lookup table at start to avoid a 256 bit boundary
TEMP_CONV ; convert A/D values to deg C based on thermistor R=Ae**(B/T) where (T is in K ie deg C plus 273)
; A =0.01058 and B is 4100
addwf PCL,f ; add value to program counter
; 60 deg C max
retlw D'60' ; 60deg C for A/D D49 (8-bit)
retlw D'59' ; deg C for A/D D50(8-bit)
retlw D'58' ; deg C for A/D D51(8-bit)
retlw D'58' ; deg C for A/D D52(8-bit)
retlw D'57' ; deg C for A/D D53(8-bit)
retlw D'57' ; deg C for A/D D54(8-bit)
retlw D'56' ; deg C for A/D D55(8-bit)
retlw D'56' ; deg C for A/D D56(8-bit)
retlw D'55' ; deg C for A/D D57(8-bit)
retlw D'54' ; deg C for A/D D58(8-bit)
retlw D'54' ; 54 deg C for A/D D59(8-bit)
retlw D'53' ; deg C for A/D D60(8-bit)
retlw D'53' ; deg C for A/D D61(8-bit)
retlw D'52' ; deg C for A/D D62(8-bit)
retlw D'52' ; deg C for A/D D63(8-bit)
retlw D'51' ; deg C for A/D D64(8-bit)
retlw D'50' ; deg C for A/D D65(8-bit)
retlw D'50' ; deg C for A/D D66(8-bit)
retlw D'50' ; deg C for A/D D67(8-bit)
retlw D'49' ; deg C for A/D D68(8-bit)
retlw D'49' ; deg C for A/D D69(8-bit)
retlw D'48' ; 48 deg C for A/D D70(8-bit)
retlw D'48' ; deg C for A/D D71(8-bit)
retlw D'47' ; deg C for A/D D72(8-bit)
retlw D'47' ; deg C for A/D D73(8-bit)
retlw D'46' ; deg C for A/D D74(8-bit)
retlw D'46' ; deg C for A/D D75(8-bit)
retlw D'45' ; deg C for A/D D76(8-bit)
retlw D'45' ; deg C for A/D D77(8-bit)
retlw D'44' ; deg C for A/D D78(8-bit)
retlw D'44' ; deg C for A/D D79(8-bit)
retlw D'43' ; deg C for A/D D80(8-bit)
retlw D'43' ; deg C for A/D D81(8-bit)
retlw D'43' ; deg C for A/D D82(8-bit)
retlw D'42' ; deg C for A/D D83(8-bit)
retlw D'42' ; deg C for A/D D84(8-bit)
retlw D'41' ; deg C for A/D D85(8-bit)
retlw D'41' ; deg C for A/D D86(8-bit)
retlw D'40' ; deg C for A/D D87(8-bit)
retlw D'40' ; deg C for A/D D88(8-bit)
retlw D'40' ; 40 deg C for A/D D89(8-bit)
retlw D'39' ; deg C for A/D D90(8-bit)
retlw D'39' ; deg C for A/D D91(8-bit)
retlw D'38' ; deg C for A/D D92(8-bit)
retlw D'38' ; deg C for A/D D93(8-bit)
retlw D'38' ; deg C for A/D D94(8-bit)
retlw D'37' ; deg C for A/D D95(8-bit)
retlw D'37' ; deg C for A/D D96(8-bit)
retlw D'36' ; deg C for A/D D97(8-bit)
retlw D'36' ; deg C for A/D D98(8-bit)
retlw D'36' ; deg C for A/D D99(8-bit)
retlw D'35' ; deg C for A/D D100(8-bit)
retlw D'35' ; deg C for A/D D101(8-bit)
retlw D'34' ; deg C for A/D D102(8-bit)
retlw D'34' ; deg C for A/D D103(8-bit)
retlw D'34' ; deg C for A/D D104(8-bit)
retlw D'33' ; deg C for A/D D105(8-bit)
retlw D'33' ; deg C for A/D D106(8-bit)
retlw D'33' ; deg C for A/D D107(8-bit)
retlw D'32' ; deg C for A/D D108(8-bit)
retlw D'32' ; 32 deg C for A/D D109(8-bit)
retlw D'32' ; deg C for A/D D110(8-bit)
retlw D'31' ; deg C for A/D D111(8-bit)
retlw D'31' ; deg C for A/D D112(8-bit)
retlw D'30' ; deg C for A/D D113(8-bit)
retlw D'30' ; deg C for A/D D114(8-bit)
retlw D'30' ; deg C for A/D D115(8-bit)
retlw D'29' ; deg C for A/D D116(8-bit)
retlw D'29' ; deg C for A/D D117(8-bit)
retlw D'29' ; deg C for A/D D118(8-bit)
retlw D'28' ; deg C for A/D D119(8-bit)
retlw D'28' ; deg C for A/D D120(8-bit)
retlw D'28' ; deg C for A/D D121(8-bit)
retlw D'27' ; deg C for A/D D122(8-bit)
retlw D'27' ; deg C for A/D D123(8-bit)
retlw D'27' ; deg C for A/D D124(8-bit)
retlw D'26' ; deg C for A/D D125(8-bit)
retlw D'26' ; deg C for A/D D126(8-bit)
retlw D'26' ; deg C for A/D D127(8-bit)
retlw D'25' ; deg C for A/D D128(8-bit)
retlw D'25' ; deg C for A/D D129(8-bit)
retlw D'24' ; deg C for A/D D130(8-bit)
retlw D'24' ; deg C for A/D D131(8-bit)
retlw D'24' ; deg C for A/D D132(8-bit)
retlw D'24' ; deg C for A/D D133(8-bit)
retlw D'23' ; deg C for A/D D134(8-bit)
retlw D'23' ; deg C for A/D D135(8-bit)
retlw D'23' ; deg C for A/D D136(8-bit)
retlw D'22' ; deg C for A/D D137(8-bit)
retlw D'22' ; deg C for A/D D138(8-bit)
retlw D'22' ; deg C for A/D D139(8-bit)
retlw D'21' ; deg C for A/D D140(8-bit)
retlw D'21' ; deg C for A/D D141(8-bit)
retlw D'21' ; deg C for A/D D142(8-bit)
retlw D'20' ; deg C for A/D D143(8-bit)
retlw D'20' ; deg C for A/D D144(8-bit)
retlw D'20' ; deg C for A/D D145(8-bit)
retlw D'19' ; deg C for A/D D146(8-bit)
retlw D'19' ; deg C for A/D D147(8-bit)
retlw D'19' ; deg C for A/D D148(8-bit)
retlw D'18' ; deg C for A/D D149(8-bit)
retlw D'18' ; deg C for A/D D150(8-bit)
retlw D'18' ; deg C for A/D D151(8-bit)
retlw D'17' ; deg C for A/D D152(8-bit)
retlw D'17' ; deg C for A/D D153(8-bit)
retlw D'17' ; deg C for A/D D154(8-bit)
retlw D'16' ; deg C for A/D D155(8-bit)
retlw D'16' ; deg C for A/D D156(8-bit)
retlw D'16' ; deg C for A/D D157(8-bit)
retlw D'15' ; deg C for A/D D158(8-bit)
retlw D'15' ; deg C for A/D D159(8-bit)
retlw D'15' ; deg C for A/D D160(8-bit)
retlw D'14' ; deg C for A/D D161(8-bit)
retlw D'14' ; deg C for A/D D162(8-bit)
retlw D'14' ; deg C for A/D D163(8-bit)
retlw D'13' ; deg C for A/D D164(8-bit)
retlw D'13' ; deg C for A/D D165(8-bit)
retlw D'13' ; deg C for A/D D166(8-bit)
retlw D'12' ; deg C for A/D D167(8-bit)
retlw D'12' ; deg C for A/D D168(8-bit)
retlw D'12' ; deg C for A/D D169(8-bit)
retlw D'11' ; deg C for A/D D170(8-bit)
retlw D'11' ; deg C for A/D D171(8-bit)
retlw D'11' ; deg C for A/D D172(8-bit)
retlw D'10' ; deg C for A/D D173(8-bit)
retlw D'10' ; deg C for A/D D174(8-bit)
retlw D'10' ; deg C for A/D D175(8-bit)
retlw D'9' ; deg C for A/D D176(8-bit)
retlw D'9' ; deg C for A/D D177(8-bit)
retlw D'8' ; deg C for A/D D178(8-bit)
retlw D'8' ; 8 deg C for A/D D179(8-bit)
retlw D'8' ; deg C for A/D D180(8-bit)
retlw D'7' ; deg C for A/D D181(8-bit)
retlw D'7' ; deg C for A/D D182(8-bit)
retlw D'7' ; deg C for A/D D183(8-bit)
retlw D'6' ; deg C for A/D D184(8-bit)
retlw D'6' ; deg C for A/D D185(8-bit)
retlw D'6' ; deg C for A/D D186(8-bit)
retlw D'5' ; deg C for A/D D187(8-bit)
retlw D'5' ; deg C for A/D D188(8-bit)
retlw D'4' ; 4 deg C for A/D D189(8-bit)
retlw D'4' ; deg C for A/D D190(8-bit)
retlw D'4' ; deg C for A/D D191(8-bit)
retlw D'3' ; deg C for A/D D192(8-bit)
retlw D'3' ; deg C for A/D D193(8-bit)
retlw D'2' ; deg C for A/D D194(8-bit)
retlw D'2' ; deg C for A/D D195(8-bit)
retlw D'2' ; deg C for A/D D196(8-bit)
retlw D'1' ; deg C for A/D D197(8-bit)
retlw D'1' ; deg C for A/D D198(8-bit)
retlw D'0' ; deg C for A/D D199(8-bit)
; 0 deg C min
retlw D'0' ; 0 deg C for A/D D200(8-bit)
;**********************************************************************************************
SETUP
clrf PORTB ; outputs low
clrf PORTA
; set inputs/outputs
bsf STATUS,RP0 ; select memory bank 1
movlw B'00000111' ; comparators off
movwf CMCON
movlw B'00010011' ; port B outputs/ inputs set
movwf TRISB ; port B data direction register
movlw B'00111111' ; outputs (0) and inputs (1)
movwf TRISA ; port A data direction register
movlw B'00000111' ; settings (pullups enabled, TMR0/256)
movwf OPTION_REG
; analog inputs, A/D
movlw B'00011111' ; AN0 to AN4 are analog inputs
movwf ANSEL
; movlw B'10000000' ; * 4MHz operation right justified A/D result, Vdd to Vss A/D
movlw B'11000000' ; ** 8MHz operation right justified A/D result, Vdd to Vss A/D
movwf ADCON1
bcf STATUS,RP0 ; select memory bank 0
movlw B'01000000' ; Fosc, channel 0 etc
movwf ADCON0
bsf ADCON0,ADON ; A/D on
bsf STATUS,RP0 ; select memory bank 1
; movlw B'01101000' ; * 4MHz operation
movlw B'01111000' ; ** 8MHz operation 8MHz
movwf OSCCON ;
bcf STATUS,RP0 ; select memory bank 0
; timer 1
; movlw B'00100001' ; * 4MHz operation timer 1 prescaler /4, fosc/4
movlw B'00110001' ; ** 8MHz operation timer 1 prescaler /8, fosc/4
movwf T1CON
bsf T1CON,0 ; timer 1 on
bsf STATUS,RP0 ; select memory bank 1
; movlw H'1F' ; * 4MHz operation 31.24kHz pwm rate 7-bit resolution
movlw H'3F' ; ** 8MHz operation 31.24kHz pwm rate 8-bit resolution
movwf PR2 ; PWM period register
bcf STATUS,RP0 ; memory bank 0
; pwm set
clrf CCPR1L ; duty 0% Mosfet off
bcf CCP1CON,4
bcf CCP1CON,5 ; clear 10-bits
clrf T2CON
bsf T2CON,2 ; enable timer 2
movlw B'00001100' ; set PWM mode
movwf CCP1CON ; enable PWM operation
; initial conditions
INITIAL
clrf PORTB
clrf PORTA
clrf THERMISTOR ; thermistor flags
movlw D'1'
movwf SENSOR_COUNT ; counter ready to zero on next decrement
movwf SENSOR_COUNT1
clrf CHARGE_STATE ; start at main Bulk ( 0 main Bulk, 1 float)
clrf CHARGE_FLAG ; flag for charge
movlw D'5' ; 5 x 0.262ms
movwf PERIOD ; period counter for solar cell power calculations
clrf CCPR1_STORE ; CCPR1L storage
clrf FIRST ; first run
clrf POWERH ; power ms byte
clrf POWERL ; power ls byte
clrf FLASHER ; flash timer
clrf CHRG_RATE ; charge rate flag
clrf HOUR0 ; hour counter
clrf HOUR1 ; 14s counter for hour0 counter
clrf HOUR2 ; 56s counter for 4 hour counter
clrf HOUR3 ; 4- hour timer
clrf EQ_FLAG ; equalisation flag
bsf EQ_FLAG,0 ; equalisation flag.0 Does not run equalisation when set
clrf EQ_LEVEL ; equalisation input level store
clrf BATT_IND ; no battery error when clear
clrf BURST_FLG ; no burst
clrf BULK_TIMER ; bulk charge timer
clrf BULK_TIMER_END ; bulk timer ended flag
; load SLA preset values
; battery voltage reduced to 0.3125 so 14.4V becomes 4.50V and D920 (H398) with A/D conversion (10-bit)
movlw H'03'
movwf CUT_M ; cutout SLA voltage high byte 14.4V
movlw H'98'
movwf CUT_L ; cutout SLA voltage low byte
movlw H'03'
movwf FLOAT_H ; float SLA voltage high byte 13.5V
movlw H'5F'
movwf FLOAT_L ; float SLA voltage low byte
movlw H'03'
movwf EQ_HI ; Equalsiation voltage high byte (14.4V x 10%)= 15.84V
movlw H'F4'
movwf EQ_LO ; Equalisation voltage low byte
ALLOW_INTERRUPTS
; allow interrupts
bsf STATUS,RP0 ; select memory bank 1
bsf PIE1,TMR1IE ; timer 1 overflow interrupt enable
bcf STATUS,RP0 ; select memory bank 0
bcf PIR1,TMR1IF ; timer 1 interrupt flag
bsf INTCON,PEIE ; enable periperal interrupts
bsf INTCON,GIE ; enable global interrupts
;*******************************************************
CYCLE ; beginining of normal running loop
; sensors checked periodically
decfsz SENSOR_COUNT,f
goto CHARGE_MODE
decfsz SENSOR_COUNT1,f
goto CHARGE_MODE ; when both zero
; movlw D'4' ; * 4MHz operation
movlw D'8' ; ** 8MHz operation
movwf SENSOR_COUNT1 ; set period to about 500ms
SENSORS
; equalisation input
btfss PORTB,4 ; equalisation input selection
goto LOW_IN
btfss EQ_LEVEL,4 ; input store
goto HI_IN
; if portB,4 is high and EQ_LEVEL,4 is also high set EQ_FLAG,0 (no equalisation)
clrf EQ_FLAG
bsf EQ_FLAG,0 ; no equalisation when flag is set (PORTB,4 is high)
goto CH_1AD
LOW_IN
btfss EQ_LEVEL,4
goto CH_1AD ; if portB,4 and EQ_LEVEL,4 both low ignore
; if portB,4 is low and EQ_LEVEL,4 is high, run delay and check again.
call DELAY
btfsc PORTB,4
goto CH_1AD ; If portB,4 high ignore
; if portB,4 remains low clear EQ_LEVEL,4 and clear EQ_FLAG (level change from h/l)
clrf EQ_LEVEL ; store new portB,4 level
clrf EQ_FLAG ; equalisation flag clear for equalisation
; level change from H/L indicates equalisation required
; flash LEDS
bcf INTCON,GIE ; stop interrupt
bcf PORTA,7 ; Bulk LED off
bcf PORTB,7 ; Float LED off
bcf PORTA,6 ; Absorption LED off
bsf PORTB,6 ; equalisation LED on
call DELAY
bcf PORTB,6 ; Equalisation LED off
call DELAY
bsf PORTB,6 ; Equalisation LED on
call DELAY
bcf PORTB,6 ; Equalisation LED off
call DELAY
bsf INTCON,GIE ; interrupt starts again
goto CH_1AD
HI_IN
; if portB,4 is high and EQ_LEVEL,4 is low, run delay and check again.
call DELAY
btfss PORTB,4
goto CH_1AD ; portB,4 low so bypass
; If portB,4 is still high, set EQ_LEVEL,4 and set EQ_FLAG,0 (no equalisation)
bsf EQ_LEVEL,4 ; store portB,4 level
bsf EQ_FLAG,0 ; no equalisation
; Channel 1 A/D value(mV/deg C Compensation)
; compensation calculated as (Comp/50) x 255
CH_1AD
; set analog input address
bcf ADCON0,5
bcf ADCON0,4
bsf ADCON0,3 ;
call DEL_AD ; convert to digital ls bits in 'DIGITAL'
; reduce from 10-bit to 8-bit
rrf ADRESH,f ; move right ls byte
rrf DIGITAL,f ; ls byte moved right
rrf ADRESH,f ; move right ls byte
rrf DIGITAL,f ; ls byte moved right
; write compensation value
movf DIGITAL,w ; 8-bit byte
movwf COMP ; mV/deg C SLA compensation
; Channel 4 A/D value (thermistor (temperature))
CH_4AD
; set analog input address
bsf ADCON0,5
bcf ADCON0,4
bcf ADCON0,3 ; A/D No.4
call DEL_AD ; convert to digital ls bits in 'DIGITAL'
; change from 10-bit to 8-bit
rrf ADRESH,f ; move right ls byte
rrf DIGITAL,f ; ls byte moved right
rrf ADRESH,f ; move right ls byte
rrf DIGITAL,f ; ls byte moved right
; check for thermistor out of circuit
movf DIGITAL,w
sublw D'250' ; >250
bcf INTCON,GIE ; stop interrupt
clrf THERMISTOR ; clear value
btfsc STATUS,C
goto CK_ZRO
bsf THERMISTOR,0 ; set bit 0 when out of circuit
goto BY_ZRO
; check for zero degrees or less
CK_ZRO
movf DIGITAL,w
sublw D'199' ; >199
movlw D'199' ; keep at 0 degrees
btfss STATUS,C
movwf DIGITAL ; keep at 0 degrees C so compensation plateaus below 0 degrees C
; check for thermistor short circuit
movlw D'04'
subwf DIGITAL,w ; if less than 4
btfss STATUS,C
bsf THERMISTOR,1 ; set when short circuit
BY_ZRO
TEMP_CONV1
bsf INTCON,GIE ; allow interrupt
; convert to temperature
movf DIGITAL,w
sublw D'199' ; take from 199 if negative then >200 so set at 200
movlw D'200' ; ready to load if >200
btfss STATUS,C
movwf DIGITAL
movlw D'49' ; minimum value
subwf DIGITAL,f ; take away 49 from A/D value
btfss STATUS,C ; if minus then >60 deg C so set at 60deg
clrf DIGITAL ; 0 so 60 deg C in lookup table
movf DIGITAL,w
call TEMP_CONV ; convert reading to temperature in deg C
movwf TEMPERATURE ; store value
; find compensation requirement with temperature difference from 20 deg C
; multiplied by D100 and divided by D8000 to calculate mV/deg C for cutout and float voltages
; this is added (for <20 deg C) or subtracted (for >20deg C) from cutoff and float Voltages.
; take away 20 deg C
clrf NEGATIVE ; subtract flag
movlw D'20' ; 20 deg C
subwf TEMPERATURE,w ;
btfss STATUS,C ; if negative then less than 20 deg C
bsf NEGATIVE,7
; (temperature - 20) x 100
movwf AARGB0
; if negative then subtract from 20
btfss NEGATIVE,7
goto CONTINUE1
movf TEMPERATURE,w
sublw D'20' ; temperature from 20
movwf AARGB0
CONTINUE1
; multiply temperature difference from 20 deg C (in AARGB0) by compensation value
movf COMP,w
movwf BARGB0
call EIGHTEIGHT
; result in AARGB0,AARGB1
; shift result
movf AARGB1,w
movwf AARGB2
movf AARGB0,w
movwf AARGB1
clrf AARGB0
; Multiply by 100
movlw D'100'
movwf BARGB2
clrf BARGB1
clrf BARGB0
call FXM2424U ; multiply
; shift result for division
movf AARGB2,w ; ms of multiplication
movwf AARGB0
movf AARGB3,w ; ls byte
movwf AARGB1
movf AARGB4,w ; ms of multiplication
movwf AARGB2
movf AARGB5,w ; ls byte
movwf AARGB3
; Divide by D8000 = H1F40
clrf BARGB0
clrf BARGB1
movlw H'1F'
movwf BARGB2
movlw H'40'
movwf BARGB3
call FXD3232U ; divide
; cutoff calculations
btfsc NEGATIVE,7 ; if set add value
goto ADD_COMP1
; take compensation value from cutoff V and place in CUT_COMP_M/LS
movf AARGB3,w ; result
subwf CUT_L,w
movwf CUT_COMP_L
movf CUT_M,w ; ms cutout V
btfss STATUS,C
decf CUT_M,w ; decrease if carry
movwf CUT_COMP_M
btfss CUT_COMP_M,7 ; if bit 7 set then over so clear
goto CHECK_EQ
clrf CUT_COMP_M
clrf CUT_COMP_L
; take compensation value from equalisation voltage and place in EQ_LO_COMP, EQ_HI_COMP
CHECK_EQ
movf AARGB3,w ; result
subwf EQ_LO,w
movwf EQ_LO_COMP
movf EQ_HI,w ; ms
btfss STATUS,C
decf EQ_HI,w ; decrease if carry
movwf EQ_HI_COMP
btfss EQ_HI_COMP,7 ; if bit 7 set then over so clear
goto CHECK_FLOAT
clrf EQ_HI_COMP
clrf EQ_LO_COMP
goto CHECK_FLOAT
ADD_COMP1
movf CUT_M,w
movwf CUT_COMP_M
movf AARGB3,w ; result
addwf CUT_L,w
movwf CUT_COMP_L
btfsc STATUS,C
incf CUT_COMP_M,f ; increase if carry
; check if over 1024
btfss CUT_COMP_M,2 ; if bit set over so set at 1023
goto CHECK_EQ_PLUS
movlw B'00000011' ; set at 1023
movwf CUT_COMP_M
movlw H'FF'
movwf CUT_COMP_L
CHECK_EQ_PLUS
movf EQ_HI,w
movwf EQ_HI_COMP
movf AARGB3,w ; result
addwf EQ_LO,w
movwf EQ_LO_COMP
btfsc STATUS,C
incf EQ_HI_COMP,f ; increase if carry
; check if over 1024
btfss EQ_HI_COMP,2 ; if bit set over so set at 1023
goto CHECK_FLOAT
movlw B'00000011' ; set at 1023
movwf EQ_HI_COMP
movlw H'FF'
movwf EQ_LO_COMP
; Float calculations
CHECK_FLOAT
btfsc NEGATIVE,7 ; if set add value
goto ADD_COMP2
; take compensation value from float V and place in FLOAT_COMP_M/LS
movf AARGB3,w ; result
subwf FLOAT_L,w
movwf FLOAT_COMP_L
movf FLOAT_H,w ; ms float V
btfss STATUS,C
decf FLOAT_H,w ; decrease if carry
movwf FLOAT_COMP_M
btfss FLOAT_COMP_M,7 ; if bit 7 set then over so clear
goto CH_0AD
clrf FLOAT_COMP_M
clrf FLOAT_COMP_L
goto CH_0AD
ADD_COMP2
movf FLOAT_H,w ; ms float V to w
movwf FLOAT_COMP_M
movf AARGB3,w ; result
addwf FLOAT_L,w
movwf FLOAT_COMP_L
btfsc STATUS,C
incf FLOAT_COMP_M,f ; increase if carry
; check if over 1024
btfss FLOAT_COMP_M,2 ; if bit set over so set at 1023
goto CH_0AD
movlw B'00000011' ; set at 1023
movwf FLOAT_COMP_M
movlw H'FF'
movwf FLOAT_COMP_L
; Battery voltage, Channel 0 A/D
; voltage at AN2 is 0.3125 of actual measured due to divider
; so 15V is reduced to 4.6875V and results in D960 from A/D converter (10-bit value)
; this divider value sets the other cutoff, float and compensation calculations
CH_0AD
; set analog input address
bcf ADCON0,5
bcf ADCON0,4
bcf ADCON0,3 ;
call DEL_AD
movf DIGITAL,w
movwf BATT_LO ; battery voltage ls byte
movf ADRESH,w ; ms byte
movwf BATT_HI ; battery voltage ms byte
; check if below 12.45V or about 75% of capacity
; A/D is (D796, H31C). Reset to main Bulk when voltage drops to below 12.45V
movf BATT_HI,w ; high byte of battery voltage
sublw H'3' ; take from
movwf DIGITAL ; store
movf BATT_LO,w ; low byte
sublw H'1C' ; 12.45V
btfss STATUS,C
decf DIGITAL,f ; decrease if required
btfsc DIGITAL,7 ; if set then >12.45V
goto BY_BULK_SET
clrf CHARGE_STATE ; below 12.45V so set for bulk/main charging
clrf BULK_TIMER
clrf BULK_TIMER_END ; bulk timer ended flag
; end of switched sensors
BY_BULK_SET
bsf CHRG_RATE,0 ; charge rate flag set to show new values available
; Charge Control
CHARGE_MODE
; if THERMISTOR,1 is set (ie a short circuit)
btfss THERMISTOR,1 ; short circuit thermistor
goto CHK_ZRO_BIT
bsf CHARGE_FLAG,0 ; set charge flag so no charge
goto NO_CHARGE
CHK_ZRO_BIT
btfss THERMISTOR,0 ; thermistor out
goto CHK_BATT
bsf CHARGE_FLAG,0 ; set charge flag so no charge
goto NO_CHARGE
CHK_BATT
; battery voltage: if low then apply bursts till >10.5V (D671, H29F)
; check if below 10.5V. 10.5V = 29F
;(for testing set values to test at 33F for 13V)
movf BATT_HI,w ; high byte of battery voltage
sublw H'2' ; take from 10.5V (H29F)
movwf DIGITAL ; store
movf BATT_LO,w ; low byte
sublw H'9F' ; 10.5V (H29F)
btfss STATUS,C
decf DIGITAL,f ; decrease if required
btfss DIGITAL,7 ; if set then >10.5V
goto BURST ; burst charge till voltage is above 10.5V
clrf BURST_FLG ; burst flag off (no burst)
; if battery above 15V (usually when an O/C cell) then show Batt. LED
; first check if Equalisation running
btfss EQ_FLAG,1 ; when set equalisation is running so bypass since >15V during eq
goto BATT15
bsf PORTB,2 ; equalisation and >15V output. High on equalisation
goto MODE_CHARGE
BATT15
movf BATT_HI,w ; high byte of battery voltage
sublw H'3' ; take from 15V
movwf DIGITAL ; store
movf BATT_LO,w ; low byte
sublw H'BF' ; 15V
btfss STATUS,C
decf DIGITAL,f ; decrease if required
btfss DIGITAL,7 ; if set then >15V
goto MODE_CHARGE1 ; <15V
bsf CHARGE_FLAG,0 ; stop charging
bsf BATT_IND,0 ; Batt. indicator LED on (Flash Bulk LED)
bsf PORTB,2 ; >15V output
goto NO_CHARGE ; battery voltage high so end charge
MODE_CHARGE1
; test for low battery
; if above 12V (3.75V after division (H2FF)) set RB2 low
BATT12
movf BATT_HI,w ; high byte of battery voltage
sublw H'2' ; take from 12V
movwf DIGITAL ; store
movf BATT_LO,w ; low byte
sublw H'FF' ; 12V
btfss STATUS,C
decf DIGITAL,f ; decrease if required
btfss DIGITAL,7 ; if set then >12V
goto BATT11.5
bcf PORTB,2 ; output low at <15V and >12V
goto MODE_CHARGE
; if below 11.5V (3.59V after division (H2DF)) set RB2 high
BATT11.5
movf BATT_HI,w ; high byte of battery voltage
sublw H'2' ; take from 11.5V
movwf DIGITAL ; store
movf BATT_LO,w ; low byte
sublw H'DF' ; 11.5V
btfss STATUS,C
decf DIGITAL,f ; decrease if required
btfss DIGITAL,7 ; if set then >11.5V
bsf PORTB,2 ; set when <11.5V
MODE_CHARGE
bcf BATT_IND,0 ; Batt.indicator LED off
; charge mode
; measure solar cell voltage
; AN2
; solar cell voltage is divided by a factor of 0.176
; set analog input address
bcf ADCON0,5
bsf ADCON0,4
bcf ADCON0,3 ;
call DEL_AD
movf DIGITAL,w
movwf CELL_LO ; solar cell voltage ls byte
movf ADRESH,w ; ms byte
movwf CELL_HI ; solar cell voltage ms byte
; start charge when solar cell has sufficient voltage. ie about 12V
; check if above 12V D432, H1B0 (solar cell voltage is divided by a factor of 0.176)
movf CELL_HI,w ; high byte of solar call voltage
sublw H'1' ; take from
movwf DIGITAL ; store
movf CELL_LO,w ; low byte
sublw H'B0' ; 12V
btfss STATUS,C
decf DIGITAL,f ; decrease if required
btfss DIGITAL,7 ; if set then >12V
goto NO_CHARGE ; charge off till solar cell ready
clrf HOUR3 ; prevents return to Bulk charge if this is before the end of 4hr timer
; charge; check charge status. Bulk charge or absorption/ float (trickle)
clrf CHARGE_FLAG ; charging flag
movf CHARGE_STATE,w ; 0 Bulk, 1 float
btfsc STATUS,Z
goto CHARGE_FULL
goto CHARGE_ABSORP_FLOAT
NO_CHARGE
bsf CHARGE_FLAG,0 ; no charge flag
clrf CCPR1L ; charge off
clrf FIRST
movlw D'5' ; 5 x 0.262ms
movwf PERIOD
; check if 4-hour timer is set
movf HOUR3,w ; if zero then not yet set
btfss STATUS,Z
goto CYCLE
; not set
bcf STATUS,GIE ; stop interrupt
; set timer
movlw H'FF' ; 256 counts for 4 hours
; ** test timer, remark out for normal 4 hours
; movlw H'1' ; ** about 56 seconds timer. For use as a shorter test period
; **
movwf HOUR3 ; set 4 hour timer
clrf HOUR2
bsf STATUS,GIE ; allow interrupt
goto CYCLE
CHARGE_FULL; (CHARGE_STATE = 0) main bulk charge
TEST_BATT2
; compare battery voltage (BATT_HI/LO) with cutout (CUT_COMP_M/L)
movf BATT_HI,w ; high byte of battery voltage
subwf CUT_COMP_M,w ; take from compensated cutout
movwf DIGITAL ; store
movf BATT_LO,w ; low byte
subwf CUT_COMP_L,w ; take from compensated cutout
btfss STATUS,C
decf DIGITAL,f ; decrease if required
btfss DIGITAL,7 ; if set then battery is over cutout voltage
goto FULL_POWER_RUN
; end of bulk charge
btfsc BULK_TIMER_END,0; bulk timer ended flag. If not set, then bulk charge occurred in <60s
; so clear timer 0 so charging goes to float rather than absorption
goto ABS_TME
clrf HOUR0 ; stop absorption charge
clrf BULK_TIMER_END ; bulk timer ended flag
goto BY_SET ; bypass setting the timer for absorption
ABS_TME ; absorption timer set
clrf CCPR1L
clrf HOUR1 ; 14 seconds counter
movlw H'FF' ; 256 counts for 1 hour
; ** test timer, remark out for normal 1hour
; movlw H'4' ; ** about 42-56 seconds timer. For use as a shorter test period
; **
movwf HOUR0 ; set absorption period @ 1 hour
BY_SET
movlw D'5' ; 5 x 0.262ms
movwf PERIOD
goto CHARGE_ABSORP_FLOAT
; full charge; maintain max power from solar cell during bulk charging
; periodically alter the duty cycle to find power maximum
; store CCPR1L value that provides max power
FULL_POWER_RUN
; set 60s timer for bulk charge
movf CHARGE_STATE,w ; check if bulk
btfss STATUS,Z
goto BY_BULK_TIMER ; absorption or float so bypass bulk timer
movf BULK_TIMER,w ; check if timer running
btfss STATUS,Z
goto BY_BULK_TIMER
movlw D'229' ; 0.262ms x 229 = 60s
movwf BULK_TIMER ; decreased in interrupt to zero and sets bulk timer ended flag
BY_BULK_TIMER
movf PERIOD,w ; when zero check for maximum power
btfss STATUS,Z ;
goto CYCLE
movf FIRST,w ; first run
btfss STATUS,Z ; when clear
goto CH_3AD
clrf POWERH ; power
clrf POWERL
clrf CCPR1L ; drive cleared
call DELAY2 ; time for current reading to drop
clrf CCPR1_STORE
movlw H'FF'
movwf FIRST ; sets first run
; measure solar cell current
; AN3
CH_3AD
; solar cell current (1V=2.21A)
; set analog input address
bcf ADCON0,5
bsf ADCON0,4
bsf ADCON0,3 ;
call DEL_AD
movf DIGITAL,w
movwf CELL_I_LO ; solar cell current ls byte
movf ADRESH,w ; ms byte
movwf CELL_I_HI ; solar cell current ms byte
; AN2
CH_2AD
; solar cell voltage is divided by a factor of 0.176
; set analog input address
bcf ADCON0,5
bsf ADCON0,4
bcf ADCON0,3 ;
call DEL_AD
movf DIGITAL,w
movwf CELL_LO ; solar cell voltage ls byte
movf ADRESH,w ; ms byte
movwf CELL_HI ; solar cell voltage ms byte
; multiply CELL_HI, CELL_LO by CELL_I_HI, CELL_I_LO check for maximum
; set at 8-bit
; solar cell voltage
rrf CELL_HI,w ; shift ms byte right and store
movwf DIGITAL
rrf CELL_LO,w ; shift ls byte and store
movwf CELL_V
rrf DIGITAL,w ; shift stored ms byte
rrf CELL_V,f ; shift stored ls byte
; solar cell current
rrf CELL_I_HI,w
movwf DIGITAL
rrf CELL_I_LO,w
movwf CELL_I
rrf DIGITAL,w
rrf CELL_I,f
; multiply
movf CELL_V,w
movwf AARGB0
movf CELL_I,w
movwf BARGB0
call EIGHTEIGHT
; result is in AARGB0,AARGB1
; compare with POWERH,POWERL
movf AARGB0,w ; high byte of power new
subwf POWERH,w ; take from last power value
movwf DIGITAL ; store
movf AARGB1,w ; low byte
subwf POWERL,w ; take from last power value
btfss STATUS,C
decf DIGITAL,f ; decrease if required
btfss DIGITAL,7 ; if set then new power > old power
goto INC_CHRG ; increase PWM
TRANSFER ; transfer values
; new power is larger than last, transfer to POWERH,POWERL
; transfer CCPR1L into CCPR1_STORE
movf AARGB0,w
movwf POWERH
movf AARGB1,w
movwf POWERL
movf CCPR1L,w
movwf CCPR1_STORE
INC_CHRG
; increase charge
movf CCPR1L,w ; check if maximum
sublw D'64'
btfss STATUS,C ; if maximum value end of test cycle
goto MAX ; bypass decrease if 0
incf CCPR1L,f
call DELAY3 ; allow time to change at I and V inputs
goto CYCLE
MAX
; when max power found, set next timer for test period
movlw D'76' ; D76 = 20s (0.262ms per bit)
movwf PERIOD ; next 20s
clrf FIRST ; so runs with first values at start
movf CCPR1_STORE,w
movwf CCPR1L ; set full charge rate at maximum power
goto CYCLE
CHARGE_ABSORP_FLOAT; (CHARGE_STATE = 1)
movlw D'01'
movwf CHARGE_STATE ; absorption/float mode set when coming from full mode
clrf BULK_TIMER_END ; bulk timer ended flag
; Measure battery Voltage
; set analog input address
bcf ADCON0,5
bcf ADCON0,4
bcf ADCON0,3 ;
call DEL_AD
movf DIGITAL,w
movwf BATT_LO ; battery voltage ls byte
movf ADRESH,w ; ms byte
movwf BATT_HI ; battery voltage ms byte
; if battery voltage is D1023 (H3FF) then over in value
movf BATT_HI,w ; ms byte
xorlw H'03' ; 3
btfss STATUS,Z
goto TEST_BATT3 ; not equal
movf BATT_LO,w
xorlw H'FF'
btfsc STATUS,Z
goto NO_CHARGE ; battery voltage high so end charge
TEST_BATT3
; alter CHARGE_CONT to adjust the drive to maintain float V
; set values to 8-bit
; battery
rrf BATT_HI,w
movwf VALUE1
rrf BATT_LO,w ; get value difference
movwf VALUE2
rrf VALUE1,w
rrf VALUE2,f
; check hour timer. If still timing then absorption. if timer ended (hour0=0) then float
movf HOUR0,w
btfsc STATUS,Z
goto FLOAT_VALUES
; check Equalisation or Absorption
btfsc EQ_LEVEL,4 ; when low run equalisation unless already run (EQ_FLAG,0 set)
goto ABSORPTION_VALUES
btfsc EQ_FLAG,0 ; if flag is set equalisation has already run so bypass to absorption
goto ABSORPTION_VALUES
EQUALISATION_VALUES
bsf EQ_FLAG,1 ; equalisation started flag so LED lights
; equalisation
rrf EQ_HI_COMP,w
movwf VALUE3
rrf EQ_LO_COMP,w ; get value difference
movwf VALUE4
rrf VALUE3,w
rrf VALUE4,f
; compare battery with compensated cutoff V
movf BATT_HI,w ; high byte of battery voltage
subwf EQ_HI_COMP,w ; take from compensated equalisation Voltage
movwf DIGITAL ; store
movf BATT_LO,w ; low byte
subwf EQ_LO_COMP,w ; take from compensated V
btfss STATUS,C
decf DIGITAL,f ; decrease if required
btfss DIGITAL,7 ; if set then battery voltage is over cut voltage
goto PWM_CONTROL ; control power
goto DECREASE_CHARGE
ABSORPTION_VALUES
bcf EQ_FLAG,1 ; clear so equaliser LEDs off
; absorption
rrf CUT_COMP_M,w
movwf VALUE3
rrf CUT_COMP_L,w ; get value difference
movwf VALUE4
rrf VALUE3,w
rrf VALUE4,f
; compare battery with compensated cutoff V
movf BATT_HI,w ; high byte of battery voltage
subwf CUT_COMP_M,w ; take from compensated cut V
movwf DIGITAL ; store
movf BATT_LO,w ; low byte
subwf CUT_COMP_L,w ; take from compensated cut V
btfss STATUS,C
decf DIGITAL,f ; decrease if required
btfss DIGITAL,7 ; if set then battery voltage is over cut voltage
goto PWM_CONTROL ; control power
goto DECREASE_CHARGE
FLOAT_VALUES
bsf EQ_FLAG,0 ; equalisation no run flag set so no further equalisation occurs until reset
btfsc EQ_FLAG,1 ; if running flag set set bit 2
bsf EQ_FLAG,2 ; allows EQ LED to flash
bcf EQ_FLAG,1 ; equalisation flag for eq running indicator LED
; float
rrf FLOAT_COMP_M,w
movwf VALUE3
rrf FLOAT_COMP_L,w ; get value difference
movwf VALUE4
rrf VALUE3,w
rrf VALUE4,f
; compare battery with float V
movf BATT_HI,w ; high byte of battery voltage
subwf FLOAT_COMP_M,w ; take from compensated float
movwf DIGITAL ; store
movf BATT_LO,w ; low byte
subwf FLOAT_COMP_L,w ; take from compensated float V
btfss STATUS,C
decf DIGITAL,f ; decrease if required
btfsc DIGITAL,7 ; if set then battery voltage is over cut voltage
goto DECREASE_CHARGE
; check RB1 for return to bulk charge after drawing current when in float
btfsc PORTB,1
goto PWM_CONTROL
; compare float control with previous CCPR1 storage during bulk charge
movf CCPR1_STORE,w
subwf CCPR1L,w
btfss STATUS,C
goto PWM_CONTROL ;
clrf CHARGE_STATE ; set for bulk/main charging
clrf BULK_TIMER
clrf BULK_TIMER_END ; bulk timer ended flag
goto CYCLE
; control of PWM other than for full power
PWM_CONTROL
movf CCPR1L,w
subwf CCPR1_STORE,w
btfss STATUS,C ; if over max power point PWM value go to FULL POWER mode
goto FULL_POWER_RUN
btfsc STATUS,Z
goto FULL_POWER_RUN
incf CCPR1L,w
sublw D'64'
btfss STATUS,C
goto FULL_POWER_RUN
incf CCPR1L,f
goto CYCLE
; decrease charge
DECREASE_CHARGE
movf VALUE4,w ; absorption/float 8-bit
subwf VALUE2,f ; battery 8-bit
; if >3 switch off charge
movf VALUE2,w
sublw D'3'
btfss STATUS,C
goto CLEAR_CHRG ; over
movf VALUE2,w ; subtracted value
subwf CCPR1L,w
btfss STATUS,C ; if negative set at 0
clrw
movwf CCPR1L ; reduce charge
goto CYCLE
CLEAR_CHRG
clrf CCPR1L
goto CYCLE
BURST
bsf BURST_FLG,0 ; set flag
bcf PORTA,6 ; Absorption LED off
bcf PORTB,7 ; Float LED off
bcf PORTB,6 ; Equalisation LED off
; burst pulses of current till voltage >10.5V
movf FLASHER,w ; flasher counter (0-255 count)
andlw B'00001111' ;
; only burst is on for 1 in 16 (6.25% on duty cycle) at a 4.2s rate
btfss STATUS,Z
goto BURST_OFF
; Burst on
bsf PORTA,7 ; Bulk LED on
movlw D'64'
movwf CCPR1L ; set full charge
goto CYCLE
BURST_OFF
bcf PORTA,7 ; Bulk LED off
clrf CCPR1L
goto CYCLE
;***************************************************
; INTERRUPT
; start interrupt by saving w and status registers
INTERRUPT
movwf W_TMP ; w to w_tmp storage
swapf STATUS,w ; status to w
movwf STATUS_TMP ; status in status_tmp
bcf STATUS,RP0 ; bank select
bcf STATUS,RP1 ; select memory bank 0
bcf PIR1,TMR1IF ; clear flag
FLASH1
; flasher rate (increases every 0.262ms)
incf FLASHER,f ; flasher
; rate for power calculation during charging
movf PERIOD,w ; period for charging power cycle
btfss STATUS,Z
decf PERIOD,f ; decrease if not 0
; flash NTC Thermistor LED(PORTB,5)if required
; check thermistor
btfss THERMISTOR,0 ; when set, thermistor is out of circuit
goto CK_THERM1
; charge LEDs off
bcf PORTA,7 ; Bulk LED off
bcf PORTA,6 ; Absorption LED off
bcf PORTB,7 ; Float LED off
bcf PORTB,6 ; Equalisation LED off
; flash NC thermistor LED
movf FLASHER,w
andlw B'00001111' ; flash 262ms on each 2 seconds
btfsc STATUS,Z ;
goto SET_OUT
bcf PORTB,5 ; NTC thermistor LED off
goto CHECK_END
SET_OUT
bsf PORTB,5 ; NTC thermistor LED on
goto CHECK_END
CK_THERM1
btfss THERMISTOR,1 ; when set, thermistor is shorted
goto CHARGE_CONDITION
; charge LEDs off
bcf PORTA,7 ; Bulk LED off
bcf PORTA,6 ; Absorption LED off
bcf PORTB,7 ; Float LED off
bcf PORTB,6 ; Equalisation LED off
; flash thermistor LED
movf FLASHER,w
andlw B'00000111' ; flash 262ms on each 1 second
btfsc STATUS,Z
goto SET_OUT1
bcf PORTB,5 ; NTC thermistor LED off
goto CHECK_END
SET_OUT1
bsf PORTB,5 ; NTC thermistor LED on
goto CHECK_END
CHARGE_CONDITION
; check battery error
btfss BATT_IND,0 ; when set flash Bulk LED
goto CHARGE_STATES
; flash Bulk LED
; charging LEDs off
bcf PORTA,6 ; Absorption LED off
bcf PORTB,7 ; Float LED off
bcf PORTB,6 ; Equalisation LED off
; flash LED
movf FLASHER,w
andlw B'00000111' ; flash 262ms on each 1 second
btfsc STATUS,Z
goto SET_OUT_CHRG
bcf PORTA,7 ; LED off
goto CHECK_END
SET_OUT_CHRG
bsf PORTA,7 ; LED on
goto CHECK_END
CHARGE_STATES
movf CHARGE_FLAG,w ; if zero then charging
btfss STATUS,Z
goto OFF_CHRG
; check burst
btfsc BURST_FLG,0 ; if set burst mode
goto BURST_IND
; check main or trickle
btfss CHARGE_STATE,0 ; clear then main Bulk
goto MAIN_LED
; if HOUR0 is clear then float. Otherwise absorption
movf HOUR0,w
btfsc STATUS,Z
goto FLOAT
;
; Absorption or Equalisation
btfss EQ_FLAG,1 ; when set Equalisation in process
goto ABSORPTION
EQUALISATION
bcf PORTB,5 ; NTC thermistor LED off
bcf PORTA,7 ; Bulk LED off
bcf PORTB,7 ; Float LED off
bcf PORTA,6 ; Absorption LED off
bsf PORTB,6 ; Equalisation LED on
goto CHECK_END
ABSORPTION
bcf PORTB,5 ; NTC thermistor LED off
bcf PORTA,7 ; Bulk LED off
bcf PORTB,7 ; Float LED off
bcf PORTB,6 ; Equalisation LED off
bsf PORTA,6 ; Absorption LED on
goto CHECK_END
;
FLOAT
bcf PORTB,5 ; NTC thermistor LED off
bcf PORTA,7 ; Bulk LED off
bsf PORTB,7 ; Float LED on
bcf PORTA,6 ; Absorption LED off
bcf PORTB,6 ; Equalisation LED off
goto CHECK_END
;
MAIN_LED ;(main Bulk)
bcf PORTB,5 ; NTC thermistor LED off
bsf PORTA,7 ; Bulk LED on
bcf PORTA,6 ; Absorption LED off
bcf PORTB,7 ; Float LED off
bcf PORTB,6 ; Equalisation LED off
goto CHECK_END
;
OFF_CHRG
; charge LEDs off
bcf PORTA,7 ; Bulk LED off
BURST_IND ; for burst indication
bcf PORTA,6 ; Absorption LED off
bcf PORTB,7 ; Float LED off
bcf PORTB,6 ; Equalisation LED off
; flash Equalisation LED once run
btfss EQ_FLAG,2 ; equalisation run flag
goto HOUR_TIMER
movf FLASHER,w
andlw B'00001111' ; flash 262ms on each 2 seconds
btfss STATUS,Z
goto OFF_TIMER
bsf PORTB,6 ; equalisation LED flashes
goto OFF_TIMER ; bypass hour timer when charge is off
CHECK_END
; flash Equalisation LED once run
btfss EQ_FLAG,2 ; equalisation run flag
goto HOUR_TIMER
movf FLASHER,w
andlw B'00001111' ; flash 262ms on each 2 seconds
btfss STATUS,Z
goto HOUR_TIMER
bsf PORTB,6 ; equalisation LED flashes
; hour timer
HOUR_TIMER
incf HOUR1,f ; seconds
movf HOUR1,w
sublw D'52' ; 14 seconds
btfsc STATUS,C
goto BULK_TIME
clrf HOUR1 ; cleared when 14-seconds reached
movf HOUR0,w ; starts at 255 so 256 x 14s = 1 hour
btfss STATUS,Z ; check if zero
decf HOUR0,f ; no decrease if already 0
; decrease bulk timer (used to check if bulk charge < 1 minute
BULK_TIME
movf BULK_TIMER,w
btfss STATUS,Z
decfsz BULK_TIMER,f ; decrease til zero
goto OFF_TIMER
bsf BULK_TIMER_END,0; bulk timer ended flag
; solar panel 4-hour off timer
OFF_TIMER
; off timer is included if RB0 is low
btfsc PORTB,0
goto RECLAIM
incf HOUR2,f ; seconds
movf HOUR2,w
sublw D'208' ; 56 seconds
btfsc STATUS,C
goto RECLAIM
clrf HOUR2 ; cleared when 56-seconds reached
movf HOUR3,w ; starts at 255 so 256 x 56s = 4 hour
btfsc STATUS,Z ; check if zero
goto RECLAIM ; no decrease if already 0
decfsz HOUR3,f ;
goto RECLAIM
clrf CHARGE_STATE ; set to Bulk charge after 4 hours off
clrf BULK_TIMER
clrf BULK_TIMER_END ; bulk timer ended flag
RECLAIM
; end of interrupt reclaim w and status
swapf STATUS_TMP,w; status temp storage to w
movwf STATUS ; w to status register
swapf W_TMP,f ; swap upper and lower 4-bits in w_tmp
swapf W_TMP,w ; swap bits and into w register
retfie ; return from interrupt
;**************************************************************
; Subroutines
; delays
; DELAY for A/D acquisition
DEL_AD
; movlw D'50' ; * 4MHz operation
movlw D'100' ; ** 8MHz operation
movwf DELCNT
DEL1
decfsz DELCNT,f
goto DEL1
bsf ADCON0,2 ; GO/DONE bit start conversion
WAIT_CONV1
btfsc ADCON0,2 ; conversion complete when cleared ~11 cycles
goto WAIT_CONV1
bsf STATUS,RP0 ; select memory bank 1
movf ADRESL,w ; ls bits
bcf STATUS,RP0 ; select memory bank 0
movwf DIGITAL
return
; delay general purpose debounce switch 500ms
DELAY
; movlw D'2' ; * 4MHz operation
movlw D'4' ; ** 8MHz operation number of delay cycles
DELAY_1
movwf DELCNT
DELAY_M
movlw D'255' ; set delay period
movwf VALUE_1 ; VALUE_1 = w
LP_1
movlw D'255' ; set delay period value 2
movwf VALUE_2 ; VALUE_2 = w
LP_2
decfsz VALUE_2,f ; decrease VALUE_2, skip if zero
goto LP_2
decfsz VALUE_1,f ; decrease VALUE_1, skip if zero
goto LP_1
decfsz DELCNT,f
goto DELAY_M
return
DELAY2
; movlw D'4' ; * 4MHz operation set delay period
movlw D'8' ; ** 8MHz operation set delay period
movwf VALUE_1 ; VALUE_1 = w
LP_3
movlw D'255' ; set delay period value 2
movwf VALUE_2 ; VALUE_2 = w
LP_4
decfsz VALUE_2,f ; decrease VALUE_2, skip if zero
goto LP_4
decfsz VALUE_1,f ; decrease VALUE_1, skip if zero
goto LP_3
return
DELAY3
; movlw D'116' ; * 4MHz operation
movlw D'58' ; ** 8MHz operation set delay period value 2 for 50ms max power calc period
movwf VALUE_2 ; VALUE_2 = w
LP_5
decfsz VALUE_2,f ; decrease VALUE_2, skip if zero
goto LP_5
return
;*********************************
; 24x24 Bit Unsigned Fixed Point Multiply 24x24 -> 48
; Input: 24 bit unsigned fixed point multiplicand in AARGB0,1,2
; 24 bit unsigned fixed point multiplier in BARGB0,1,2
; Use: CALL FXM2424U
; Output: 48 bit unsigned fixed point product in AARGB0
; Result: AARG <-- AARG x BARG
; Max Timing: 9+501+2 = 512 clks
; Min Timing: 9+150 = 159 clks
FXM2424U
CLRF AARGB3 ; clear partial product
CLRF AARGB4
CLRF AARGB5
MOVF AARGB0,W
MOVWF TEMPB0
MOVF AARGB1,W
MOVWF TEMPB1
MOVF AARGB2,W
MOVWF TEMPB2
MOVLW H'08'
MOVWF LOOPCOUNT
LOOPUM2424A
RRF BARGB2,F
BTFSC STATUS,C
GOTO ALUM2424NAP
DECFSZ LOOPCOUNT,F
GOTO LOOPUM2424A
MOVWF LOOPCOUNT
LOOPUM2424B
RRF BARGB1,F
BTFSC STATUS,C
GOTO BLUM2424NAP
DECFSZ LOOPCOUNT,F
GOTO LOOPUM2424B
MOVWF LOOPCOUNT
LOOPUM2424C
RRF BARGB0,F
BTFSC STATUS,C
GOTO CLUM2424NAP
DECFSZ LOOPCOUNT,F
GOTO LOOPUM2424C
CLRF AARGB0
CLRF AARGB1
CLRF AARGB2
RETLW 0x00
CLUM2424NAP
BCF STATUS,C
GOTO CLUM2424NA
BLUM2424NAP
BCF STATUS,C
GOTO BLUM2424NA
ALUM2424NAP
BCF STATUS,C
GOTO ALUM2424NA
ALOOPUM2424
RRF BARGB2,F
BTFSS STATUS,C
GOTO ALUM2424NA
MOVF TEMPB2,W
ADDWF AARGB2,F
MOVF TEMPB1,W
BTFSC STATUS,C
INCFSZ TEMPB1,W
ADDWF AARGB1,F
MOVF TEMPB0,W
BTFSC STATUS,C
INCFSZ TEMPB0,W
ADDWF AARGB0,F
ALUM2424NA
RRF AARGB0,F
RRF AARGB1,F
RRF AARGB2,F
RRF AARGB3,F
DECFSZ LOOPCOUNT,F
GOTO ALOOPUM2424
MOVLW H'08'
MOVWF LOOPCOUNT
BLOOPUM2424
RRF BARGB1,F
BTFSS STATUS,C
GOTO BLUM2424NA
MOVF TEMPB2,W
ADDWF AARGB2,F
MOVF TEMPB1,W
BTFSC STATUS,C
INCFSZ TEMPB1,W
ADDWF AARGB1,F
MOVF TEMPB0,W
BTFSC STATUS,C
INCFSZ TEMPB0,W
ADDWF AARGB0,F
BLUM2424NA
RRF AARGB0,F
RRF AARGB1,F
RRF AARGB2,F
RRF AARGB3,F
RRF AARGB4,F
DECFSZ LOOPCOUNT,F
GOTO BLOOPUM2424
MOVLW H'08'
MOVWF LOOPCOUNT
CLOOPUM2424
RRF BARGB0,F
BTFSS STATUS,C
GOTO CLUM2424NA
MOVF TEMPB2,W
ADDWF AARGB2,F
MOVF TEMPB1,W
BTFSC STATUS,C
INCFSZ TEMPB1,W
ADDWF AARGB1,F
MOVF TEMPB0,W
BTFSC STATUS,C
INCFSZ TEMPB0,W
ADDWF AARGB0,F
CLUM2424NA
RRF AARGB0,F
RRF AARGB1,F
RRF AARGB2,F
RRF AARGB3,F
RRF AARGB4,F
RRF AARGB5,F
DECFSZ LOOPCOUNT,F
GOTO CLOOPUM2424
return
;********************************
; 32/32 Bit Unsigned Fixed Point Divide 32/32 -> 32.32
; Input: 32 bit unsigned fixed point dividend in AARGB0, AARGB1,AARGB2,AARGB3
; 32 bit unsigned fixed point divisor in BARGB0, BARGB1, BARGB2, BARGB3
; Use: CALL FXD3232U
; Output: 32 bit unsigned fixed point quotient in AARGB0, AARGB1,AARGB2,AARGB3
; 32 bit unsigned fixed point remainder in REMB0, REMB1, REMB2, REMB3
; Result: AARG, REM <-- AARG / BARG
; Max Timing: 4+1025+2 = 1031 clks
; Max Timing: 4+981+2 = 987 clks
; PM: 4+359+1 = 364 DM: 13
FXD3232U
CLRF REMB0
CLRF REMB1
CLRF REMB2
CLRF REMB3
call UDIV3232L
return
UDIV3232L
; Max Timing: 24+6*32+31+31+6*32+31+31+6*32+31+31+6*32+31+16 = 1025 clks
; Min Timing: 24+6*31+30+30+6*31+30+30+6*31+30+30+6*31+30+3 = 981 clks
; PM: 359 DM: 13
CLRF TEMP
RLF AARGB0,W
RLF REMB3,F
MOVF BARGB3,W
SUBWF REMB3,F
MOVF BARGB2,W
BTFSS STATUS,C
INCFSZ BARGB2,W
SUBWF REMB2,F
MOVF BARGB1,W
BTFSS STATUS,C
INCFSZ BARGB1,W
SUBWF REMB1,F
MOVF BARGB0,W
BTFSS STATUS,C
INCFSZ BARGB0,W
SUBWF REMB0,F
CLRW
BTFSS STATUS,C
MOVLW H'1'
SUBWF TEMP,F
RLF AARGB0,F
MOVLW H'7'
MOVWF LOOPCOUNT
LOOPU3232A
RLF AARGB0,W
RLF REMB3,F
RLF REMB2,F
RLF REMB1,F
RLF REMB0,F
RLF TEMP,F
MOVF BARGB3,W
BTFSS AARGB0,0
GOTO UADD22LA
SUBWF REMB3,F
MOVF BARGB2,W
BTFSS STATUS,C
INCFSZ BARGB2,W
SUBWF REMB2,F
MOVF BARGB1,W
BTFSS STATUS,C
INCFSZ BARGB1,W
SUBWF REMB1,F
MOVF BARGB0,W
BTFSS STATUS,C
INCFSZ BARGB0,W
SUBWF REMB0,F
CLRW
BTFSS STATUS,C
MOVLW H'1'
SUBWF TEMP,F
GOTO UOK22LA
UADD22LA
ADDWF REMB3,F
MOVF BARGB2,W
BTFSC STATUS,C
INCFSZ BARGB2,W
ADDWF REMB2,F
MOVF BARGB1,W
BTFSC STATUS,C
INCFSZ BARGB1,W
ADDWF REMB1,F
MOVF BARGB0,W
BTFSC STATUS,C
INCFSZ BARGB0,W
ADDWF REMB0,F
CLRW
BTFSC STATUS,C
MOVLW H'1'
ADDWF TEMP,F
UOK22LA
RLF AARGB0,F
DECFSZ LOOPCOUNT,F
GOTO LOOPU3232A
RLF AARGB1,W
RLF REMB3,F
RLF REMB2,F
RLF REMB1,F
RLF REMB0,F
RLF TEMP,F
MOVF BARGB3,W
BTFSS AARGB0,0
GOTO UADD22L8
SUBWF REMB3,F
MOVF BARGB2,W
BTFSS STATUS,C
INCFSZ BARGB2,W
SUBWF REMB2,F
MOVF BARGB1,W
BTFSS STATUS,C
INCFSZ BARGB1,W
SUBWF REMB1,F
MOVF BARGB0,W
BTFSS STATUS,C
INCFSZ BARGB0,W
SUBWF REMB0,F
CLRW
BTFSS STATUS,C
MOVLW H'1'
SUBWF TEMP,F
GOTO UOK22L8
UADD22L8
ADDWF REMB3,F
MOVF BARGB2,W
BTFSC STATUS,C
INCFSZ BARGB2,W
ADDWF REMB2,F
MOVF BARGB1,W
BTFSC STATUS,C
INCFSZ BARGB1,W
ADDWF REMB1,F
MOVF BARGB0,W
BTFSC STATUS,C
INCFSZ BARGB0,W
ADDWF REMB0,F
CLRW
BTFSC STATUS,C
MOVLW H'1'
ADDWF TEMP,F
UOK22L8
RLF AARGB1,F
MOVLW H'7'
MOVWF LOOPCOUNT
LOOPU3232B
RLF AARGB1,W
RLF REMB3,F
RLF REMB2,F
RLF REMB1,F
RLF REMB0,F
RLF TEMP,F
MOVF BARGB3,W
BTFSS AARGB1,0
GOTO UADD22LB
SUBWF REMB3,F
MOVF BARGB2,W
BTFSS STATUS,C
INCFSZ BARGB2,W
SUBWF REMB2,F
MOVF BARGB1,W
BTFSS STATUS,C
INCFSZ BARGB1,W
SUBWF REMB1,F
MOVF BARGB0,W
BTFSS STATUS,C
INCFSZ BARGB0,W
SUBWF REMB0,F
CLRW
BTFSS STATUS,C
MOVLW H'1'
SUBWF TEMP,F
GOTO UOK22LB
UADD22LB
ADDWF REMB3,F
MOVF BARGB2,W
BTFSC STATUS,C
INCFSZ BARGB2,W
ADDWF REMB2,F
MOVF BARGB1,W
BTFSC STATUS,C
INCFSZ BARGB1,W
ADDWF REMB1,F
MOVF BARGB0,W
BTFSC STATUS,C
INCFSZ BARGB0,W
ADDWF REMB0,F
CLRW
BTFSC STATUS,C
MOVLW H'1'
ADDWF TEMP,F
UOK22LB
RLF AARGB1,F
DECFSZ LOOPCOUNT,F
GOTO LOOPU3232B
RLF AARGB2,W
RLF REMB3,F
RLF REMB2,F
RLF REMB1,F
RLF REMB0,F
RLF TEMP,F
MOVF BARGB3,W
BTFSS AARGB1,0
GOTO UADD22L16
SUBWF REMB3,F
MOVF BARGB2,W
BTFSS STATUS,C
INCFSZ BARGB2,W
SUBWF REMB2,F
MOVF BARGB1,W
BTFSS STATUS,C
INCFSZ BARGB1,W
SUBWF REMB1,F
MOVF BARGB0,W
BTFSS STATUS,C
INCFSZ BARGB0,W
SUBWF REMB0,F
CLRW
BTFSS STATUS,C
MOVLW H'1'
SUBWF TEMP,F
GOTO UOK22L16
UADD22L16
ADDWF REMB3,F
MOVF BARGB2,W
BTFSC STATUS,C
INCFSZ BARGB2,W
ADDWF REMB2,F
MOVF BARGB1,W
BTFSC STATUS,C
INCFSZ BARGB1,W
ADDWF REMB1,F
MOVF BARGB0,W
BTFSC STATUS,C
INCFSZ BARGB0,W
ADDWF REMB0,F
CLRW
BTFSC STATUS,C
MOVLW H'1'
ADDWF TEMP,F
UOK22L16
RLF AARGB2,F
MOVLW H'7'
MOVWF LOOPCOUNT
LOOPU3232C
RLF AARGB2,W
RLF REMB3,F
RLF REMB2,F
RLF REMB1,F
RLF REMB0,F
RLF TEMP,F
MOVF BARGB3,W
BTFSS AARGB2,0
GOTO UADD22LC
SUBWF REMB3,F
MOVF BARGB2,W
BTFSS STATUS,C
INCFSZ BARGB2,W
SUBWF REMB2,F
MOVF BARGB1,W
BTFSS STATUS,C
INCFSZ BARGB1,W
SUBWF REMB1,F
MOVF BARGB0,W
BTFSS STATUS,C
INCFSZ BARGB0,W
SUBWF REMB0,F
CLRW
BTFSS STATUS,C
MOVLW H'1'
SUBWF TEMP,F
GOTO UOK22LC
UADD22LC
ADDWF REMB3,F
MOVF BARGB2,W
BTFSC STATUS,C
INCFSZ BARGB2,W
ADDWF REMB2,F
MOVF BARGB1,W
BTFSC STATUS,C
INCFSZ BARGB1,W
ADDWF REMB1,F
MOVF BARGB0,W
BTFSC STATUS,C
INCFSZ BARGB0,W
ADDWF REMB0,F
CLRW
BTFSC STATUS,C
MOVLW H'1'
ADDWF TEMP,F
UOK22LC
RLF AARGB2,F
DECFSZ LOOPCOUNT,F
GOTO LOOPU3232C
RLF AARGB3,W
RLF REMB3,F
RLF REMB2,F
RLF REMB1,F
RLF REMB0,F
RLF TEMP,F
MOVF BARGB3,W
BTFSS AARGB2,0
GOTO UADD22L24
SUBWF REMB3,F
MOVF BARGB2,W
BTFSS STATUS,C
INCFSZ BARGB2,W
SUBWF REMB2,F
MOVF BARGB1,W
BTFSS STATUS,C
INCFSZ BARGB1,W
SUBWF REMB1,F
MOVF BARGB0,W
BTFSS STATUS,C
INCFSZ BARGB0,W
SUBWF REMB0,F
CLRW
BTFSS STATUS,C
MOVLW H'1'
SUBWF TEMP,F
GOTO UOK22L24
UADD22L24
ADDWF REMB3,F
MOVF BARGB2,W
BTFSC STATUS,C
INCFSZ BARGB2,W
ADDWF REMB2,F
MOVF BARGB1,W
BTFSC STATUS,C
INCFSZ BARGB1,W
ADDWF REMB1,F
MOVF BARGB0,W
BTFSC STATUS,C
INCFSZ BARGB0,W
ADDWF REMB0,F
CLRW
BTFSC STATUS,C
MOVLW H'1'
ADDWF TEMP,F
UOK22L24
RLF AARGB3,F
MOVLW H'7'
MOVWF LOOPCOUNT
LOOPU3232D
RLF AARGB3,W
RLF REMB3,F
RLF REMB2,F
RLF REMB1,F
RLF REMB0,F
RLF TEMP,F
MOVF BARGB3,W
BTFSS AARGB3,0
GOTO UADD22LD
SUBWF REMB3,F
MOVF BARGB2,W
BTFSS STATUS,C
INCFSZ BARGB2,W
SUBWF REMB2,F
MOVF BARGB1,W
BTFSS STATUS,C
INCFSZ BARGB1,W
SUBWF REMB1,F
MOVF BARGB0,W
BTFSS STATUS,C
INCFSZ BARGB0,W
SUBWF REMB0,F
CLRW
BTFSS STATUS,C
MOVLW H'1'
SUBWF TEMP,F
GOTO UOK22LD
UADD22LD
ADDWF REMB3,F
MOVF BARGB2,W
BTFSC STATUS,C
INCFSZ BARGB2,W
ADDWF REMB2,F
MOVF BARGB1,W
BTFSC STATUS,C
INCFSZ BARGB1,W
ADDWF REMB1,F
MOVF BARGB0,W
BTFSC STATUS,C
INCFSZ BARGB0,W
ADDWF REMB0,F
CLRW
BTFSC STATUS,C
MOVLW H'1'
ADDWF TEMP,F
UOK22LD
RLF AARGB3,F
DECFSZ LOOPCOUNT, F
GOTO LOOPU3232D
BTFSC AARGB3,0
GOTO UOK22L
MOVF BARGB3,W
ADDWF REMB3,F
MOVF BARGB2,W
BTFSC STATUS,C
INCFSZ BARGB2,W
ADDWF REMB2,F
MOVF BARGB1,W
BTFSC STATUS,C
INCFSZ BARGB1,W
ADDWF REMB1,F
MOVF BARGB0,W
BTFSC STATUS,C
INCFSZ BARGB0,W
ADDWF REMB0,F
UOK22L
RETURN
;******************
; 8 x 8 multiply
EIGHTEIGHT CLRF AARGB1 ; clear partial product
UMUL0808L
MOVLW H'08'
MOVWF LOOPCOUNT
MOVF AARGB0,W
LOOPUM0808A
RRF BARGB0, F
BTFSC STATUS,C
GOTO LUM0808NAP
DECFSZ LOOPCOUNT, F
GOTO LOOPUM0808A
CLRF AARGB0
RETLW H'00'
LUM0808NAP
BCF STATUS,C
GOTO LUM0808NA
LOOPUM0808
RRF BARGB0, F
BTFSC STATUS,C
ADDWF AARGB0, F
LUM0808NA RRF AARGB0, F
RRF AARGB1, F
DECFSZ LOOPCOUNT,F
GOTO LOOPUM0808
return
end
.HEX
:020000040000FA
:020000009E2838
:080008001D2B82073C343B3440
:100010003A343A343934393438343834373436347D
:100020003634353435343434343433343234323491
:10003000323431343134303430342F342F342E34A0
:100040002E342D342D342C342C342B342B342B34AF
:100050002A342A34293429342834283428342734BB
:1000600027342634263426342534253424342434C5
:1000700024342334233422342234223421342134CE
:1000800021342034203420341F341F341E341E34D5
:100090001E341D341D341D341C341C341C341B34DC
:1000A0001B341B341A341A341A34193419341834E2
:1000B00018341834183417341734173416341634E7
:1000C00016341534153415341434143414341334EC
:1000D00013341334123412341234113411341134F1
:1000E0001034103410340F340F340F340E340E34F7
:1000F0000E340D340D340D340C340C340C340B34FC
:100100000B340B340A340A340A3409340934083401
:100110000834083407340734073406340634063408
:100120000534053404340434043403340334023411
:100130000234023401340134003400348601850174
:10014000831607309C00133086003F30850007304F
:1001500081001F309B00C0309F00831240309F0001
:100160001F14831678308F008312313090001014E2
:1001700083163F3092008312950117129712920155
:1001800012150C30970086018501AC010130B600D4
:10019000B700BC01BD010530C100C201A101C3010E
:1001A000C401AA01BE01B401B501D201D101C90146
:1001B0004914CE01CF01D001D301D4010330A200F4
:1001C0009830A3000330A4005F30A5000330CB00BB
:1001D000F430CA0083160C1483120C100B178B1703
:1001E000B60BD129B70BD1290830B700061EFD2860
:1001F0004E1E1229C901491417294E1E1729B6236C
:10020000061A1729CE01C9018B138513861305130E
:100210000617B6230613B6230617B6230613B6230E
:100220008B171729B623061E17294E1649149F123D
:100230001F129F15AA239E0CA00C9E0CA00C200838
:10024000A6009F161F129F11AA239E0CA00C9E0CA5
:10025000A00C2008FA3C8B13AC01031831292C1494
:100260003A292008C73CC730031CA00004302002F4
:10027000031CAC148B172008C73CC830031CA0001B
:100280003130A002031CA00120080520AB00B10101
:1002900014302B02031CB117EA00B11F52292B089E
:1002A000143CEA002608EE00B0256908E8006A0858
:1002B000E900EA016430EC00ED01EE01D1236808A9
:1002C000EA006708E9006608E8006508E700EE0153
:1002D000ED011F30EC004030EB003824B11B8729C2
:1002E00067082302AE002208031C2203AD00AD1FE5
:1002F0007B29AD01AE0167084A02CC004B08031C04
:100300004B03CD00CD1FA129CD01CC01A12922088D
:10031000AD0067082307AE000318AD0A2D1D942910
:100320000330AD00FF30AE004B08CD0067084A0730
:10033000CC000318CD0A4D1DA1290330CD00FF309C
:10034000CC00B11BAF2967082502B0002408031CAC
:100350002403AF00AF1FBC29AF01B001BC292408A2
:10036000AF0067082507B0000318AF0A2F1DBC298E
:100370000330AF00FF30B0009F121F129F11AA235D
:100380002008A8001E08A7002708033CA000280892
:100390001C3C031CA003A01BD029BC01D301D40129
:1003A0003E14AC1CD5293D14202A2C1CD9293D14FF
:1003B000202A2708023CA00028089F3C031CA00319
:1003C000A01F0E2BD001C91CE7290615082A2708F3
:1003D000033CA0002808BF3C031CA003A01FF42975
:1003E0003D144F140615202A2708023CA0002808B7
:1003F000FF3C031CA003A01FFF290611082A2708A1
:10040000023CA0002808DF3C031CA003A01F061527
:100410004F109F121F169F11AA232008B8001E0814
:10042000B9003908013CA0003808B03C031CA00307
:10043000A01F202AD101BD013C0803192E2A952AAC
:100440003D149501A1010530C1005108031DF0289C
:100450008313FF30D100D2018317F02827082D0223
:10046000A00028082E02031CA003A01F432A541832
:100470003C2AB401D401402A9501B501FF30B400F3
:100480000530C100952A3C08031D4B2A5308031D63
:100490004B2AE530D3004108031DF0282108031D35
:1004A000582AC301C4019501C323C201FF30A10032
:1004B0009F121F169F15AA232008BA001E08BB0012
:1004C0009F121F169F11AA232008B8001E08B9000A
:1004D000390CA000380CBF00200CBF0C3B0CA00056
:1004E0003A0CC000200CC00C3F08EA004008EE00A7
:1004F000B0256A084302A00069084402031CA00357
:10050000A01F882A6A08C3006908C4001508C20031
:100510001508403C031C8F2A950ACC23F0284C3048
:10052000C100A10142089500F0280130BC00D401AF
:100530009F121F129F11AA232008A8001E08A700BF
:100540002708033A031DA82A2808FF3A0319202A7E
:10055000270CC500280CC600450CC60C340803192E
:10056000D72A4E1AC62A4918C62AC9144D0CC700E4
:100570004C0CC800470CC80C27084D02A0002808E6
:100580004C02031CA003A01FF42A002BC9102D0C41
:10059000C7002E0CC800470CC80C27082D02A0006D
:1005A00028082E02031CA003A01FF42A002B4914C4
:1005B000C9184915C9102F0CC700300CC800470CCA
:1005C000C80C27082F02A00028083002031CA00333
:1005D000A01B002B8618F42A42081502031CF42ADB
:1005E000BC01D301D401F02815084202031C432AA0
:1005F0000319432A150A403C031C432A950AF02894
:100600004808C6024608033C031C0C2B460815028A
:10061000031C03019500F0289501F02850140513E0
:10062000861306132A080F39031D1A2B851740302D
:100630009500F02885139501F028F000030EF100D5
:10064000831203130C10AA0A4108031DC1032C1CBA
:10065000352B85130513861306132A080F39031942
:10066000332B8612802B8616802BAC1C432B8513D4
:100670000513861306132A0807390319412B86121E
:10068000802B8616802B4F1C502B051386130613C8
:100690002A08073903194E2B8513802B8517802BC9
:1006A0003D08031D742B5018752B3C1C6E2B340811
:1006B0000319682BC91C622B861285138613051338
:1006C0000617802B86128513861306130517802BB9
:1006D00086128513861705130613802B861285173D
:1006E000051386130613802B851305138613061333
:1006F000491D872B2A080F39031D952B0617952BAB
:10070000491D872B2A080F39031D872B0617B50AA9
:100710003508343C0318902BB5013408031DB4038D
:100720005308031DD30B952B54140618A52BD20A7E
:100730005208D03C0318A52BD20151080319A52B50
:10074000D10BA52BBC01D301D401710E8300F00E97
:10075000700E09006430A900A90BAC2B1F151F19DE
:10076000AF2B83161E088312A00008000430A900D6
:10077000FF30B200FF30B300B30BBC2BB20BBA2B6F
:10078000A90BB82B08000830B200FF30B300B30B40
:10079000C72BB20BC52B08003A30B300B30BCE2BDE
:1007A0000800E701E601E5016A08DD006908DE00EE
:1007B0006808DF000830EF00EC0C0318F52BEF0B96
:1007C000DC2BEF00ED0C0318F32BEF0BE22BEF000B
:1007D000EE0C0318F12BEF0BE82BEA01E901E8011D
:1007E000003403102F2C0310192C0310042CEC0CD4
:1007F000031C042C5F08E8075E0803185E0FE90776
:100800005D0803185D0FEA07EA0CE90CE80CE70C39
:10081000EF0BF72B0830EF00ED0C031C192C5F08D1
:10082000E8075E0803185E0FE9075D0803185D0F0F
:10083000EA07EA0CE90CE80CE70CE60CEF0B0C2CD1
:100840000830EF00EE0C031C2F2C5F08E8075E0851
:1008500003185E0FE9075D0803185D0FEA07EA0C4D
:10086000E90CE80CE70CE60CE50CEF0B222C080079
:10087000E401E301E201E1013E240800E0016A0D28
:10088000E10D6B08E1026C08031C6C0FE2026D08BD
:10089000031C6D0FE3026E08031C6E0FE4020301DC
:1008A000031C0130E002EA0D0730EF006A0DE10D94
:1008B000E20DE30DE40DE00D6B086A1C712CE10202
:1008C0006C08031C6C0FE2026D08031C6D0FE30241
:1008D0006E08031C6E0FE4020301031C0130E002EA
:1008E000822CE1076C0803186C0FE2076D080318EF
:1008F0006D0FE3076E0803186E0FE407030103187A
:100900000130E007EA0DEF0B562C690DE10DE20D09
:10091000E30DE40DE00D6B086A1CA02CE1026C08ED
:10092000031C6C0FE2026D08031C6D0FE3026E08DE
:10093000031C6E0FE4020301031C0130E002B12C22
:10094000E1076C0803186C0FE2076D0803186D0FC0
:10095000E3076E0803186E0FE40703010318013064
:10096000E007E90D0730EF00690DE10DE20DE30D41
:10097000E40DE00D6B08691CCF2CE1026C08031C30
:100980006C0FE2026D08031C6D0FE3026E08031C7E
:100990006E0FE4020301031C0130E002E02CE107CA
:1009A0006C0803186C0FE2076D0803186D0FE3075E
:1009B0006E0803186E0FE407030103180130E00707
:1009C000E90DEF0BB42C680DE10DE20DE30DE40D24
:1009D000E00D6B08691CFE2CE1026C08031C6C0F17
:1009E000E2026D08031C6D0FE3026E08031C6E0F1C
:1009F000E4020301031C0130E0020F2DE1076C0843
:100A000003186C0FE2076D0803186D0FE3076E08FB
:100A100003186E0FE407030103180130E007E80D27
:100A20000730EF00680DE10DE20DE30DE40DE00D80
:100A30006B08681C2D2DE1026C08031C6C0FE20290
:100A40006D08031C6D0FE3026E08031C6E0FE402B9
:100A50000301031C0130E0023E2DE1076C0803187E
:100A60006C0FE2076D0803186D0FE3076E0803189B
:100A70006E0FE407030103180130E007E80DEF0BE8
:100A8000122D670DE10DE20DE30DE40DE00D6B0895
:100A9000681C5C2DE1026C08031C6C0FE2026D08FF
:100AA000031C6D0FE3026E08031C6E0FE4020301CA
:100AB000031C0130E0026D2DE1076C0803186C0F78
:100AC000E2076D0803186D0FE3076E0803186E0F39
:100AD000E407030103180130E007E70D0730EF00DA
:100AE000670DE10DE20DE30DE40DE00D6B08671CF1
:100AF0008B2DE1026C08031C6C0FE2026D08031CD5
:100B00006D0FE3026E08031C6E0FE4020301031C69
:100B10000130E0029C2DE1076C0803186C0FE2071E
:100B20006D0803186D0FE3076E0803186E0FE407D6
:100B3000030103180130E007E70DEF0B702D671874
:100B4000AF2D6B08E1076C0803186C0FE2076D0806
:100B500003186D0FE3076E0803186E0FE407080013
:100B6000E9010830EF006A08EE0C0318BB2DEF0B0B
:100B7000B42DEA0100340310C02DEE0C0318EA076F
:0A0B8000EA0CE90CEF0BBD2D080094
:02400E00700F31
:02401000FC3F73
:00000001FF