' cycler.bs2 ' Battery Cycling function, used with the Digital Charger Adapter ' John Saunders 12/14/2006 ' {$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 iout 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 Phase VAR Bit '2 Hz waveform from CD4060,1=high Sec VAR Byte 'Count of 2Hz clock cycles per 1/100 hr (72) Hours VAR Word 'Time in 1/100 hour since last charge in Discharge 'Initialization Dispinitlen CON 8 DispInitData DATA $30,$30,$30,$38,$0C,$01,$06,$14,$80 Row0Loc DATA " V MA " 'Top row fixed values Row1Loc DATA " AH " 'Second row fixed values Row2Loc DATA " . V . V 4 A " 'Third row fixed values RowCLoc DATA " HRS CHARGING " 'Bottom row Charging RowDLoc DATA " HRS DISCHARGE" 'Bottom row Discharging 'Hitachi 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 'Control variables and External Digital Inputs DIGdata VAR Byte 'Signals connected to the 74HC165 shift register Mode VAR DIGdata.LOWNIB 'Bits 0-2 are the mode switch encoded Externals VAR DIGdata.HIGHNIB 'External signals on DB-25 pins20,7,6&19 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 Byte 'for loop variable Limit VAR Byte 'For loop end point PowerFail VAR Bit 'Is one if power was lost 'Analog variables and constants Shunt VAR Bit '1 = 0.5 ohm shunt, 0 = 0.05 ohm shunt Offset VAR Nib 'The zero value to be added to 505,range 505 to 521,nominal 512(7) VoltsLoc DATA 4,6,2,8 VoltsLimit DATA 20,9,20,9 VoltsPos DATA 0,3,7,10 VoltsMode DATA 1,0,1,0 AH VAR Byte 'Ampere-Hours accumulated MAH VAR Word 'Milliamp-hours accumulated Fractional VAR Byte 'in 1/100 of MAH AverageMA VAR Word 'Sum of 1-sec milliamp readings over 36-sec period Discharge VAR Bit 'When battery is discharging CyclesLoc DATA 101 'No of Charge/Discharge cycles, increment end of discharge,also filename Cycles VAR Byte RunFlag VAR Bit Start: DIRS = %0010100110111000 LOW DispLD 'display enable pin phase=TwoHz 'make sure to find the first transition LOW IOCLK DispLD = 0 RunFlag = 0 sec = 10 GOSUB InitDisp GOSUB GetInputData Offset = 4 GOTO main 'find the 2 Hz transitions Main: 'Main loop, normall takes 171 ms (129 with DTR on) max 292 DO WHILE TwoHz=Phase 'Clock signal is not changing IF PwrGood = 0 THEN 'Set inputs to IN to reduce current draw on battery DIRS = 0 PowerFail = 1 GOTO Main ELSE GOSUB GetInputData ENDIF LOOP Phase=TwoHz 'reset the phase IF (Phase = 0) OR (PwrGood = 0) THEN main IF Powerfail = 1 THEN Powerfail = 0 GOTO Start ENDIF GOSUB DispExternals GOSUB DispLimits GOSUB TimeUpdate GOSUB GetMA IF sec = 0 THEN GOSUB DispAH GOSUB DispHours ENDIF GOSUB GetVolts GOTO main 'continue monitoring the 2 Hz clock 'subroutines: 'subroutines for Hitachi LM044L 4x20 LCD display: InitDisp: FOR Iter = 0 TO DispInitLen READ DispInitData + Iter,DECData GOSUB DispCmd NEXT DECData = row0addr GOSUB DispCmd FOR Iter = 0 TO 18 READ Row0Loc + Iter,DECData GOSUB DispChar NEXT DECData = row1addr GOSUB DispCmd FOR Iter = 0 TO 18 READ Row1Loc + Iter,DECData GOSUB DispChar NEXT DECData = row2addr GOSUB DispCmd FOR Iter = 0 TO 18 READ Row2Loc + Iter,DECData GOSUB DispChar NEXT DECData = row3addr GOSUB DispCmd IF Discharge = 1 THEN FOR Iter = 0 TO 18 READ RowDLoc + Iter,DECData GOSUB DispChar NEXT HIGH MOSFET ELSE FOR Iter = 0 TO 18 READ RowCLoc + Iter,DECData GOSUB DispChar NEXT LOW MOSFET ENDIF SettingIndex = 4 READ CyclesLoc,Cycles GOSUB DispLimits GOSUB DispAH 'GOSUB DispExternals GOSUB DispCycles GOSUB DispHours 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 DispDec: 'Displays DECData at current cursor position in Digital IF DispMode = 0 THEN OneDigit IF DispMode = 1 THEN TwoDigit IF DispMode = 2 THEN ThreeDigit ' Only 4-digit can have decimal points div = DECData/1000 rem = DECData//1000 DECData = div + "0" GOSUB DispChar 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: div = DECData/10 rem = DECData//10 DECData = div + "0" GOSUB DispChar IF Dispmode = $B THEN DECData = "." GOSUB DispChar ENDIF DECData = rem OneDigit: DECdata = DECdata + "0" GOSUB DispChar RETURN DispLimits: 'Displays the Upper and Lower Voltage Limits FOR iter = 0 TO 3 READ VoltsPos + iter,DECData DecData = row2addr + DECData GOSUB DispCmd READ VoltsMode + iter,DispMode IF (SettingIndex = iter) AND (TwoHz = 0) THEN DECData = " " GOSUB DispChar IF DispMode = 1 THEN DECData = " " GOSUB DispChar ENDIF ELSE READ VoltsLoc + iter,DECData GOSUB DispDec ENDIF NEXT DecData = row2addr + 14 GOSUB DispCmd IF Shunt = 1 THEN DECData = " " ELSE DECData = "." ENDIF GOSUB DispChar RETURN DispAH: DecData = row1addr GOSUB DispCmd AverageMA = AverageMA/72 << 3 IF Shunt = 0 THEN AverageMA = AverageMA/10 ENDIF IF Discharge = 1 THEN 'Not interested in Ampere-Hours in charging mode MAH = MAH + (AverageMA/100) Fractional = Fractional + (AverageMA//100) AverageMA = 0 IF Fractional > 99 THEN MAH = MAH + 1 Fractional = Fractional - 100 ENDIF IF MAH > 999 THEN AH = AH + 1 MAH = MAH - 1000 ENDIF ENDIF DispMode = 2 '3 digits for AH DECData = AH GOSUB DispDec DECData = "." GOSUB DispChar DispMode = 2 '3 digits for MAH DECData = MAH GOSUB DispDec DispMode = 1 '2 digits for Fractional DECData = Fractional GOSUB DispDec RETURN DispHours: DECData = Row3Addr GOSUB DispCmd DispMode = 15 '4 digits, 2 afer DP DECData = Hours GOSUB DispDEC RETURN DispExternals: ' Display the externals DECData = row1addr + 13 GOSUB DispCmd IF Externals < 10 THEN DECdata = Externals + "0" ELSE DECdata = Externals + "7" ENDIF GOSUB DispChar RETURN DispCycles: ' Display the current filenane DECData = row1addr + 15 GOSUB DispCmd DispMode = 2 DECData = Cycles GOSUB DispDec RETURN 'Time handling TimeUpdate: sec = sec +1 IF sec > 71 THEN 'cycle time measured at 36.003 sec sec = 0 SEROUT RS232Out,84,["O 1 A /C",DEC3 Cycles,".CSV",CR] Hours = Hours + 1 ENDIF IF sec = 2 THEN SEROUT RS232Out,84,["C 1",CR] 'close the file RunFlag = 1 ENDIF noDTR4: RETURN 'External Input handling GetInputData: 'Rotary Switch and external inputs OldDn = SwDn OldUp = SwUp OldDigitals = DIGData 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 'handle settings Limit = DigData & 7 SELECT Limit CASE 0 IF (SWDn = 0) AND (OldDn = 1) THEN sec = 70 RunFlag = 0 ENDIF CASE 1 IF (Mode = 1) THEN AH = 0 MAH = 0 Fractional = 0 ENDIF CASE 2 IF (Mode = 2) THEN Hours = 0 ENDIF CASE 3 GOSUB DispLimits GOSUB SetValues CASE 4 IF SWDn = 0 THEN Discharge = 1 GOTO Start ENDIF IF SWUp = 0 THEN Discharge = 0 GOTO Start ENDIF CASE 5 IF SWDn = 0 THEN Shunt = 0 GOTO Start ENDIF IF SWUp = 0 THEN Shunt = 1 GOTO Start ENDIF CASE 6 IF (EnterSW = 0) AND (OldEnter = 1) THEN GOTO Start ENDIF ENDSELECT RETURN GetVolts: DecData = row0addr GOSUB DispCmd SHIFTIN ad1in,ad1clk,MSBPRE,[DECData\10] DecData = DecData << 1 IF sec = 1 AND runFlag = 1 THEN SEROUT RS232Out,84,[",",DEC4 DECData,",",DEC Shunt,",",BIN DigData,CR,LF] ENDIF IF sec = 0 THEN FOR iter = 0 TO 1 READ VoltsLoc + (2*iter),Limit READ VoltsLoc + 1 + (2*iter),div rem = (Limit * 100) + (10 * div) IF (Discharge = 0) AND (iter = 0) AND (DECData > rem) THEN Discharge = 1 AH = 0 MAH = 0 Fractional = 0 Hours = 0 GOSUB InitDisp ENDIF IF (Discharge = 1) AND (iter = 1) AND (DECData < rem) THEN Discharge = 0 'Start a new charge Cycles = Cycles + 1 WRITE CyclesLoc,Cycles Hours = 0 GOSUB InitDisp ENDIF NEXT ENDIF DispMode = $F '4 digits with 2 after the DP GOSUB DispDec RETURN GetMA: DecData = row0addr + 8 GOSUB DispCmd SHIFTIN ad2in,ad2clk,MSBPRE,[rem\10] IF (Mode = 5) AND (EnterSW = 0) THEN Offset = rem - 500 'Zero the offset with inputs shorted ENDIF 'Common mode < 16 reading from -2V to 15.6 V IF rem < 500 + Offset THEN rem = 500 + Offset - rem DecData = "-" 'gain is 9.96 + 23 at 0V CM ELSE rem = rem - Offset - 500 DecData = " " 'gain is 10.04 + 39 at 14.5V CM ENDIF iter = DECData GOSUB DispChar AverageMA = AverageMA + rem DECdata = rem << 3 'multiply by 8 Limit = Discharge + "C" IF sec = 1 THEN IF RunFlag = 1 THEN SEROUT RS232Out,84,["W 1 39",CR] SEROUT RS232Out,84,[Limit,",",DEC5 Hours,",",DEC3 AH,".",DEC3 MAH,",",iter,DEC4 DECData] ELSE SEROUT RS232Out,84,["W 1 23",CR] SEROUT RS232Out,84,["C/D",",","HRS",",","AH",",","A",",","V",",","SH",",","Ext",CR,LF] ENDIF ENDIF DispMode = 11 - (8 * Shunt) GOSUB DispDec RETURN 'Setting parameters SetValues: IF (EnterSw = 0) AND (OldEnter = 1) THEN SettingIndex = SettingIndex + 1 OldEnter = EnterSw ENDIF IF SettingIndex > 3 THEN SettingIndex = 0 ENDIF READ VoltsLoc + SettingIndex,DECData READ VoltsLimit + SettingIndex,rem GOSUB AdjustValue IF rem = 0 THEN WRITE VoltsLoc + SettingIndex,DECData ENDIF 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 rem = 0 ENDIF IF SwUp = 0 AND OldUp = 1 THEN IF DECData >= Rem THEN DECData = 0 ELSE DECData = DECData + 1 ENDIF rem = 0 ENDIF RETURN