If you don't want to upgrade PBP, and you don't mind adding some additional code, here is a customizable I2C routine that will work with the DS1307 (it could also be set-up to work with multiple I2C devices):
Code:
' SDA = I2C serial data line
' SCL = I2C serial clock lines
'
DS1307 Con $D0 ' I2C Slave Device "Write" Address (DS1307)
I2Cdelay con 15 ' usec delay used in SDA and SCL timing
' routines.
blocksize con 8 ' maximum # of bytes to send or receive
i2cBytes var byte ' # of bytes in data array
i2cData var byte[blocksize] ' data array
i2cWork var byte ' work byte for TX routine
i2cDevAddr var byte ' Device Slave Address
i2cAddr var word ' Memory Address
i2cloop var byte
i2cindex var byte
' ----------------------------------------------------
' Subroutines
' ----------------------------------------------------
'DS1307 RTC Time/Date Register Block Write Routine
'(i2cData = data array, i2cbytes = # of bytes to send)
DS1307blkwrite:
i2cDevAddr = DS1307 ' set slave device WRITE address
Gosub I2C_AddrSend ' Send Address Info!
For i2cindex = 0 To (i2cbytes-1) ' loop for number of bytes in array
i2cWork = i2cData[i2cindex] ' xfer from array to temp
Gosub I2C_TX_Byte ' Send Data!
Next i2cindex
Gosub I2C_Stop ' Finished!
Return
'DS1307 RTC Time/Date Register Byte Write Routine
'(i2cData = byte to send, i2caddr = address of byte to write)
DS1307bytewrite:
i2cDevAddr = DS1307 ' set slave device WRITE address
Gosub I2C_AddrSend ' Send Address Info!
i2cWork = i2cData ' Transfer data!
Gosub I2C_TX_Byte ' Send Data!
Gosub I2C_Stop ' Finished!
Return
'DS1307 RTC Time/Date Register Block Read Routine
'(i2cData = data array, i2cbytes = # of bytes to read)
DS1307blkread:
i2cDevAddr = DS1307 ' set slave device WRITE address
Gosub I2C_AddrSend ' Send Address Info!
Gosub I2C_Stop ' break between events and
Gosub I2C_Start ' re-start for device read
i2cWork = (DS1307+1) ' set slave device READ address
Gosub I2C_TX_Byte
For i2cindex = 0 To (i2cbytes-1) ' loop for number of bytes in array
Gosub I2C_RX_Byte ' Receive Data!
i2cData[i2cindex] = i2cWork ' Transfer Data!
If i2cindex != 6 Then Gosub I2C_ACK
Next i2cindex
Gosub I2C_Stop ' Finished!
Return
'DS1307 RTC Time/Date Register Byte Read Routine
'(i2cData = byte to receive, i2caddr = address of byte to read)
DS1307byteread:
i2cDevAddr = DS1307 ' set slave device WRITE address
Gosub I2C_AddrSend ' Send Address Info!
Gosub I2C_Stop ' break between events and
Gosub I2C_Start ' re-start for device read
i2cWork = (DS1307+1) ' set slave device READ address
Gosub I2C_TX_Byte
Gosub I2C_RX_Byte ' Receive Data!
i2cData = i2cWork ' Transfer Data!
Gosub I2C_Stop ' Finished!
Return
'I2C Device Read/Write and Memory Address Routine
'(i2cDevAddr = Device Address, i2caddr = Memory Address)
I2C_AddrSend:
Gosub I2C_Stop ' Normalize Bus/Recover from errors
Gosub I2C_Start ' send Start
i2cWork = i2cDevAddr ' send slave WRITE address
Gosub I2C_TX_Byte
i2cWork = i2caddr // 256 ' send LSB ADDRESS
Gosub I2C_TX_Byte
If i2cDevAddr = DS1307 Then Return ' 1 byte memory address
i2cWork = i2caddr / 256 ' send MSB ADDRESS
Goto I2C_TX_Byte
' ----------------------------------------------------
' Low Level I2C Subroutines
' ----------------------------------------------------
' --- Start ---
I2C_Start: ' I2C start bit sequence
Gosub SCLlo
Gosub SDAhi
Gosub SCLhi
Gosub SDAlo ' SDA -> low while SCL high
Goto SCLlo
' --- Stop ---
I2C_Stop: ' I2C stop bit sequence
Gosub SCLlo
Gosub SDAlo
Gosub SCLhi
Gosub SDAhi ' SDA --> high while SCL high
Goto SCLlo
' --- Transmit ---
I2C_TX_Byte:
For i2cloop = 0 to 7
If i2cWork.7 = 0 Then
Gosub SDAlo
Else
Gosub SDAhi
Endif
Gosub SCLhi
Gosub SCLlo
i2cWork = i2cWork << 1
Next i2cloop
Goto I2C_NACK
' --- Receive ---
I2C_RX_Byte:
For i2cloop = 0 to 7
Gosub SCLhi
i2cWork = (i2cWork*2)+ SDA ' shift left and insert bit
Gosub SCLlo
Next i2cloop
Return
'Get Acknowledge Bit
I2C_NACK:
Gosub SDAhi
Gosub SCLhi
Goto SCLlo
'Send Acknowledge Bit
I2C_ACK:
Gosub SDAlo
Gosub SCLhi
Gosub SCLlo
Goto SDAhi
SDAhi:
Input SDA
Pauseus I2Cdelay
Return
SDAlo:
Low SDA
Pauseus I2Cdelay
Return
SCLhi:
High SCL
Pauseus I2Cdelay
Return
SCLlo:
Low SCL
Pauseus I2Cdelay
Return
There are 2 sets of routines, block read/write, and byte read/write.
Here is an example using block read to fetch the time/date registers:
Code:
'Retrieve RTC values
getclk:
i2caddr = 0
i2cbytes = 7
Gosub DS1307blkread
For indx = 0 to 6
Select Case indx
Case 0 'seconds
secs = i2cData[indx]
Case 1 'minutes
mins = i2cData[indx]
Case 2 'hours
hours = i2cData[indx]
Case 3 'day of the week
dweek = i2cData[indx]
Case 4 'day
day = i2cData[indx]
Case 5 'month
month = i2cData[indx]
Case 6 'year
year = i2cData[indx]
End Select
Next indx
Return
And here is a way to update those same registers with the block write routine:
Code:
'Update RTC registers from system variables
UpdateRTC:
Gosub RTCoff
For indx = 0 to 6
Select Case indx
Case 0 'seconds
If newsecs = $FF Then newsecs = 59
If newsecs > 59 Then newsecs = 0
tTemp = newsecs
Gosub dec2BCD
Case 1 'minutes
If newmins = $FF Then newmins = 59
If newmins > 59 Then newmins = 0
tTemp = newmins
Gosub dec2BCD
Case 2 'hours
If newhours = $FF Then newhours = 23
If newhours > 23 Then newhours = 0
tTemp = newhours
Gosub dec2BCD
Case 3 'day of the week
If newdweek = $FF Or newdweek = 0 Then newdweek = 7
If newdweek > 7 Then newdweek = 1
tTemp = newdweek
Gosub dec2BCD
Case 4 'day
tTemp = month
Gosub BCD2dec
If tTemp // 2 = 0 Then
daytop = 30
Else
daytop = 31
Endif
If tTemp = 2 Then
tTemp = year
Gosub BCD2dec
If tTemp // 4 = 0 Then
daytop = 29
Else
daytop = 28
Endif
Endif
If newday = $FF Or newday = 0 Then newday = daytop
If newday > daytop Then newday = 1
tTemp = newday
Gosub dec2BCD
Case 5 'month
If newmonth = $FF Or newmonth = 0 Then newmonth = 12
If newmonth > 12 Then newmonth = 1
tTemp = newmonth
Gosub dec2BCD
Case 6 'year
If newyear = $FF Then newyear = 99
If newyear > 99 Then newyear = 0
tTemp = newyear
Gosub dec2BCD
End Select
Next indx
i2caddr = 0
i2cbytes = 7
Gosub DS1307blkwrite
Goto RTCon
dec2BCD:
tTemp = ((tTemp DIG 1) << 4) | (tTemp DIG 0)
i2cData[indx] = tTemp
Return
BCD2dec:
tTemp = ((tTemp >> 4)*10) + (tTemp & %1111)
Return
And here are some handy low level byte write routines:
Code:
RTCon:
i2caddr = 0
Gosub DS1307byteread
If i2cData.7 = 0 Then Return
i2cData = i2cData & %01111111
i2caddr = 0
Goto DS1307bytewrite
RTCoff:
i2caddr = 0
Gosub DS1307byteread
If i2cData.7 = 1 Then Return
i2cData = i2cData | %10000000
i2caddr = 0
Goto DS1307bytewrite
RTChour24:
i2caddr = 2
Gosub DS1307byteread
If i2cData.6 = 0 Then Return
i2cData = 0
i2caddr = 2
Goto DS1307bytewrite
And here is a routine that will do a block read and then update your system variables directly from the time/date registers:
Code:
'Refresh system variables from RTC registers
RTCrefresh:
Gosub getclk
tTemp = secs
Gosub BCD2dec
newsecs = tTemp
tTemp = mins
Gosub BCD2dec
newmins = tTemp
tTemp = hours
Gosub BCD2dec
newhours = tTemp
tTemp = dweek
Gosub BCD2dec
newdweek = tTemp
tTemp = day
Gosub BCD2dec
newday = tTemp
tTemp = month
Gosub BCD2dec
newmonth = tTemp
tTemp = year
Gosub BCD2dec
newyear = tTemp
Return
I don't know if any of this will be of use to you, but I had it laying around and I figured I should at least offer it up.
Bookmarks