; 100W 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