' CyclerSX.bsx Modified to use DS1302 RTC, and cycler add-on
' John Saunders 3/21/2014 Added manual charge/discharge and support for 10AH
' {$STAMP BS2SX ,CyclerSXInit.BSX, CyclerSXAdj.BSX}
' {$PBASIC 2.5}
' ($COM2)
'startup CON 0
'Stamp Ports
DS1302IO PIN 0 'DS1302 Input and Output
RS232In PIN 1 'Input:RS-232 Serial in
DSR PIN 2 'Input:Data Set 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
DS1302CE PIN 15 'DS1302 Chip enable
'String Declarations
'These are used with DispBCDString to generate most of the display fields
DateString DATA " ",$89,"/",$87,0
YearString DATA "/20",$8D,0
YearAdjString DATA "20",$8D," ADJ",0
MinAdjString DATA "Adj Min ",$83,0
HourAdjString DATA "Adj Hour ",$85,0
TimeString DATA $85,":",$83,":",$81,0
VoltString DATA " V",0
MAString DATA " MA",0
HourString DATA " Hrs",0
ZeroAdjString DATA "Adj Zero ",0
ChargeTimeString DATA "Adj Chg Time ",0
MinVoltsstring DATA "Adj Min Volt ",0
DigitalsString DATA "Pin 6 Pin 7 Pin 20",0
MAHString DATA " MAH ",0
ChgString DATA "Chg:",0
DischgString DATA "Dis:",0
MinsString DATA " Mins",0
'Dallas DS1302 RTC addresses and variables
WRProtData CON 0
WRProtAddr CON $8E
OSCEnAddr CON $80
DSIntervalAddr CON $D2
TCHData CON %10100101
TCHAddr CON $90
ReadMonthAddr CON $89
ReadDateAddr CON $87
ReadSecAddr CON $81
WriteHourAddr CON $84
WriteMinuteAddr CON $82
DSAddr VAR Byte 'DS1302 register address
DSData VAR Byte 'DS1302 data is in BCD format
Tens VAR DSData.HIGHNIB
Units VAR DSData.LOWNIB
ItemSelect VAR Bit '0 = adjust min/chg time. 1 = Adjust hour/min volts
'Initialization
DispInitData DATA $30,$30,$30,$38,$0C,$01,$06,$14,$80
DispInitLen CON 8
'Display parameters
DECdata VAR Word 'numerical value to be displayed
Upper VAR DECData.HIGHBYTE
Lower VAR DECData.LOWBYTE
CharData VAR Byte 'Character ot display command
div VAR Nib 'dividend used in writing numbers
rem VAR Word 'remainder used in writing multiple-digit numbers
DataAddr VAR rem
MaxValue VAR rem
DispMode VAR Nib 'Controls the way a value is to be displayed, bits 0, 1 = no of digits - 1
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
ModeSW VAR Byte
InputA VAR DIGdata.BIT7 'Signal connected to DC-29P, pin 20
InputB VAR DIGdata.BIT6 'Signal connected to DC-29P, pin 7, shorted on Temperature
InputC VAR DIGdata.BIT5 'Signal connected to DC-29P, pin 6, shorted on AC Amps
VRange VAR DIGdata.BIT4 'Signal connected to DC-29P, pin 19 and the Voltage 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
Iter VAR Nib 'for loop variable
Limit VAR Byte 'For loop end point
Changed VAR Bit
OldCharging VAR Bit
MinFlag VAR Bit
OldMin VAR Byte
FromSlot VAR Nib
'Analog variables and constants
Current VAR Word 'Accumulated value
Samples VAR Byte 'Number averaged
NumSamples CON 60 'Number to be averaged, care not to exceed 64K in Current
MAH VAR Word 'Milliamp-hours
OldMAH VAR Word
MAM VAR Word 'Milliamp-minutes
CurrentGood VAR Bit 'Current is a valid average
MinuteCount VAR Word
OffsetLoc CON $C1
MvZeroBase CON 462
start:
DIRS = %1010100110111000
LOW DispLD 'display enable pin
LOW DS1302CE
HIGH RS232Out
SELECT FromSlot
CASE 1
GOTO softreset
CASE 2
GOTO FromAdj
ENDSELECT
RUN 1
softreset:
OldDigitals = DIGdata
GET 63,FromSlot
main:
DsAddr = $83
GOSUB DS1302OUT
IF DSData <> OldMin THEN 'Flag is good for only one pass through main
OldMin = DSData
MinFlag = 1
MinuteCount = MinuteCount + 1
ENDIF
GOSUB GetInputData
IF DigData <> OldDigitals THEN
CharData = 1
GOSUB DispCmd
OldDigitals = DIGData
ENDIF
GOSUB GetBiPolar
SELECT ModeSw
CASE 3 '"ZERO":Adjust the zero offset with 0V in on selected range in external box
CharData = row0addr
GOSUB DispCmd
DataAddr = ZeroAdjString
GOSUB DispBCDString
DSAddr = $C1
GOSUB DS1302OUT 'Offset is in DSData
DECData = DSData
MaxValue = 255 'Typically 48
GOSUB AdjustValue
DispMode = 2
GOSUB DispDec 'Show the offset
DSData = DECData 'Store in the RTC
DSAddr = $C0
GOSUB DS1302IN
CharData = row0addr + 13
GOSUB DispCmd
DECData = 0
SHIFTIN ad2in,ad2clk,MSBPRE,[DECData\10]
GOSUB DispBipolar 'Show the actual current
GOSUB DispDigitals
CASE 4 '"LIMIT"
GOSUB AdjCharging 'Two items to edit: Charging hours and minimum volts
IF EnterSw = 0 THEN
ItemSelect = ItemSelect ^ 1
ENDIF
GOSUB DispDigitals
CASE 5
RUN 2
FromAdj: '"Time/Date"
' GOSUB AdjTime 'Two items to edit: Hours and minutes, else use SetupDS1302.bs2
IF EnterSw = 0 THEN
ItemSelect = ItemSelect ^ 1
ENDIF
GOSUB DispTime
CASE 6 'Reset
IF EnterSw = 0 THEN start
CASE ELSE '"1000, 250, 7 50 MA"
GOSUB DispBipolar
GOSUB DispTime
GOSUB GetVolts
IF SwDn = 0 THEN
LOW Mosfet
ENDIF
IF SwUp = 0 THEN
HIGH Mosfet
ENDIF
IF Mosfet <> OldCharging THEN
OldMAH = MAH
MAH = 0
MinuteCount = 0
OldCharging = Mosfet
MinFlag = 1
ENDIF
IF MinFlag = 1 THEN
CharData = Row2Addr
GOSUB DispCmd
DECData = MAH
DispMode = 4
GOSUB DispDec
DataAddr = MAHString
GOSUB DispBCDString
DECData = OldMAH
GOSUB DispDec
DataAddr = MAHString
GOSUB DispBCDString
CharData = Row3Addr
GOSUB DispCmd
DispMode = 3
IF Mosfet = 0 THEN
DataAddr = DisChgString
ELSE
DataAddr = ChgString
ENDIF
GOSUB DispBCDString
DECData = MinuteCount
GOSUB DispDec
DataAddr = MinsString
GOSUB DispBCDString
ENDIF
ENDSELECT
MinFlag = 0
GOTO main
'subroutines for LCD display:
DispCmd: 'puts a command (CharData) in OutputData into the display
SHIFTOUT IOData,IOCLK,1,[CharData\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,[CharData\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:
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
DispTime:
CharData = $80
GOSUB DispCmd
DataAddr = TimeString
GOSUB DispBCDString
DataAddr = DateString
GOSUB DispBCDString
DataAddr = YearString
GOSUB DispBCDString
RETURN
DispDec:
IF DispMode = 0 THEN OneDigit
IF DispMode = 1 OR DispMode = $D THEN TwoDigit
IF DispMode = 2 OR DispMode = $A OR DispMode = $C THEN ThreeDigit
IF DispMode <> 4 THEN FourDigit
div = DECData/10000
rem = DECData//10000
CharData = div + "0"
GOSUB DispChar
FourDigit:
div = DECData/1000 'DispMode Format
rem = DECData//1000 '0 #
CharData = div + "0" '1 ##
GOSUB DispChar '2 ###
IF DispMode = $E THEN '$A ##.#
CharData = "." '$B ###.#
GOSUB DispChar '$C #.##
ENDIF '$D #.#
DECData = rem '$E #.###
ThreeDigit: '$F ##.##
div = DECData/100 '3 ####
rem = DECData//100 '4 #####
CharData = div + "0"
GOSUB DispChar
IF Dispmode = $F OR DispMode = $C THEN
CharData = "."
GOSUB DispChar
ENDIF
DecData = rem
TwoDigit:
div = DECData/10
rem = DECData//10
CharData = div + "0"
GOSUB DispChar
IF Dispmode = $B OR DispMode = $A OR DispMode = $D THEN
CharData = "."
GOSUB DispChar
ENDIF
CharData = rem
OneDigit:
CharData = CharData + "0"
GOSUB DispChar
RETURN
DispDigitals:
CharData = row2addr
GOSUB DispCmd
DataAddr = DigitalsString
GOSUB DispBCDString
FOR iter = 0 TO 2
LOOKUP iter,[$D7,$DD,$E3],Chardata
GOSUB DispCmd
LOOKUP iter,[InputC,InputB,InputA],CharData
CharData = "0" + CharData
GOSUB DispChar
NEXT
RETURN
AdjustValue: 'value to be updated is in DECData, Maximum in MaxValue
Changed = 0
IF SwDn = 0 THEN
IF DECData = 0 THEN
DECData = MaxValue
ELSE
DECData = DECData - 1
ENDIF
Changed = 1
ENDIF
IF SwUp = 0 THEN
IF DECData >= MaxValue THEN
DECData = 0
ELSE
DECData = DECData + 1
ENDIF
Changed = 1
ENDIF
PAUSE 300
RETURN
GetVolts:
DECData = 0
SHIFTIN ad1in,ad1clk,MSBPRE,[DECData\10] 'ADC output, reference volts is 4.096 V
DSAddr = $C5 'Check for minimum volts once per minute
GOSUB DS1302OUT 'The minimum in 1/25 of full-scale (1000 count for 4V/20V)
Limit = DECData / 25
IF Limit < DSData AND MinFlag = 1 THEN
HIGH Mosfet 'Sets the accessory box relay on for charging
ENDIF
CharData = row1addr
GOSUB DispCmd
GOSUB DispVolts
RETURN
DispVolts: 'Displays in 1/100 V
IF Vrange = 0 THEN '4 volt range
DecData = 2*DECData /5
DispMode = $C
ELSE
DecData = 2*DECData '20V range
DispMode = $F
ENDIF
IF MinFlag = 1 THEN
GOSUB Monitor
Current = 0
ENDIF
GOSUB DispDec
DataAddr = VoltString
RETURN
GetBipolar: 'Shows each ADC, averages for MilliAmp-Hour calculation
DECData = 0
SHIFTIN ad2in,ad2clk,MSBPRE,[DECData\10]
IF CurrentGood = 0 THEN 'Sum for averaging
Current = Current + DECData
Samples = Samples + 1
IF Samples > NumSamples OR MinFlag = 1 THEN
Current = Current/Samples
CurrentGood = 1 'Keep average for MAH at minute end
ENDIF
ENDIF
IF MinFlag = 1 AND CurrentGood = 1 THEN
DSAddr = Offsetloc
GOSUB DS1302OUT
IF Current > (MvZeroBase + DSData) THEN
Current = Current - MvZeroBase - DSData
ELSE
Current = MvZeroBase + DsData - Current
ENDIF
SELECT ModeSw 'Adjust per range for 1 MA/count
CASE 0 '1 amp
Current = 2*Current
CASE 1 '250 ma
Current = (Current + 1)/2
CASE 2 '50 ma
Current = (Current + 5)/10
ENDSELECT
MAM = MAM + Current 'MilliAmp-Minute used because of Word size limitations
DO WHILE MAM > 60
MAM = MAM - 60
MAH = MAH + 1
LOOP
Samples = 0
CurrentGood = 0
IF Mosfet = 1 THEN
DSAddr = $C3 'Check if charging time is up
GOSUB DS1302OUT
rem = 60 * DSData
IF MinuteCount > rem THEN
LOW Mosfet
ENDIF
ENDIF
ENDIF
CharData = row1addr + 8
GOSUB DispCmd
RETURN
DispBipolar:
DSAddr = Offsetloc
GOSUB DS1302OUT
IF DECData > (MvZeroBase + DSData) THEN
DECData = DECData - MvZeroBase - DSData
CharData = "-"
ELSE
DECdata = MvZeroBase + DsData - DECData
CharData = " "
ENDIF
GOSUB DispChar
SELECT ModeSw
CASE 0 '1 amp
DispMode = 2
DecData = 2*DecData
CASE 1 '250 ma
DecData = DecData/2
DispMode = 2
CASE 2 '50 MA
DispMode = $A
ENDSELECT
GOSUB DispDEC
DataAddr = MAString
GOSUB DispBCDString
RETURN
'DECdata points to a DATA array which contains ASCII characters and DS1302 register addresses
DispBCDString: 'Display dates, times, and character strings, null-terminated
Limit = 0
DO 'Decode the instructions in the control string until a null character
READ (DataAddr + Limit),DSAddr
IF DSAddr = 0 THEN RETURN
IF DSAddr > $80 THEN 'This must be an address in the DS1302, no ASCII character used here is this high
GOSUB DS1302OUT
CharData = Tens + "0" 'Converts BCD to ascii, this is the upper nibble of DSData
GOSUB DispChar
CharData = Units + "0" 'Converts BCD to ascii, this is the lower nibble of DSData
GOSUB DispChar
ELSE 'Already a literal ASCII character (less than $80)
CharData = DSAddr
GOSUB DispChar
ENDIF
Limit = Limit+1 'Get next DATA array value
LOOP
RETURN 'Value is in DSData
'subroutines for the Dallas DS1302 real-time clock with battery backup
DS1302IN: 'Put the byte in DSData into the DsAddr location
HIGH DS1302CE 'Enable the DS1302
SHIFTOUT DS1302IO,IOCLK,0,[DSAddr\8] 'Put the register address (read) into the chip
SHIFTOUT DS1302IO,IOCLK,0,[DSData\8] 'The chip responds on the same line
LOW DS1302CE
RETURN
DS1302OUT: 'Read the contents of DSAddr into DsData
HIGH DS1302CE 'Enable the DS1302
SHIFTOUT DS1302IO,IOCLK,0,[DSAddr\8] 'Put the register address (write) into the chip
SHIFTIN DS1302IO,IOCLK,1,[DSdata\8] 'Put the new value into the chip
LOW DS1302CE
RETURN
AdjCharging:
CharData = Row0Addr
GOSUB DispCmd
IF ItemSelect = 0 THEN
DataAddr = ChargeTimeString
ELSE
DataAddr = MinVoltsstring
ENDIF
GOSUB DispBCDString
IF ItemSelect = 0 THEN
DsAddr = $C3 'Hours to charge
ELSE
DsAddr = $C5 'Minimum volts in 1/25 of full-scale for triggering charging
ENDIF
GOSUB DS1302OUT
DECData = DsData
MaxValue = 40
GOSUB AdjustValue
IF Changed = 1 THEN
DSAddr = DsAddr - 1
DSData = DECData
GOSUB DS1302IN
ENDIF
CharData = row0addr + 13
GOSUB DispCmd
IF ItemSelect = 0 THEN
DispMode = 1
GOSUB DispDec
DataAddr = HourString
ELSE
DECData = 25* DecData
GOSUB DispVolts
ENDIF
GOSUB DispBCDString
DataAddr = VoltString
RETURN
Monitor:
IF Mosfet = 1 THEN
CharData = "C"
ELSE
CharData = "D"
ENDIF
LOW RS232Out
PAUSE 5
HIGH RS232Out
PAUSE 5
SEROUT RS232Out,240,[DEC DecData,",",DEC Current,",",DEC MAH,",",CharData,",",DEC MinuteCount,CR]
RETURN
' CyclerSxOut.bsx Modified to use DS1302 RTC, and cycler add-on
' John Saunders 3/19/2014 Added manual charge/discharge and support for 10AH
' {$STAMP BS2SX}
' {$PBASIC 2.5}
' ($COM2)
'startup CON 0
'Stamp Ports
DS1302IO PIN 0 'DS1302 Input and Output
RS232In PIN 1 'Input:RS-232 Serial in
DSR PIN 2 'Input:Data Set 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
DS1302CE PIN 15 'DS1302 Chip enable
'String Declarations
'These are used with DispBCDString to generate most of the display fields
DateString DATA " ",$89,"/",$87,0
YearString DATA "/20",$8D,0
YearAdjString DATA "20",$8D," ADJ",0
MinAdjString DATA "Adj Min ",$83,0
HourAdjString DATA "Adj Hour ",$85,0
TimeString DATA $85,":",$83,":",$81,0
VoltString DATA " V",0
MAString DATA " MA",0
HourString DATA " Hrs",0
ZeroAdjString DATA "Adj Zero ",0
ChargeTimeString DATA "Adj Chg Time ",0
MinVoltsstring DATA "Adj Min Volt ",0
DigitalsString DATA "Pin 6 Pin 7 Pin 20",0
MAHString DATA " MAH ",0
ChgString DATA "Chg:",0
DischgString DATA "Dis:",0
MinsString DATA " Mins",0
'Dallas DS1302 RTC addresses and variables
WRProtData CON 0
WRProtAddr CON $8E
OSCEnAddr CON $80
DSIntervalAddr CON $D2
TCHData CON %10100101
TCHAddr CON $90
ReadMonthAddr CON $89
ReadDateAddr CON $87
ReadSecAddr CON $81
WriteHourAddr CON $84
WriteMinuteAddr CON $82
DSAddr VAR Byte 'DS1302 register address
DSData VAR Byte 'DS1302 data is in BCD format
Tens VAR DSData.HIGHNIB
Units VAR DSData.LOWNIB
ItemSelect VAR Bit '0 = adjust min/chg time. 1 = Adjust hour/min volts
'Initialization
DispInitData DATA $30,$30,$30,$38,$0C,$01,$06,$14,$80
DispInitLen CON 8
'Display parameters
DECdata VAR Word 'numerical value to be displayed
Upper VAR DECData.HIGHBYTE
Lower VAR DECData.LOWBYTE
CharData VAR Byte 'Character ot display command
div VAR Nib 'dividend used in writing numbers
rem VAR Word 'remainder used in writing multiple-digit numbers
DataAddr VAR rem
MaxValue VAR rem
DispMode VAR Nib 'Controls the way a value is to be displayed, bits 0, 1 = no of digits - 1
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
ModeSW VAR Byte
InputA VAR DIGdata.BIT7 'Signal connected to DC-29P, pin 20
InputB VAR DIGdata.BIT6 'Signal connected to DC-29P, pin 7, shorted on Temperature
InputC VAR DIGdata.BIT5 'Signal connected to DC-29P, pin 6, shorted on AC Amps
VRange VAR DIGdata.BIT4 'Signal connected to DC-29P, pin 19 and the Voltage 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
Iter VAR Nib 'for loop variable
Limit VAR Byte 'For loop end point
Changed VAR Bit
OldCharging VAR Bit
MinFlag VAR Bit
OldMin VAR Byte
FromSlot VAR Nib
'Analog variables and constants
Current VAR Word 'Accumulated value
Samples VAR Byte 'Number averaged
NumSamples CON 60 'Number to be averaged, care not to exceed 64K in Current
MAH VAR Word 'Milliamp-hours
OldMAH VAR Word
MAM VAR Word 'Milliamp-minutes
CurrentGood VAR Bit 'Current is a valid average
MinuteCount VAR Word
OffsetLoc CON $C1
MvZeroBase CON 462
InitCmds:
IOCLK = 0
OldDigitals = 0
#IF (startup) #THEN
DSAddr = OSCEnAddr 'Enable the RTC oscillator
DSData = $00
GOSUB DS1302IN 'Enable writing
DSData = WRProtData
DSAddr = WRProtAddr
GOSUB DS1302IN
#ENDIF
DSData = TCHData 'Set the backup battery charging
DSAddr = TCHAddr
GOSUB DS1302IN
InitDisp:
FOR Iter = 0 TO DispInitLen
READ DispInitData + Iter,CharData
GOSUB DispCmd
NEXT
SendHeader:
LOW RS232Out
PAUSE 5
HIGH RS232Out
PAUSE 5
SEROUT RS232Out,240,["Volts,MA,MAH,C/D,Minutes",CR]
GET 63,FromSlot
RUN 0
DS1302IN: 'Put the byte in DSData into the DsAddr location
HIGH DS1302CE 'Enable the DS1302
SHIFTOUT DS1302IO,IOCLK,0,[DSAddr\8] 'Put the register address (read) into the chip
SHIFTOUT DS1302IO,IOCLK,0,[DSData\8] 'The chip responds on the same line
LOW DS1302CE
RETURN
DispCmd: 'puts a command (CharData) in OutputData into the display
SHIFTOUT IOData,IOCLK,1,[CharData\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