Solar Charge Station Controller Picaxe Basic Program

Declarations and Data

'Solar ChargerTxV1.bas

#picaxe 20M2

'John Sainders 4/6/2016


'Output ports

'symbol TxPort    = A.0        'Serial Output port-supported by the 20X2 but not the 20M2

symbol Disp_clk  = B.2        '74H595 clocks on low to high

symbol Disp_data = B.1        'MSB first

symbol Disp_en   = B.0        'Positive pulse clocks the data & RS into the QC1602 display

symbol Shutdown  = B.4

symbol Batt_Chg  = B.5

symbol ScopePort = C.0


'input ports

symbol Batt_Port = C.2

symbol Curr_Port = C.7

symbol Volt_Port = C.3

symbol One_Hz    = pinC.1

symbol RangePort = B.3


'Constants

symbol Showtime  = 6        'The number of seconds the new AH limit is displayed

symbol MinExtV   = 250        'Below this voltage (in 1/100 V) there is no external battery present

symbol Recharge  = 600        'Below this, charge the internal battery

symbol FullCharge = 700        'Above this the internal battery is fully charged

symbol TxPer     = 75        'The number of 4-second periogs petween transmissions

        

DATA 0,(128,64,32,16,8,4,2,1)                'Mask for shifting into the 74H595

DATA 8,($30,$30,$30,$38,$0C,$01,$06,$14,$80)    'Display Initialization string


DATA 30,(" MA ",0)

DATA 35,(" V",0)

DATA 40,(" V ",0)

DATA 45,(" AH",0)


DATA 60,(5,9,15,22,30,46,255)    'Charging limit for the ext batt for ranges 0-6 in 1/10 AH


#rem 

Display formatting parameters: Source = 30-34, Destination = 82 to 108 (Range is 80)

Source memory address for first formatted character 

Source memory address for character with DP following, or 0

Address in destination of the first character

Display location of first character 

Fixed string data address

#endrem

DATA 80, (30,31, 82,$C7,45)    'Ampere hours,

DATA 85, (32, 0, 89,$C0,30)    'Current in MA

DATA 90, (31,32, 93,$89,35)    'External battery charging voltage

DATA 95, (32,32, 99,$82,40)    'Internal battery voltage

DATA 100,(32,33,104,$C7,45)    'Ampere-hour limit


'variables

'Display Interface

symbol RS        = bit7        'Low for command, High for data

symbol Mask      = b1        'Used to bit-bang to the 74H595 shift register

symbol Mask_Addr = b2        'Used to bit'Used to bit-bang to the 74HC595 shift register

symbol Scratch   = b3        'Used to bit'Used to bit-bang to the 74HC595 shift register


;Display Formatting

symbol Disp_loc  = b4        'A display address:$80-$8F.$C0-$CF

symbol Data_addr = b5        'Location of the data character in memory

symbol StartAddr = b6        'Position in 30-43 of the first character

symbol DP_Loc    = b7        'Position in 30-43 of the character before the decimal point

symbol String_addr = b8        'Location of string in EEPROM

symbol Mem_addr  = b9        'Address in memory of the character to be displayed


'global and general

symbol ExtBatt   = bit0        '1 is external nattery detected

symbol IntBatt   = bit1        '1 is battery charged, 0 needs charging

symbol Char      = b10        'Used to bit-bang to the 74H595 shift register

symbol Range     = b11        '0-7.0-6 controls ampere-hours to shutoff, 7 is shutdown

symbol Dummy     = b12        'General use

symbol Old_range = b13

symbol Phase     = b14        'Increments every second 0 to 3

symbol Iter      = b15        'General use

symbol ShowCtr   = b16        'Counts the number of seconds the AH limit is shown

symbol Tx_cnt    = b17        'Counts the number of 4-secomd periods between transmissions


'Analog measurement

symbol ChgAccum  = W10        'Used to accumulate charging current

symbol ADCData   = W11        'ADC output 

symbol Disp_val  = W12        'Value to be displayed

symbol Amp_hrs   = W13        'Increments for each milli-watt-hour


Init and  Main

init:

SETFREQ m8

LOW Disp_en            

LOW Disp_clk

FOR Data_addr = 8 TO 16

    READ Data_addr,Char

    GOSUB Disp_cmd

    PAUSE 5

NEXT

LOW Shutdown

LOW Batt_Chg

LET Phase = 0

LET Range = 4

LET ShowCtr = 0

LET Tx_cnt = 0

