'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:
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
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