' DS1624_18X.Bas  (PICAXE-18X)
'
' Configures DS1624 in single shot mode.  Performs ten temperature measurements, displays
' to the terminal  and saves to the DS1624 EEPROM.  Then reads from EEPROM and displays to
' the terminal.  May be modified to implement simple and inexpensive data logger.
'
' Not tested for negative temperatures,
'
'
' PICAXE-18X		             DS1624
'
' Output0 (term 6) ------------- SCL (term 2) ---------- To other DS1624 devices
' Output1 (term 7) -- 4.7K ----- SDA (term 1) ---------- each with different A2, A1, A0 strapping
'                                                        or to other I2C devices
'                           |
' Input1 (term 18) ---------
'
' Note that the strapping of A2, A1 and A0 on the DS1624 determines the DevAdr.  This may
' be in the range of 0 to 7.  Note that up to eight DS1624 devices, each having a different
' strapping, may be accommodated on the same two signal leads.
'
' Note that although the DS1624 uses the Philips I2C protocol.  However, the nature of the
' PICAXE I2C commands is not ammenable to control of the DS1624.
'
' In addition, the lack of a bidirectional I/O on the PICAXE-18X precludes bringing SDA to
' a high impedance state.  A series 4.7K resistor is used such that a logic one is +5 VDC
' through a 4.7K resistor.  The state of the SDA lead is read by bringing SDA to a logic one
' and reading SDAIn (Input1).
'
' copyright, Peter H Anderson, Elmore, VT, Aug, '04


' Define IO Terminals
Symbol SCL = 0
Symbol SDAIn = Pin1
Symbol SDAOut = 1


Symbol  DevAdr = B0		'
Symbol  EEAdr = B1

Symbol T = W1
Symbol L = B2
Symbol H = B3


' Used in I2C Routines
Symbol  OByte = B4
Symbol  IByte = B4
Symbol  Ack = B5
Symbol  N = B6
Symbol  MSBit = B7


' Used in DisplayT
Symbol X = B4
Symbol Fract = B5

    Pause 3000