LET IntBatt = 0

LET Amp_Hrs = 0

LET Disp_val = 0

LET Data_Addr = 80        'Ampere-hours

GOSUB StoreAnalog

LET ADCSetup = %1000110000001000


main:    

INC Phase

IF Phase > 3 THEN

    INC Tx_cnt

    IF Tx_cnt > TxPer THEN

        LET Tx_cnt = 0

        LET Phase = 4

    ELSE

        LET Phase = 0

    ENDIF

ENDIF

IF ShowCtr > 0 THEN

    DEC ShowCtr

ENDIF

rem Get the range

LET Old_range = Range

LET Dummy = 17

ADCconfig 0                    '5V ref.

READADC RangePort,Scratch

FOR Range = 0 TO 7

    IF Scratch < Dummy THEN Exit

    LET Dummy = Dummy + 30

NEXT

LET Char = $80

GOSUB Disp_Cmd

LET Char = Range + "0"

IF ExtBatt = 0 THEN

    IF IntBatt = 0 THEN

        LET Char = "B"

    ELSE

        LET Char = "H"

    ENDIF

ENDIF

IF Range > 6 THEN

    LET Char = "S"

ENDIF

POKE 80,Char,","

GOSUB Disp_Char

LET Char = " "

GOSUB Disp_Char

IF Range <> Old_range THEN

    LET ShowCtr = Showtime

    LET ChgAccum = 0

        IF Old_Range = 6 THEN    'Reset ampere-hours

        LET Amp_hrs = 0

        LET Disp_val = 0

        LET Data_Addr = 80        'Ampere-hours

        GOSUB StoreAnalog

    ENDIF

    IF Range < 7 THEN            'Store the Ampere-hour limit

        LET Data_Addr = 60 + Range

        READ Data_Addr,Disp_val

        LET Data_Addr = 100

        GOSUB StoreAnalog

    ENDIF

ENDIF

FVRSetup FVR2048                'Internal 2.048V ref.

ADCconfig %011                'Use internal reference


rem Display is split up into 4 phases becauuse the display is so slow

rem Measure the external battery voltage store and display in phase 0

IF Phase = 0 THEN

rem The internal battery is charged only if there is no external battery connected

    HIGH Shutdown

    PAUSE 360

    READADC10 Volt_Port,ADCData

    LET Disp_val = 8 * ADCData

    LET Disp_val = Disp_val / 5

    LET Data_Addr = 90

    GOSUB StoreAnalog

    IF Disp_val < MinExtV THEN

        LET ExtBatt = 0

        IF Range < 7 THEN

            LOW Shutdown

        ENDIF

    ELSE

        LET ExtBatt = 1

        LET Data_Addr = 60 + range

        READ Data_Addr,Dummy

        LET ADCData = 100 * Dummy

        IF Range < 7 AND Amp_Hrs < ADCData THEN

            LOW Shutdown

        ENDIF

    ENDIF

    LET Data_Addr = 92

    GOSUB Display_field            'External volts

ENDIF


rem Currents depend on whether there is an external battery present

IF ExtBatt = 1 THEN    'An external battery is present, read its charging current

    READADC10 Curr_Port,ADCData

rem Increment the ampere hours if a milliamp-hour has passed and store it

    LET ChgAccum = ChgAccum + ADCData

    IF ChgAccum > 10800 THEN        '3600x6/2

        LET Amp_hrs = Amp_hrs + 1

        LET Disp_val = Amp_hrs

        LET Data_Addr = 80

        GOSUB StoreAnalog

        LET ChgAccum = ChgAccum - 10800

    ENDIF

    LET Disp_val = ADCData/3            'gain is 6, shunt is 1 ohm, scale is 2V for 1000

    LET Data_Addr = 85      

    GOSUB StoreAnalog                    'External battery current

ENDIF


IF Phase = 1 THEN        'Measure the internal voltage, and charging current if applicable

    LOW Batt_Chg

    PAUSE 20

    READADC10 Batt_Port,ADCdata        'Read and Store Battery voltage, save raw voltage in ADCData

    LET Disp_val = 8 * ADCdata        '16 V full-scale for 1000    

    LET Disp_val = Disp_val / 5

    LET Data_Addr = 95

    GOSUB StoreAnalog

    IF Disp_Val > FullCharge THEN

        LET IntBatt = 1            'Leave internal battery charging off

    ENDIF

    IF Disp_Val < ReCharge THEN

        LET IntBatt = 0            'Battery charging on only if no external battery

    ENDIF

    LET Disp_val = 0                'Default zero charging current

    IF ExtBatt = 0 AND IntBatt = 0 THEN    'Read internal battery charging current

        HIGH Batt_Chg

        PAUSE 20

        READADC10 Batt_Port,Disp_val        'Charging voltage    via 40 ohms

        IF Disp_val > ADCData  THEN        'ADCData is the raw battery voltage count

            LET ADCData = Disp_val - ADCData    'Get charging current

