'---------------------------------------------------------------------------------------- ' ' Solar Experiments PICAXE Code ' ' file: picaxe_sun_tracker.bas ' ' created: 9-12-2009 ' updated: 9-26-2009 ' ' owner: LearnOnLine, Inc. ' author: John Gavlik ' ' created for the PicAxe 28X2 microprocessor uisng internal 8Mhz oscillator ' '---------------------------------------------------------------------------------------- '---------------------------------------------------------------------------------------- ' ' A/D Setup - Use all A/D channels ' '---------------------------------------------------------------------------------------- let adcsetup = %0001111111111111 'Bit 0 - ADC0 'Bit 1 - ADC1 'Bit 2 - ADC2 'Bit 3 - ADC3 'Bit 4 - ADC4 non existant on X2 'Bit 5 - ADC5 non existant on X2 'Bit 6 - ADC6 non existant on X2 'Bit 7 - ADC7 non existnat on X2 'Bit 8 - ADC8 'Bit 9 - ADC9 'Bit 10 - ADC10 'Bit 11 - ADC11 'Bit 12 - ADC12 'unused 'Vref+ 'Vref- '---------------------------------------------------------------------------------------- ' ' Defines ' '---------------------------------------------------------------------------------------- #com4 'change com port number to match your system #picaxe 28X2 'don't change this!!! '---------------------------------------------------------------------------------------- ' ' Important I/O Pins for PIC 28X2 Microprocessor ' '---------------------------------------------------------------------------------------- ' solarVolts pin 25 (ADC11) 'Solar panel voltage ' solarCurrent pin 22 (ADC10) 'bottom of 1 ohm sense resistor for solar panel ' battVolts pin 24 (ADC9) 'Battery voltage ' battCurrent pin 21 (ADC12) 'bottom of 1 ohm sense resistor for battery ' ' serin pin 6 ' serout pin 7 (A.4) ' reset pin 1 ' gnd pin 8 & 19 ' +5v pin 20 ' ' Q1 pin 25 (B.5) 'charge ON-OFF transistor switch ' chargeLed pin 28 (B.7) 'charging LED ' ' hBridgeEastHiBase pin 13 (C.2) 'H-Bridge controls ' hBridgeEastLoBase pin 14 (C.3) ' hBridgeWestLoBase pin 15 (C.4) ' hBridgeWestHiBase pin 16 (C.5) ' ' dataLogSelect pin 17 (C.6) 'Vcc = data log, gnd = clear data log memory ' displaySelect pin 18 (C.7) 'Vcc = display logged data, gnd = display real time data '---------------------------------------------------------------------------------------- ' ' General Variables ' '---------------------------------------------------------------------------------------- symbol cksum = b0 symbol tempByte = b1 symbol tempWord = w1 '---------------------------------------------------------------------------------------- ' ' On Demand Charging Variables ' '---------------------------------------------------------------------------------------- symbol fullChargeVolts = 1200 '1.20 volts (1200 millivolts) symbol fullDischargeVolts = 900 '0.90 volts (900 millivolts) symbol minEnergy = 7350 '7350 mAm (milli-amp-minutes) symbol measuredEnergy = w2 'accumulated current values every minute symbol charging = b6 '0 = not charging, 1 = charging symbol energyLoopCtr = w4 'energy loop counter symbol energyLoopCount= 60 'number of passes through Main to equal 1 minute symbol Q1 = B.5 symbol chargeLED = B.7 symbol batteryVolts = w5 'battery voltage in millivolts symbol battOneOhmDrop = w6 'voltage drop across 1 ohm resistor connected to battery symbol batteryCurrent = w7 'battery current in milliamps '---------------------------------------------------------------------------------------- ' ' Sun Tracker Variables ' '---------------------------------------------------------------------------------------- symbol hBridgeEastHiBase = pinC.2 'motor H-Bridge controls symbol hBridgeEastLoBase = pinC.3 symbol hBridgeWestHiBase = pinC.5 symbol hBridgeWestLoBase = pinC.4 symbol solarVolts = w8 'solar panel voltage in millivolts symbol solarCurrent = w9 'solar panel current in milliamps symbol solarOneOhmDrop= w10 'voltage drop across 1 ohm resistor connected between 'solar panel and load symbol motorOn = 60 'milliseconds duration for motor ON state symbol lastVolts = w11 'last or previous solar panel sample symbol searchTrack = b24 '0 = seach for the sun, 1 = track the sun symbol dataLogCtr = b25 'counts passes thru Main before data log event symbol dataLogCount = 120 'number of passes through Main to equal 2 minutes symbol dataLogPtr = b26 'pointer to logged data for display symbol scratchPadPtr = w14 'pointer to logged data in scratch pad ram symbol datalogSelect = pinC.6 'Vcc = data log, gnd = clear data log memory symbol displaySelect = pinC.7 'Vcc = display logged data, gnd = display real time data '------------------------------------------------------------------ ' ' LED Flash Sequence ' '------------------------------------------------------------------ ' Data Logging ' once a second - data logging in progress - short flash ' once every 2 minutes - log event - longer 1 second flash ' four rapid flashes - data log memory full ' no flashing - data logging disabled ' ' Battery Charging ' solid on - battery charging ' slow flashing - battery voltage is below minimum while charging '------------------------------------------------------------------ ' ' Initialize Routine ' '------------------------------------------------------------------ Initialize: searchTrack = 0 'initialize tracking method to search charging = 0 'initialize to not charging battery GOSUB Motor_Stop 'initialize the motor to stop state GOSUB Get_Average_Voltages 'sample the solar panel voltage and lastVolts = solarVolts 'save it for the sun tracker routine dataLogPtr = 0 'pointer for plotting logged data low chargeLed 'extinguish the LED low Q1 'disable battery charging '------------------------------------------------------------------ ' ' Main Routine ' '------------------------------------------------------------------ Main: PAUSE 250 'adjust this delay so the time through the Main Sun_Tracker: IF searchTrack = 0 THEN 'decide on how to track the sun GOSUB Sun_Search 'just starting out at the beginning of the day or ELSE GOSUB Sun_Track 'after finding out where the sun is and tracking it ENDIF Battery_Charger: IF charging = 0 THEN 'decide whether or not to charge battery if GOSUB Test_Battery_Voltage 'battery voltage is above minimum or ELSE GOSUB Charge_Battery 'if it needs charging ENDIF 'LED will remain ON for entire charging cycle Data_Logging: 'Log Data or Not IF datalogSelect = 0 THEN 'disable data logging GOSUB Clear_Logged_Data 'and erase logged memory ELSE 'LED will NOT flash as long as P11 = 0 GOSUB Log_Data 'else, log data every 2 minutes ENDIF 'LED will flash once every time thru Main 'and flash longer when event is logged 'LED will flash 4 times when data log memory 'is full Display_Data: IF displaySelect = 0 THEN 'Display Real Time or Logged Data GOSUB Plot_Real_Time_Data 'display real time solar data when P15 = 0 ELSE GOSUB Plot_Logged_Data 'display logged solar data when P15 = 1 ENDIF GOTO Main '------------------------------------------------------------------ ' ' Sun Tracker Routine ' '------------------------------------------------------------------ Sun_Search: 'do this to establish the original sun position searchTrack = 0 'by moving east until we find it GOSUB Move_East 'move east slightly GOSUB Get_Average_Voltages 'and take another solar panel voltage sample IF lastVolts > solarVolts THEN 'we've now moved the panel too far east, so searchTrack = 1 'it's time to track the sun as it moves GOTO Sun_Search_End ENDIF lastVolts = solarVolts 'else, save this voltage for next time Sun_Search_End: RETURN Sun_Track: 'do this when the original position of the sun is found searchTrack = 1 'and we're tracking it GOSUB Get_Average_Voltages 'take another solar panel voltage sample tempWord = solarVolts >> 2 'purposly degrade the solar panel voltage so that 'we don't react to "noise" IF tempWord = lastVolts THEN 'test for no sun movement in the last second PAUSE 800 'if so, pause to maintain loop timing and GOTO Sun_Track_End 'exit to Main if no movement ELSE lastVolts = tempWord 'else, save this degraded sample of solarVolts as lastVolts ENDIF GOSUB Move_West 'move solar panel west slightly Sun_Track_East: GOSUB Get_Average_Voltages 'sample solar panel voltage again tempWord = solarVolts >> 2 'purposly degrade the solar panel voltage so that 'we don't react to "noise" IF tempWord < lastVolts THEN 'if sample is less than last sample, we've gone too far GOSUB Move_East 'west so move back to where were last time ENDIF Sun_Track_End: RETURN '------------------------------------------------------------------ ' ' Motor Subroutines ' '------------------------------------------------------------------ Move_West: hBridgeEastHiBase = 1 hBridgeWestLoBase = 1 PAUSE motorOn GOSUB Motor_Stop RETURN Move_East: hBridgeWestHiBase = 1 hBridgeEastLoBase = 1 PAUSE motorOn GOSUB Motor_Stop RETURN Motor_Stop: hBridgeEastHiBase = 0 hBridgeEastLoBase = 0 hBridgeWestHiBase = 0 hBridgeWestLobase = 0 RETURN '------------------------------------------------------------------ ' ' On Demand Battery Charge Algorithm ' '------------------------------------------------------------------ ' Test_Battery_Voltage: 'stay in this loop as long as the battery is above min voltage ' Disable charging (Q1 = LOW) and extinguish LED ' Get battery voltage reading ' if batteryVolts >= fullChargeVolts, loop back ' else, goto Charge_Battery ' ' Charge_Battery: 'stay in this loop until a minimum charge is delivered into the battery ' Enable charging (Q1 = HIGH) and illuminate LED ' acquire a minimum battery charge ' when minimum battery charge is acquired, branch to Verify_Battery_Charged ' ' Verify_Battery_Charged: 'stay in this loop until the battery is at full voltage ' if batteryVolts >= fullChargeVolts, goto Test_Battery_Voltage ' else, loop back to Verify_Battery_Charged - charging is still taking place ' ' NOTE 1: Battery voltage, current, power or resistance values are NOT displayed ' ' NOTE 2: Only solar panel voltage, current, power and resistance are displayed ' ' NOTE 3: The battery voltage and current have already been sampled in the sun tracker routine above ' Test_Battery_Voltage: charging = 0 'disable charging low Q1 'turn Q1 OFF low ChargeLed 'extinguish charging LED IF batteryVolts < fullDischargeVolts THEN 'test battery voltage for below minimum measuredEnergy = 0 'if so, clear accumulated energy value energyLoopCtr = energyLoopCount 'initialize energy loop count for 1 minute value charging = 1 'set charging flag ENDIF RETURN Charge_Battery: charging = 1 'enable charging high Q1 'turn Q1 ON high ChargeLed 'illuminate charging LED IF measuredEnergy >= minEnergy THEN 'test for accumulated ampMinutes of energy GOTO Verify_Battery_Charged 'branch if minimum energy level is met ENDIF energyLoopCtr = energyLoopCtr - 1 'else, decrement energy loop counter IF energyLoopCtr = 0 THEN 'test for 1 minute equivalent time in loop energyLoopCtr = energyLoopCount 'if so, reinitialize energyLoopCtr and measuredEnergy = measuredEnergy + batteryCurrent 'add latest current reading to measuredEnergy var ENDIF RETURN Verify_Battery_Charged: 'determine if battery voltage is at or above minimums high ChargeLed pause 100 low ChargeLed IF batteryVolts >= fullChargeVolts THEN 'test against fully charged voltage charging = 0 'if so, disable charging ENDIF RETURN '------------------------------------------------------------------ ' ' Get Average Voltages ' '------------------------------------------------------------------ Get_Average_Voltages: 'zero... batteryVolts = 0 'battery voltage battOneOhmDrop = 0 'battery oneOhmDrop to compute battery current batteryCurrent = 0 'battery current solarVolts = 0 'solar panel voltage solarOneOhmDrop = 0 'solar oneOhmDrop to compute current into load solarCurrent = 0 'solar panel current FOR tempByte = 0 TO 63 'accumulate 64 readings of solar and battery voltages readadc10 9,tempWord 'set the a/d converter to the battery batteryVolts = batteryVolts + tempWord 'accumulate result readadc10 12,tempWord 'set the a/d converter to its sense resistor battOneOhmDrop = battOneOhmDrop + tempWord 'accumulate result readadc10 11,tempWord 'set the a/d converter to the solar panel solarVolts = solarVolts + tempWord 'accumulate result readadc10 10,tempWord 'set the a/d converter to its sense resistor solarOneOhmDrop = solarOneOhmDrop + tempWord 'accumulate result NEXT batteryVolts = batteryVolts / 64 'take averages of 64 samples battOneOhmDrop = battOneOhmDrop / 64 solarVolts = solarVolts / 64 solarOneOhmDrop = solarOneOhmDrop / 64 IF battOneOhmDrop > batteryVolts THEN 'test for voltage drop across 1 ohm sense resistor GOTO Get_Average_Voltages 'repeat sample if greater ENDIF IF solarOneOhmDrop > solarVolts THEN GOTO Get_Average_Voltages ENDIF 'compute currents batteryVolts = batteryVolts */$04E1 'convert to millivolts (4.88mv / count) battOneOhmDrop = battOneOhmDrop */$04E1'convert to millivolts (4.88mv / count) batteryCurrent = batteryVolts - battOneOhmDrop'compute the voltage drop across the 1 ohm sense resistor batteryCurrent = batteryCurrent / 1 'which is automatically now in milliamps by the following: ' ' I = E / R where ' I = current in milliamps ' E = voltage in millivolts ' R = resistance in ohms solarVolts = solarVolts */$04E1 'convert to millivolts (4.88mv / count) solarOneOhmDrop = solarOneOhmDrop */$04E1 'convert to millivolts (4.88mv / count) solarCurrent = solarVolts - solarOneOhmDrop 'compute the voltage drop across the 1 ohm sense resistor solarCurrent = solarCurrent / 1 'which is automatically now in milliamps by the following: ' ' I = E / R where ' I = current in milliamps ' E = voltage in millivolts ' R = resistance in ohms RETURN '------------------------------------------------------------------ ' Data Logging Routines ' All data logging is done in the 1000 byte scratch pad RAM ' ' There are 1024 bytes for data log storage ' Each data log record = 4 bytes stored as follows from low to high address ' solarVolts.HIGHBYTE ' solarVolts.LOWBYTE ' solarCurrent.HIGHBYTE ' solarCurrent.LOWBYTE ' This allows 256 records which are recorded approximately once every 2 minutes ' 256 x 2 minutes = 512 minutes ' 512 minutes / 60 min/hr = approximately 8.5 hours of continuous storage ' '------------------------------------------------------------------ Clear_Logged_Data: DataLogCtr = 0 'clear the 2 minute counter-timer IF scratchPadPtr = 0 THEN 'test for data log memory already cleared GOTO Clear_Log_Data_End 'i.e, data log pointer is at zero - return if so ENDIF FOR scratchPadPtr = 0 TO $3FF 'else, zero the log memory put scratchPadPtr,0 NEXT scratchPadPtr = 0 'reset pointer to 1K scratchpad RAM Clear_Log_Data_End: RETURN Log_Data: IF scratchPadPtr >= $400 THEN 'test to see if we are at max data log memory FOR tempByte = 0 TO 3 'if so, flash LED 4 times to aleart user of this high ChargeLed PAUSE 100 'then remove jumper to allow more data logging low ChargeLed PAUSE 100 NEXT GOTO Log_Data_End ENDIF dataLogCtr = dataLogCtr + 1 'else, increment 2 minute counter high ChargeLed 'quickly flash LED to show data logging in progress PAUSE 10 low ChargeLed IF dataLogCtr >= dataLogCount THEN 'test to see if 2 minutes have elaspsed DataLogCtr = 0 'if so, reset 2 minute counter ptr = scratchPadPtr 'use the ptr instruction to access scratchpad memory 'write solar panel voltage and current to scratchPad RAM @ptrinc=b17 'put solarVolts high byte @ptrinc=b16 'put solarVolts low byte @ptrinc=b19 'put solarCurrent high byte @ptrinc=b18 'put solarCurrent low byte scratchPadPtr = ptr 'increment to the next data record location high ChargeLed 'flash chargeLED to indicate data log event PAUSE 1000 'long 1 second flash low ChargeLed ENDIF Log_Data_End: RETURN '------------------------------------------------------------------ ' ' Plot Solar Panel Data ' '------------------------------------------------------------------ Plot_Logged_Data: tempWord = 0 'clear for below tempword = dataLogPtr 'compute pointer to logged data from 8-bit counter tempWord = tempWord << 2 'multiply by four to compute address pointer 'value of 4-bytes per data record ptr = tempWord 'use the ptr instruction to access scratchpad memory b17=@ptrinc 'get solarVolts high byte b16=@ptrinc 'get solarVolts low byte b19=@ptrinc 'get solarCurrent high byte b18=@ptrinc 'get solarCurrent low byte dataLogPtr = dataLogPtr +1 'increment it for next time thru 'fall thru to plot real time data with logged data values instead '---------------------------------------------------------------------------------------- ' ' Transmit solarVolts (w8) followed by solarCurrent(w9) followed by the checksum ' Note: Keep the bytes in the order shown as the PC software depends on having them transmitted ' exactly in this sequence. ' ' Plot_Real_Time_Data: cksum = b17 + b16 + b19 + b18 serout A.4,N9600_8,(b17,b16,b19,b18,cksum) return '---------------------------------------------------------------------------------------- end