Top:
    DevAdr = $00			  ' strapping of A2, A1, A0
    GoSub DS1624Config        ' configure DS1624 for 1SHOT operation

    For EEAdr = 0 TO 9         ' make ten measurements
        GoSub DS1624Init       ' initiate a conversion
        GoSub DS1624Meas       ' fetch the result

        Gosub DS1624EEWrite   ' save high byte to the DS1624 EEPROM
        GoSub DisplayT		  ' display the T_C with two decimal places
        Pause 1000
     Next

     For EEAdr = 0 TO 9      ' now fetch each from EEPROM and display
        GoSub DS1624EERead
        MSBit = H / 128
        If MSBit = 1 Then MainNegative
        ' else
        SerTxD(#EEAdr, "  ", #H, 13, 10)
Main_2:
     Next
     Goto Done

MainNegative:
     H = H ^ $ff + 1			' take twos comp
     SerTxD (#EEAdr, "  -", #H, 13, 10)	' display as neg
     Goto Main_2

Done:
     GoTo Done

DisplayT:
    Poke $50, B4			' save variables
    Poke $51, B5
    Poke $52, B6

    MSBit = H / 128
    If MSBit = 1 Then Negative
    ' else
    Fract = 0
    For N = 0 to 4
       MSBit = L / 128
       If MSBit = 0 Then DisplayT_1
       ' else
       Lookup N, (50, 25, 12, 6, 3), X		' thus if L = %1011 0000
       Fract = Fract + X                    ' Fract is 50 + 12 + 6 = 68
DisplayT_1:
       L = L * 2
    Next

    If Fract > 9 Then DisplayT_2   ' add a leading 0
    ' else
    SerTxD (#H, ".0", #Fract, 13, 10)
    Goto DisplayT_Done
DisplayT_2:
    SerTxD (#H, ".", #Fract, 13, 10)
    GoTo DisplayT_Done

Negative:		' same as for postive except take twos comp and display - sign
    T = T ^ $ffff + 1	' take 2's comp

    Fract = 0
    For N = 0 to 4
       MSBit = L / 128
       If MSBit = 0 Then DisplayT_3
       ' else
       Lookup N, (50, 25, 12, 6, 3), X
       Fract = Fract + X
DisplayT_3:
       L = L * 2
    Next

    If Fract > 9 Then DisplayT_4
    ' else
    SerTxD ("-", #H, ".0", #Fract, 13, 10)
    Goto DisplayT_Done
    DisplayT_4:
    SerTxD ("-", #H, ".", #Fract, 13, 10)
    GoTo DisplayT_Done

DisplayT_Done:
    Peek $50, B4		' restore variables
    Peek $51, B5
    Peek $52, B7

    Return

DS1624Config:   ' configures DS1624 in 1SHOT temperature conversion mode
     Gosub I2CStart

     OByte = 2 * DevAdr + $90
     Gosub I2COutByte

     OByte = $AC          'Access Config
     GoSub I2COutByte


     OByte = $01          '1 SHOT mode
     Gosub I2COutByte


     Gosub I2CStop
     Pause 30            ' wait for EEPROM to program

     Return

DS1624Init:     ' causes DS1624 to initiate a conversion

     Gosub I2CStart
     OByte = 2 * DevAdr + $90
     Gosub I2COutByte


     OByte = $EE          ' Start Conversion
     Gosub I2COutByte

     Gosub I2CStop
     Pause 1000          ' wait 1000 ms for conversion to complete

     Return

DS1624Meas:     ' fetches temperature result.  Value returned in T_HI and T_LO

     Gosub I2CStart
     OByte = 2 * DevAdr + $90
     Gosub I2COutByte


     OByte = $AA          ' Fetch Temperature
     Gosub I2COutbyte


     Gosub I2CStart         ' read
     OByte = 2 * DevAdr + $91
     Gosub I2COutByte

     Ack = 1			   ' acknowledge after receiving the byte
     Gosub I2CInByte       ' fetch the two byte reading
     H = IByte    ' high byte

     Ack = 0			   ' no acknowledge as this is last byte prior to the stop
     Gosub I2CInByte       ' fetch the two byte reading
     L = IByte    ' low byte

     GoSub I2CStop

     Return

DS1624EERead:  ' fetches content location ADR in DS1624 EEPROM

     Gosub I2CStart
     OByte = 2 * DevAdr + $90
     Gosub I2COutByte

     OByte = $17          ' access EEPROM
     Gosub I2COutByte


     OByte = EEAdr          ' specify address to read
     Gosub I2COutByte

     Gosub I2CStart         ' read
     OByte = 2 * DevAdr + $91
     Gosub I2COutByte


     Ack = 0				' no ack as this is last byte prior to stop
     Gosub I2CInByte

     Gosub I2CStop
     H = IByte
     Return

DS1624EEWrite: ' writes content of DAT to specified address ADR

     Gosub I2CStart
     OByte = 2 * DevAdr + $90
     Gosub I2COutByte

     OByte = $17          ' access EEPROM
     Gosub I2COutByte


     OByte = EEAdr          ' specify address to read
     Gosub I2COutByte

     OByte = H          ' data to write
     Gosub I2COutByte

     Gosub I2CStop
     Pause 15            ' wait for EEPROM to program

     Return

I2CStart:
    High SDAOut
    High SCL
    Low SDAOut			' bring SDA low while SCL is high
    Low SCL
    Return

I2CStop:
    High SCL
    High SDAOut         ' bring SDA high while SCL is high
    Return


I2COutByte:

    For N = 1 to 8      ' for eight bits
       MSBit = OByte / 128  ' beginning with the MSB
       If MSBit = 1 Then I2COutByte_1 	' most sig bit

       Low SDAOut
       GoTo I2COutByte_2
I2COutByte_1:
       High SDAOut
I2COutByte_2:
       High SCL
       Low SCL
       OByte = OByte * 2	' shift byte such that next bit is in most sig bit position
    Next
    High SDAOut 			' null clock pulse to allow for slave to acknowledge
    High SCL
    Low SCL
    Low SDAOut
    Return

I2CInByte:  ' receives a byte, most sig byte first.
          ' result returned in I_BYTE
    High SDAOut
    For N=1 to 8             ' for eight bits
       High SCL
       IByte = IByte * 2 + SDAIn
       Low SCL
    Next
    Branch Ack, (NoAck, YesAck)

NoAck:
     High SDAOut             ' high Z on 9th clock pulse
     Goto I2CInByte1

YesAck:
     Low SDAOut              ' logic zero on 9th clock pulse
I2CInByte1:
     High SCL
     Low SCL

     Low SDAOut

     Return