rem Increment the ampere hours if a milliamp-hour has passed

            LET ChgAccum = ChgAccum + ADCData

            IF ChgAccum > 2250 THEN        '3600/4*40/16

                LET Amp_hrs = Amp_hrs + 1

                LET Disp_val = Amp_hrs

                LET Data_Addr = 80

                GOSUB StoreAnalog            'Store Ampere-hours

                LET ChgAccum = ChgAccum - 2250

            ENDIF

            LET Disp_val = 2 * ADCData        'Convert current to engineering units

            LET Disp_val = Disp_val / 5        'The dropping resistor is 40 ohms

        ENDIF

    ENDIF

    LET Data_Addr = 85

    GOSUB StoreAnalog            'Store Charging current

    LET Data_Addr = 97

    GOSUB Display_field        'Internal battery voltage

ENDIF


rem Display the current in phase 2

IF Phase = 2 THEN

    LET Data_Addr = 87

    GOSUB Display_Field

ENDIF


rem Display the ampere-hours or the Limit in phase 3

IF Phase = 3 THEN

    IF ShowCtr > 0 THEN

        LET Data_Addr = 102

    ELSE

        LET Data_Addr = 82

    ENDIF

    GOSUB Display_Field

ENDIF


IF Phase = 4 THEN

    SETFREQ k250

    SERTXD (0)

    SETFREQ m2

    PAUSE 2

    LET Bptr = 80

rem                          80       81        82      83       84       85       86       87       88

    SERTXD ("14L1776p,",@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc)

rem              89       90       91        92      93       94        95      96       97       98

    SERTXD (@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc,@Bptrinc)

rem              99       100      101     102

    SERTXD (@Bptrinc,@Bptrinc,@Bptrinc,@Bptr,13,10)

    SETFREQ m8

ENDIF


DO WHILE One_Hz = 1

    PAUSE 1

LOOP


GOTO main

Sub-programs

Shift_595:                    'MSB first            

FOR Mask_Addr = 0 to 7

    READ Mask_Addr,Mask

    LET Scratch = Char & Mask

    LOW Disp_data

    IF Scratch = 0 THEN BitisLow

    HIGH Disp_data

BitisLow:

    PULSOUT Disp_clk,1    

NEXT

IF RS = 0 THEN

    LOW Disp_data

ELSE

    HIGH Disp_data

ENDIF

PULSOUT Disp_en,15            

RETURN



Disp_Cmd:

LET RS = 0

GOSUB Shift_595

RETURN



Disp_Char:

LET RS = 1

GOSUB Shift_595

RETURN


StoreAnalog:

'Store the analog value in Disp_val at 30, then format and transfer per the array at Data_Addr

LET Bptr = 30

BINTOASCII Disp_val,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptr    'MSD first

READ Data_Addr,StartAddr,DP_Loc,Mem_Addr

LET Bptr = Mem_Addr

FOR Iter = StartAddr TO 34

    PEEK Iter, Char

    LET @bptrinc = Char

    IF Iter = DP_Loc THEN

        LET Char = "."

        LET @bptrinc = Char

    ENDIF

NEXT

LET @bptr = ","            'Always add a comma for the spreadsheet

RETURN


Display_Field:        'Displays the analog value with parameters in Data_Addr

READ Data_addr,Mem_Addr,Disp_loc,String_Addr

LET Char = Disp_loc

GOSUB Disp_cmd

IF Data_Addr = 102 THEN

    LET Char = " "

    GOSUB Disp_Char

    GOSUB Disp_Char

ENDIF

LET bptr = Mem_Addr

DO

    LET Char = @bptrinc

    IF Char <> "," THEN

        GOSUB Disp_Char

    ENDIF

LOOP WHILE Char <> ","

DO                    'Add units string

    READ String_addr,Char

    IF Char = 0 THEN

        EXIT

    ENDIF

    GOSUB Disp_Char

    INC String_addr

LOOP

RETURN