' Measure.bs2 ' Measures Solar Panel Volts, Current and Ampere-hours ' John Saunders 10/11/2007 ' {$STAMP BS2} ' {$PBASIC 2.5} 'Stamp Ports PwrGood PIN 0 'Input:1 if line is up RS232In PIN 1 'Input:RS-232 Serial in DTR PIN 2 'Input:Data Terminal Ready RS232Out PIN 3 'Output:RS-232 Serial out MOSFET PIN 4 'Output:1 energises the MOSFET output on DC-25 pins 17&18 IOCLK PIN 5 'Output:74HC165 and 74HCT164 clock SwData PIN 6 'Input:Switch and external discrete inputs IOData PIN 7 'Output:Display character, mode and command,165 Load DispLD PIN 8 'Output:Display load SwDn PIN 9 'Input:0 = switch down, also DC-25P pin 21 SwUp PIN 10 'Input:0 = switch up, also DC-25P pin 22 AD1CLK PIN 11 'Output:10 clock pulses to input analog 1 value AD1In PIN 12 'Input:analog 1 value, MSB first AD2CLK PIN 13 'Output:10 clock pulses to input analog 2 value AD2In PIN 14 'Input:analog 2 value, MSB first TwoHz PIN 15 'Input:2-Hz square wave timing input 'time processing parameters sec VAR Byte 'current seconds minute VAR Byte 'current minutes hour VAR Byte 'current hour day VAR Byte 'current day, starting at 1 month VAR Nib 'current month, 1 to 12 year VAR Nib 'current year, add to 0, assume 20XX phase VAR Bit '2 Hz waveform from CD4060,1=high halfsec VAR Bit 'To run some processes once per second 'Initialization DispInitData DATA $30,$30,$30,$38,$0C,$01,$06,$14,$80 DispInitLen CON 8 DayInMonth DATA 31,28,31,30,31,30,31,31,30,31,30,31 DayLoc DATA 11 'using EEPROM to reduce need to re-enter MonthLoc DATA 10 'using EEPROM to reduce need to re-enter YearLoc DATA 07 'using EEPROM to reduce need to re-enter 'Display parameters DECdata VAR Word 'actual character or value to be displayed div VAR Nib 'dividend used in writing numbers rem VAR Word 'remainder used in writing multiple-digit numbers DispMode VAR Nib 'Controls the way a value is to be displayed, bits 0, 1 = no of digits - 1 DPLoc VAR DispMode.BIT2 '0=1 digit after DP, 1 = 2 DPOnOff VAR DispMode.BIT3 '0 = no decimal point, 1 = DP row0addr CON $80 'instruction for top row row1addr CON $C0 'second row row2addr CON $94 'third row row3addr CON $D4 'bottom row Blink VAR Bit 'Control variables and External Digital Inputs DIGdata VAR Byte 'Signals connected to the 74HC165 shift register ModeSW VAR Byte Charging VAR DIGdata.BIT7 'Signal connected to DC-29P, pin 20 InputB VAR DIGdata.BIT6 'Signal connected to DC-29P, pin 7 InputC VAR DIGdata.BIT5 'Signal connected to DC-29P, pin 6 Range VAR DIGdata.BIT4 'Signal connected to DC-29P, pin 19 and the range switch EnterSw VAR DIGdata.BIT3 'Signal connected to DC-29P, pin 16 and the push-button OldDigitals VAR Byte 'Previous value of DIGData OldMode VAR OldDigitals.LOWNIB OldEnter VAR OldDigitals.BIT3 OldUp VAR Bit 'Previous value of SwUp OldDn VAR Bit 'Previous value of SwDn SettingIndex VAR Nib 'Cursor position when setting values Iter VAR Nib 'for loop variable Limit VAR Byte 'For loop end point 'Analog variables and constants Offset VAR Byte 'The zero value to be added to MAZeroBase MAZeroBase CON 462 OffsetLoc DATA 43 'store the value of current offset from MAOffsetBase Shunt VAR Byte 'Calibration factor in 1/10 MA/count 'Allowable values: 1(4 OHM,+/- 50 MA 'Allowable values: 2(2 OHM,+/- 100 MA 'Allowable values: 3(1.33 OHM,+/- 150 MA 'Allowable values: 4(1 OHM,+/- 200 MA 'Allowable values: 5(0.8 OHM,+/- 240 MA 'Allowable values: 6(0.67 OHM,+/- 300 MA 'Allowable values: 10(0.4 OHM,+/- 500 MA 'Allowable values: 12(0.33 OHM,+/- 600 MA 'Allowable values: 20(0.2 OHM,+/- 1000 MA ShuntLoc DATA 2 'The stored calibration value MAH VAR Word 'Milliamp-hour accumulated in tenths of charging Fractional VAR Byte 'Remainder of MAH each minute MASum VAR Word 'running Sum of 1-sec 0.1 milliamp readings AverageMA VAR Word 'Average of MASum over 1 MIN period 'monitoring FileNoLoc DATA 103 'Set to one more than the last one start: DIRS = %0010100110111000 LOW DispLD 'display enable pin phase=TwoHz 'make sure to find the first transition GOSUB InitCmds GOSUB InitDisp GOSUB ReadDate softreset: SettingIndex = 0 GOSUB GetInputData OldDigitals = DIGdata OldDn = SwDn OldUp = SwUp 'find the 2 Hz transitions transition: DO WHILE TwoHz=phase 'Clock signal is not changing GOSUB GetInputData 'get the inputs 4 times a second LOOP 'transition processing phase=TwoHz 'reset the phase IF ModeSW = 5 THEN GOSUB SetTimeDate GOSUB DispTime OldDigitals = DIGData GOTO transition ENDIF IF phase=0 THEN halfsec = ~ halfsec IF halfsec = 1 THEN 'Once per second GOSUB DispTime ELSE GOSUB getvolts IF ModeSW = 3 THEN READ OffsetLoc,DECData rem = 99 GOSUB AdjustValue WRITE OffsetLoc,DECData ENDIF IF ModeSW = 4 THEN READ ShuntLoc,DECData rem = 20 GOSUB AdjustValue WRITE ShuntLoc,DECData ENDIF ENDIF ELSE IF halfsec = 1 THEN 'Once per second GOSUB getMA GOSUB DispMAH ELSE IF ModeSW = 6 THEN IF EnterSw = 0 THEN start IF SwUp = 0 AND OldUp = 1 THEN MAH = 0 ENDIF ENDIF GOSUB TimeUpdate ENDIF ENDIF GOSUB DispSettings OldDigitals = DIGData GOTO transition 'continue monitoring the 2 Hz clock 'subroutines: 'subroutines for LCD display: InitCmds: IOCLK = 0 OldDigitals = 0 Fractional = 0 MAH = 0 MASum = 0 AverageMA = 0 sec = 7 RETURN InitDisp: FOR Iter = 0 TO DispInitLen READ DispInitData + Iter,DECData GOSUB DispCmd NEXT RETURN ReadDate: READ YearLoc,Year READ MonthLoc,Month READ DayLoc,Day RETURN SetTimeDate: IF EnterSw = 0 AND OldEnter = 1 THEN SettingIndex = SettingIndex + 1 IF SettingIndex > 4 THEN SettingIndex = 0 ENDIF Sec = 0 ENDIF SELECT SettingIndex CASE 0 DECData = Hour rem = 23 GOSUB AdjustValue Hour = DECData CASE 1 DECData = Minute rem = 59 GOSUB AdjustValue Minute = DECData CASE 2 DECData = Month - 1 rem = 11 'computations start at 0, corrected in DispTime GOSUB AdjustValue Month = DECData + 1 WRITE MonthLoc,Month CASE 3 READ (DayInMonth + Month),rem 'to index Day in month DECData = Day - 1 GOSUB AdjustValue Day = DECData + 1 WRITE DayLoc,Day CASE 4 DECData = Year rem = 99 GOSUB AdjustValue WRITE YearLoc,DECData Year = DecData ENDSELECT OldDn = SwDn OldUp = SwUp RETURN AdjustValue: 'value to be updated is in DECData, Div is in Div IF SwDn = 0 AND OldDn = 1 THEN IF DECData = 0 THEN DECData = Rem ELSE DECData = DECData - 1 ENDIF ENDIF IF SwUp = 0 AND OldUp = 1 THEN IF DECData >= Rem THEN DECData = 0 ELSE DECData = DECData + 1 ENDIF ENDIF RETURN DispCmd: 'puts a command (IoData) in OutputData into the display SHIFTOUT IOData,IOCLK,1,[DECdata\8] 'clocks the instruction into the shift register LOW IOData 'instruction function is low, IOData does double duty PULSOUT DispLD,10 'clocks the instruction and the function into the display PAUSE 1 RETURN DispChar: 'puts one character onto the display SHIFTOUT IOData,IOCLK,1,[DECdata\8] 'clocks the character into the shift register HIGH IOData 'data function is high PULSOUT DispLD,1 'clocks the instruction and the character into the display RETURN GetInputData: 'inputs are scanned at 4 hz HIGH IOData 'load the inputs into the 74165 shift register PULSOUT IOData,2 HIGH IOData SHIFTIN SWData,IOCLK,1,[DIGdata\8] 'clock input states out of the shift register into the stamp ModeSW = DIGdata & 7 RETURN TimeUpdate: sec = sec +1 SELECT sec CASE 1 SEROUT RS232Out,84,2,["S 1 5",CR] '50 ms timeout for missing bytes CASE 2 READ FileNoloc,rem SEROUT RS232Out,84,2,["O 1 A /M",DEC3 rem,".CSV",CR] CASE 3 SEROUT RS232Out,84,2,["W 1 16",CR, DEC2 month,"/",DEC2 day,"/20",DEC2 year,",",DEC2 hour,":",DEC2 minute] CASE 4 GOSUB CalcMAH CASE 6 SEROUT RS232Out,84,2,["W 1 10",CR,",",DEC2 Offset,",",DEC2 Shunt,",",DEC Charging,CR,LF] CASE 7 SEROUT RS232Out,84,2,["C 1",CR] ENDSELECT IF sec > 59 THEN sec = 0 minute = minute + 1 IF minute > 59 THEN minute = 0 hour = hour + 1 IF hour > 23 THEN hour = 0 READ (DayInMonth + Month - 1),Limit 'to index Day in month Day = Day + 1 WRITE DayLoc,Day READ FileNoLoc,rem rem = rem + 1 WRITE FileNoLoc,rem MAH = 0 IF Day > Limit THEN Day = 1 WRITE DayLoc,1 Month = Month + 1 WRITE MonthLoc,Month IF Month > 12 THEN Month = 1 WRITE MonthLoc,1 Year = Year + 1 WRITE YearLoc,Year ENDIF ENDIF ENDIF ENDIF ENDIF RETURN DispTime: 'format is hh:mm:ss mm/dd/20yy DECdata = row0addr GOSUB DispCmd DECData = Hour DispMode = 1 'Two digits IF SettingIndex = 0 THEN Blink = 1 ENDIF GOSUB DispDec DECData = ":" GOSUB Dispchar Iter = 2 DECData = Minute IF SettingIndex = 1 THEN Blink = 1 ENDIF GOSUB DispDec DECData = ":" GOSUB Dispchar DECData = Sec GOSUB DispDec DECData = row0addr + 9 GOSUB DispCmd DECData = Month IF SettingIndex = 2 THEN Blink = 1 ENDIF GOSUB DispDec DECData = "/" GOSUB Dispchar DECData = Day IF SettingIndex = 3 THEN Blink = 1 ENDIF GOSUB DispDec DECData = "/" GOSUB Dispchar DECData = "2" GOSUB Dispchar DECData = "0" GOSUB Dispchar DECData = Year IF SettingIndex = 4 THEN Blink = 1 ENDIF GOSUB DispDec RETURN DispDec: IF DispMode = 0 THEN OneDigit IF DispMode = 1 THEN TwoDigit IF DispMode = 2 OR DispMode = "A" THEN ThreeDigit div = DECData/1000 rem = DECData//1000 DECData = div + "0" GOSUB DispChar IF DispMode = $E THEN DECData = "." GOSUB DispChar ENDIF DECData = rem ThreeDigit: div = DECData/100 rem = DECData//100 DECData = div + "0" GOSUB DispChar IF Dispmode = $F THEN DECData = "." GOSUB DispChar ENDIF DecData = rem TwoDigit: IF Phase = 1 AND Blink = 1 THEN DECData = " " GOSUB DispChar DECData = " " GOSUB DispChar ELSE div = DECData/10 rem = DECData//10 DECData = div + "0" GOSUB DispChar IF Dispmode = $B OR DispMode = $A THEN DECData = "." GOSUB DispChar ENDIF DECData = rem OneDigit: DECdata = DECdata + "0" GOSUB DispChar ENDIF Blink = 0 RETURN getvolts: DecData = row2addr GOSUB DispCmd rem = 0 SHIFTIN ad1in,ad1clk,MSBPRE,[rem\10] IF Range = 1 THEN DecData = rem << 1 '1 count = 4mv, * 2 is 2 mv gain is 0.2 for 20 V = 2000 ELSE DECData = rem << 2 '1 count = 4mv, * 4 is 1 mv , gain is 1 for 4V range 4 V = 4000 ENDIF IF sec = 5 THEN SEROUT RS232Out,84,2,["W 1 5",CR,",",DEC4 DECData] ENDIF DispMode = $E + range '4 digits with 2 after the DP GOSUB DispDec DecData = " " GOSUB DispChar DecData = "V" GOSUB DispChar RETURN getMA: 'The slope is 0.41 mv per count DecData = row2addr + 8 GOSUB DispCmd READ Offsetloc,Offset SHIFTIN ad2in,ad2clk,MSBPRE,[rem\10] IF rem > (MAZeroBase + Offset) THEN rem = rem - MAZeroBase - Offset DecData = "-" ELSE rem = MAZeroBase + Offset - rem DecData = " " ENDIF MASum = MASum + rem GOSUB DispChar DispMode = $A READ ShuntLoc,Shunt DECData = rem * Shunt GOSUB DispDEC DecData = " " GOSUB DispChar DecData = "M" GOSUB DispChar DecData = "A" GOSUB DispChar DecData = " " GOSUB DispChar RETURN CalcMAH: rem = 60/Shunt AverageMA = MASum / rem 'MA in tenths IF Charging = 1 THEN MAH = MAH + (AverageMA / 60) DECData = AverageMA // 60 Fractional = Fractional + DECData IF Fractional > 59 THEN MAH = MAH + 1 Fractional = Fractional - 60 ENDIF ENDIF SEROUT RS232Out,84,2,["W 1 11",CR,",",DEC4 AverageMA,",",DEC5 MAH] MASum = 0 RETURN DispMAH: DecData = row1addr GOSUB DispCmd IF MAH < 10000 THEN DispMode = $A DECData = MAH ELSE DispMode = 3 DECData = MAH/10 ENDIF GOSUB DispDec DecData = " " GOSUB DispChar DECData = "M" GOSUB DispChar DECData = "A" GOSUB DispChar DECData = "H" GOSUB DispChar DecData = " " GOSUB DispChar RETURN DispSettings: DecData = row3addr GOSUB DispCmd READ ShuntLoc,DECData DispMode = 1 IF ModeSW = 4 THEN Blink = 1 ENDIF GOSUB DispDec DECData = " " GOSUB DispChar READ OffsetLoc,DECData DispMode = 1 IF ModeSW = 3 THEN Blink = 1 ENDIF GOSUB DispDec DecData = " " GOSUB DispChar IF Charging = 1 THEN DECData = "C" ELSE DECData = "D" ENDIF GOSUB DispChar RETURN