Introduction.
The BX24 provides an onboard real time clock. However, the use of some functions sacrifices its accuracy. Further, in many low power applications, one may wish to turn the BX24 off so as to save power.
Thus, an attractive alternative is to use an outboard real time clock with its own back up battery such that when the +5V power is lost the clock continues to operate.
The following presents four routines using the Dallas DS1307 Real Time Clock which uses the Philips I2C 2-wire protocol. Note that in preparing this tutorial I modifed the I2C routines which were first used with the BX-01 and these new rotuines appear at the bottom of this page. All routines, the four DS1307 routines and the I2C_BX24.Bas routines may be downloaded in zipped format. Click Here.
In DS1307_1.Bas, a date and time are written to the DS1307 and the RTC is then read at nominally one second intervals. Note that the date and time is stored in BCD format which agrees with the architecture of the DS1307, but it somewhat ackward in attempting to perform calculations.
Program DS1307_2.Bas improves on this by working with the date and time quantities in natural binary. Note that in writing to the DS1307, the quantities are converted to BCD and when reading from the DS1307, the BCD is converted to natural binary.
Program DS1307_3.Bas uses this natural binary to perform a DS1307Timer function which provides the number of seconds since midnight much like the BX24's Timer() function.
Program DS1307_4.Bas illustrates how to write to and read from the 56 RAM locations on the DS1307. Assumming the DS1307 uses a battery backup, this might be a useful alternative to using a persistent variable which is frequently written.
' DS1307_1.Bas
'
' Writes a base time and date to DS1307. About every second reads
' time and date and displays to the terminal.
'
' Note that Dt and Tm are passed as arrays. Thus Dt(Yr) refers to
' the year. Tm(Se) refers to seconds. This approach alleviates
' the passing of numerous arguments.
'
' Note that Dt and Tm are in BCD (vs decimal) which agress with the
' method or storing data in the DS1307. However, this is ackward in
' performing such calculations as calculating the elapsed time.
' Program DS1307_2.Bas improves on this such that the conversion to and
' from BCD is performed in DS1307PutTime, .. PutDate, ... GetTime and
' ... GetDate.
'
' Note that, the Weekday is simply a number which is in the range of 0 - 6.
' I defined Weekday 0 to be Sunday.
'
' BX-24 DS1307
'
' Term 14 ------------------- SCL (term 6) ----- To Other
' Term 13 ------------------- SDA (term 5) ----- I2C Devices
'
' Note that 4.7K pullup resistor to +5 VDC are required on both the
' SDA and SCL leads.
'
' Note that there is no provision for the user defining the
' secondary I2C address using straps.
'
' Compile with I2C_BX24.Bas and SerialPort.Bas
'
' copyright, Peter H. Anderson, Baltimore, MD, Sept, '00
Public Const SDA_PIN as Byte = 13 ' may be modified as required
Public Const SCL_PIN as Byte = 14
Const Hr as Integer = 1 ' define elements of array Tm
Const Mi as Integer = 2
Const Se as Integer = 3
Const Yr as Integer = 1 ' define elements of array Dt
Const Mo as Integer = 2
Const Da as Integer = 3
Const WkDay as Integer = 4
Sub Main()
Dim Tm(1 to 3) as Byte
Dim Dt(1 to 4) as Byte
Dt(Yr) = &H00 ' Initialize the date to Sept 13, '00
Dt(Mo) = &H09
Dt(Da) = &H13
Dt(WkDay) = &H03 ' Weds
Tm(Hr) = &H23 ' Init the time to 23:59:00
Tm(Mi) = &H59
Tm(Se) = &H00
Call OpenSerialPort(1, 19200)
Call DS1307SetUpClk(&H10) ' sqwe enabled, 1 Hz output
Call DS1307PutDate(Dt) ' Init DS1307 date
Call DS1307PutTime(Tm) ' and time
Do ' continually read date and time
Call DS1307GetDate(Dt)
Call DS1307GetTime(Tm)
Call DisplayDateTime(Dt, Tm) ' and display
Sleep(1.0)
Loop
End Sub
Sub DS1307SetUpClk(ByVal ControlReg as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0) ' address the DS1307
Call I2C_Nack()
Call I2C_Out_byte(&H07) ' control register address
Call I2C_Nack()
Call I2C_Out_Byte(ControlReg)
Call I2C_Nack()
Call I2C_Stop()
End Sub
Sub DS1307PutDate(ByRef Dt() as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(&H03) ' first address to write
Call I2C_Nack()
Call I2C_Out_Byte(Dt(WkDay))
Call I2C_Nack()
Call I2C_Out_Byte(Dt(Da))
Call I2C_Nack()
Call I2C_Out_Byte(Dt(Mo))
Call I2C_Nack()
Call I2C_Out_Byte(Dt(Yr))
Call I2C_Nack()
Call I2C_Stop()
End Sub
Sub DS1307GetDate(ByRef Dt() as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(&H03) ' first address to read
Call I2C_Nack()
Call I2C_Stop()
Call I2C_Start()
Call I2C_Out_Byte(&HD1) ' read
Call I2C_Nack()
Dt(WkDay) = I2C_In_Byte() AND &H07
Call I2C_Ack()
Dt(Da) = I2C_In_Byte() AND &H3F
Call I2C_Ack()
Dt(Mo) = I2C_In_Byte() AND &H3F
Call I2C_Ack()
Dt(Yr) = I2C_In_Byte() ' no ack prior to stop
Call I2C_Stop()
End Sub
Sub DS1307PutTime(ByRef Tm() as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(&H00) ' first address to write
Call I2C_Nack()
Call I2C_Out_Byte(Tm(Se))
Call I2C_Nack()
Call I2C_Out_Byte(Tm(Mi))
Call I2C_Nack()
Call I2C_Out_Byte(Tm(Hr))
Call I2C_Nack()
Call I2C_Stop()
End Sub
Sub DS1307GetTime(ByRef Tm() as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(&H00) ' first address to read, Secs, Mins, Hrs
Call I2C_Nack()
Call I2C_Stop()
Call I2C_Start()
Call I2C_Out_Byte(&HD1) ' read
Call I2C_Nack()
Tm(Se) = I2C_In_Byte() AND &H7F
Call I2C_Ack()
Tm(Mi) = I2C_In_Byte() AND &H7F
Call I2C_Ack()
Tm(Hr) = I2C_In_Byte() AND &H3F ' no ack prior to stop
Call I2C_Stop()
End Sub
Sub DisplayDateTime(ByRef Dt() as Byte, Tm() as Byte)
Dim Str as String *16
Select Case Dt(WkDay) ' output the weekday
Case 0
Str = "Sunday"
Case 1
Str = "Monday"
Case 2
Str = "Tuesday"
Case 3
Str = "Wednesday"
Case 4
Str = "Thursday"
Case 5
Str = "Friday"
Case Else
Str = "Saturday"
End Select
Call PutStr(Str)
Call NewLine()
Call PutHexB(Dt(Mo)) ' MM/DD/YY
Call PutByte(Asc("/"))
Call PutHexB(Dt(Da))
Call PutByte(Asc("/"))
Call PutHexB(Dt(Yr))
Call PutByte(Asc(" "))
Call PutHexB(Tm(Hr)) ' HH:MM:SS
Call PutByte(Asc(":"))
Call PutHexB(Tm(Mi))
Call PutByte(Asc(":"))
Call PutHexB(Tm(Se))
Call NewLine()
End Sub
Sub PutHexB(ByVal X as Byte) ' display a byte in hex format
Dim Y as Byte
Y= X \ 16 ' convert high nibble to character
If (Y < 10) then
Y = Y + Asc("0")
Else
Y = Y - 10 + Asc ("A")
End If
Call PutByte(Y)
Y= X And bx00001111 ' same for low nibble
If (Y < 10) then
Y = Y + Asc("0")
Else
Y = Y - 10 + Asc ("A")
End If
Call PutByte(Y)
End Sub
' DS1307_2.Bas
'
' Writes a base time and date to DS1307. About every second reads
' time and date and displays to the terminal.
'
' Note that Dt and Tm are passed as arrays. Thus Dt(Yr) refers to
' the year. Tm(Se) refers to seconds. This approach alleviates
' the passing of numerous arguments.
'
' Note that Dt and Tm are in decimal. The conversion to BCD is made
' in DS1307PutDate and DS1307PutTime. When reading the date and time
' in DS1307GetDate and DS1307GetTime, the BCD value is converted to
' decimal.
'
' Note that, the Weekday is simply a number which is in the range of 0 - 6.
' I defined Weekday 0 to be Sunday.
'
' BX-24 DS1307
'
' Term 14 ------------------- SCL (term 6) ----- To Other
' Term 13 ------------------- SDA (term 5) ----- I2C Devices
'
' Note that 4.7K pullup resistor to +5 VDC are required on both the
' SDA and SCL leads.
'
' Note that there is no provision for the user defining the
' secondary I2C address using straps.
'
' Compile with I2C.Bas and SerialPort.Bas
'
' copyright, Peter H. Anderson, Baltimore, MD, Sept, '00
Public Const SDA_PIN as Byte = 13 ' may be modified as required
Public Const SCL_PIN as Byte = 14
Const Hr as Integer = 1 ' define elements of array Tm
Const Mi as Integer = 2
Const Se as Integer = 3
Const Yr as Integer = 1 ' define elements of array Dt
Const Mo as Integer = 2
Const Da as Integer = 3
Const WkDay as Integer = 4
Sub Main()
Dim Tm(1 to 3) as Byte
Dim Dt(1 to 4) as Byte
Dt(Yr) = 00 ' Initialize the date to Sept 13, '00
Dt(Mo) = 9
Dt(Da) = 13
Dt(WkDay) = 03 ' Weds
Tm(Hr) = 23 ' Init the time to 23:59:00
Tm(Mi) = 59
Tm(Se) = 00
Call OpenSerialPort(1, 19200)
Call DS1307SetUpClk(&H10) ' sqwe enabled, 1 Hz output
Call DS1307PutDate(Dt) ' Init DS1307 date
Call DS1307PutTime(Tm) ' and time
Do ' continually read date and time
Call DS1307GetDate(Dt)
Call DS1307GetTime(Tm)
Call DisplayDateTime(Dt, Tm) ' and display
Sleep(1.0)
Loop
End Sub
Sub DS1307SetUpClk(ByVal ControlReg as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0) ' address the DS1307
Call I2C_Nack()
Call I2C_Out_Byte(&H07) ' control register address
Call I2C_Nack()
Call I2C_Out_Byte(ControlReg)
Call I2C_Nack()
Call I2C_Stop()
End Sub
Sub DS1307PutDate(ByRef Dt() as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(&H03) ' first address to write
Call I2C_Nack()
Call I2C_Out_Byte(Dt(WkDay))
Call I2C_Nack()
Call I2C_Out_Byte(DectoBCD(Dt(Da)))
Call I2C_Nack()
Call I2C_Out_Byte(DectoBCD(Dt(Mo)))
Call I2C_Nack()
Call I2C_Out_Byte(DectoBCD(Dt(Yr)))
Call I2C_Nack()
Call I2C_Stop()
End Sub
Sub DS1307GetDate(ByRef Dt() as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(&H03) ' first address to read
Call I2C_Nack()
Call I2C_Stop()
Call I2C_Start()
Call I2C_Out_Byte(&HD1) ' read
Call I2C_Nack()
Dt(WkDay) = I2C_In_Byte() AND &H07
Call I2C_Ack()
Dt(Da) = BCDtoDec(I2C_In_Byte() AND &H3F)
Call I2C_Ack()
Dt(Mo) = BCDtoDec(I2C_In_Byte() AND &H3F)
Call I2C_Ack()
Dt(Yr) = I2C_In_Byte() ' no ack prior to stop
Call I2C_Stop()
End Sub
Sub DS1307PutTime(ByRef Tm() as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(&H00) ' first address to write
Call I2C_Nack()
Call I2C_Out_Byte(DectoBCD(Tm(Se)))
Call I2C_Nack()
Call I2C_Out_Byte(DectoBCD(Tm(Mi)))
Call I2C_Nack()
Call I2C_Out_Byte(DectoBCD(Tm(Hr)))
Call I2C_Nack()
Call I2C_Stop()
End Sub
Sub DS1307GetTime(ByRef Tm() as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(&H00) ' first address to read, Secs, Mins, Hrs
Call I2C_Nack()
Call I2C_Stop()
Call I2C_Start()
Call I2C_Out_Byte(&HD1) ' read
Call I2C_Nack()
Tm(Se) = BCDtoDec(I2C_In_Byte() AND &H7F)
Call I2C_Ack()
Tm(Mi) = BCDtoDec(I2C_In_Byte() AND &H7F)
Call I2C_Ack()
Tm(Hr) = BCDtoDec(I2C_In_Byte() AND &H3F) ' no ack prior to stop
Call I2C_Stop()
End Sub
Sub DisplayDateTime(ByRef Dt() as Byte, Tm() as Byte)
Dim Str as String *16
Select Case Dt(WkDay) ' output the weekday
Case 0
Str = "Sunday"
Case 1
Str = "Monday"
Case 2
Str = "Tuesday"
Case 3
Str = "Wednesday"
Case 4
Str = "Thursday"
Case 5
Str = "Friday"
Case Else
Str = "Saturday"
End Select
Call PutStr(Str)
Call NewLine()
Call PutBCDB(Dt(Mo)) ' MM/DD/YY
Call PutByte(Asc("/"))
Call PutBCDB(Dt(Da))
Call PutByte(Asc("/"))
Call PutBCDB(Dt(Yr))
Call PutByte(Asc(" "))
Call PutBCDB(Tm(Hr)) ' HH:MM:SS
Call PutByte(Asc(":"))
Call PutBCDB(Tm(Mi))
Call PutByte(Asc(":"))
Call PutBCDB(Tm(Se))
Call NewLine()
End Sub
Sub PutBCDB(ByVal X as Byte) ' display a dec quantity BCD format
Dim Y as Byte
Y= X \ 10 ' convert tens to character
Y = Y + Asc("0")
Call PutByte(Y)
Y= X MOD 10 ' same for units
Y = Y + Asc("0")
Call PutByte(Y)
End Sub
Function BCDtoDec(ByVal X as Byte) as Byte
Dim H as Byte, L as Byte
H = X \ 16
L = X MOD 16
BCDtoDec = H*10 + L
End Function
Function DectoBCD(ByVal X as Byte) as Byte
Dim H as Byte, L as Byte
H = X \ 10
L = X MOD 10
DectoBCD = H * 16 + L
End Function
' DS1307_3.Bas
'
' Writes a base time and date to DS1307. About every second reads
' time which has elapsed since midnight and displays to the terminal.
'
' Note that Dt and Tm are passed as arrays. Thus Dt(Yr) refers to
' the year. Tm(Se) refers to seconds. This approach alleviates
' the passing of numerous arguments.
'
' Note that Dt and Tm are in decimal. The conversion to BCD is made
' in DS1307PutDate and DS1307PutTime. When reading the date and time
' in DS1307GetDate and DS1307GetTime, the BCD value is converted to
' decimal.
'
' Note that, the Weekday is simply a number which is in the range of 0 - 6.
' I defined Weekday 0 to be Sunday.
'
' BX-24 DS1307
'
' Term 14 ------------------- SCL (term 6) ----- To Other
' Term 13 ------------------- SDA (term 5) ----- I2C Devices
'
' Note that 4.7K pullup resistor to +5 VDC are required on both the
' SDA and SCL leads.
'
' Note that there is no provision for the user defining the
' secondary I2C address using straps.
'
' Compile with I2C.Bas and SerialPort.Bas
'
' copyright, Peter H. Anderson, Baltimore, MD, Mar, '00
Public Const SDA_PIN as Byte = 13 ' may be modified as required
Public Const SCL_PIN as Byte = 14
Const Hr as Integer = 1 ' define elements of array Tm
Const Mi as Integer = 2
Const Se as Integer = 3
Const Yr as Integer = 1 ' define elements of array Dt
Const Mo as Integer = 2
Const Da as Integer = 3
Const WkDay as Integer = 4
Sub Main()
Dim Tm(1 to 3) as Byte
Dim Dt(1 to 4) as Byte
Dim ElapsedTime as Long
Dt(Yr) = 00 ' Initialize the date to Sept 13, '00
Dt(Mo) = 9
Dt(Da) = 13
Dt(WkDay) = 03 ' Weds
Tm(Hr) = 23 ' Init the time to 23:59:00
Tm(Mi) = 59
Tm(Se) = 00
Call OpenSerialPort(1, 19200)
Call DS1307SetUpClk(&H10) ' sqwe enabled, 1 Hz output
Call DS1307PutDate(Dt) ' Init DS1307 date
Call DS1307PutTime(Tm) ' and time
Do ' continually read the elapsed time
ElapsedTime = DS1307Timer()
Call PutL(ElapsedTime) ' and display
Call NewLine()
Sleep(1.0)
Loop
End Sub
Sub DS1307SetUpClk(ByVal ControlReg as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0) ' address the DS1307
Call I2C_Nack()
Call I2C_Out_Byte(&H07) ' control register address
Call I2C_Nack()
Call I2C_Out_Byte(ControlReg)
Call I2C_Nack()
Call I2C_Stop()
End Sub
Sub DS1307PutDate(ByRef Dt() as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(&H03) ' first address to write
Call I2C_Nack()
Call I2C_Out_Byte(Dt(WkDay))
Call I2C_Nack()
Call I2C_Out_Byte(DectoBCD(Dt(Da)))
Call I2C_Nack()
Call I2C_Out_Byte(DectoBCD(Dt(Mo)))
Call I2C_Nack()
Call I2C_Out_Byte(DectoBCD(Dt(Yr)))
Call I2C_Nack()
Call I2C_Stop()
End Sub
Sub DS1307GetDate(ByRef Dt() as Byte)
' Not used in this routine
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(&H03) ' first address to read
Call I2C_Nack()
Call I2C_Stop()
Call I2C_Start()
Call I2C_Out_Byte(&HD1) ' read
Call I2C_Nack()
Dt(WkDay) = I2C_In_Byte() AND &H07
Call I2C_Ack()
Dt(Da) = BCDtoDec(I2C_In_Byte() AND &H3F)
Call I2C_Ack()
Dt(Mo) = BCDtoDec(I2C_In_Byte() AND &H3F)
Call I2C_Ack()
Dt(Yr) = I2C_In_Byte() ' no ack prior to stop
Call I2C_Stop()
End Sub
Sub DS1307PutTime(ByRef Tm() as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(&H00) ' first address to write
Call I2C_Nack()
Call I2C_Out_Byte(DectoBCD(Tm(Se)))
Call I2C_Nack()
Call I2C_Out_Byte(DectoBCD(Tm(Mi)))
Call I2C_Nack()
Call I2C_Out_Byte(DectoBCD(Tm(Hr)))
Call I2C_Nack()
Call I2C_Stop()
End Sub
Sub DS1307GetTime(ByRef Tm() as Byte)
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(&H00) ' first address to read, Secs, Mins, Hrs
Call I2C_Nack()
Call I2C_Stop()
Call I2C_Start()
Call I2C_Out_Byte(&HD1) ' read
Call I2C_Nack()
Tm(Se) = BCDtoDec(I2C_In_Byte() AND &H7F)
Call I2C_Ack()
Tm(Mi) = BCDtoDec(I2C_In_Byte() AND &H7F)
Call I2C_Ack()
Tm(Hr) = BCDtoDec(I2C_In_Byte() AND &H3F) ' no ack prior to stop
Call I2C_Stop()
End Sub
Function DS1307Timer() as Long ' returns the number of seconds since
' midnight
Dim Tm(1 to 3) as Byte
Dim ET as Long
Call DS1307GetTime(Tm) ' fetch hours, minutes, secs
ET = 3600 * CLng(Tm(Hr)) + 60 * CLng(Tm(Mi)) + CLng(Tm(Se))
DS1307Timer = ET
End Function
Sub DisplayDateTime(ByRef Dt() as Byte, Tm() as Byte)
' Not used in this routine
Dim Str as String *16
Select Case Dt(WkDay) ' output the weekday
Case 0
Str = "Sunday"
Case 1
Str = "Monday"
Case 2
Str = "Tuesday"
Case 3
Str = "Wednesday"
Case 4
Str = "Thursday"
Case 5
Str = "Friday"
Case Else
Str = "Saturday"
End Select
Call PutStr(Str)
Call NewLine()
Call PutBCDB(Dt(Mo)) ' MM/DD/YY
Call PutByte(Asc("/"))
Call PutBCDB(Dt(Da))
Call PutByte(Asc("/"))
Call PutBCDB(Dt(Yr))
Call PutByte(Asc(" "))
Call PutBCDB(Tm(Hr)) ' HH:MM:SS
Call PutByte(Asc(":"))
Call PutBCDB(Tm(Mi))
Call PutByte(Asc(":"))
Call PutBCDB(Tm(Se))
Call NewLine()
End Sub
Sub PutBCDB(ByVal X as Byte) ' display a dec quantity BCD format
Dim Y as Byte
Y= X \ 10 ' convert tens to character
Y = Y + Asc("0")
Call PutByte(Y)
Y= X MOD 10 ' same for units
Y = Y + Asc("0")
Call PutByte(Y)
End Sub
Function BCDtoDec(ByVal X as Byte) as Byte
Dim H as Byte, L as Byte
H = X \ 16
L = X MOD 16
BCDtoDec = H*10 + L
End Function
Function DectoBCD(ByVal X as Byte) as Byte
Dim H as Byte, L as Byte
H = X \ 10
L = X MOD 10
DectoBCD = H * 16 + L
End Function
' DS1307_4.Bas
'
' Illustrates use of the 56 RAM locations on the DS1307.
'
' Sub DS1307PutRAM(A() as Byte, Adr as Byte, NumBytes as Byte)
' Writes NumBytes of data in array A beginning at address Adr
' Reads NumBytes of data beginning at address Adr into Array A
'
' BX-24 DS1307
'
' Term 14 ------------------- SCL (term 6) ----- To Other
' Term 13 ------------------- SDA (term 5) ----- I2C Devices
'
' Note that 4.7K pullup resistor to +5 VDC are required on both the
' SDA and SCL leads.
'
' Note that there is no provision for the user defining the
' secondary I2C address using straps.
'
' Compile with I2C.Bas and SerialPort.Bas
'
' copyright, Peter H. Anderson, Baltimore, MD, Sept, '00
Public Const SDA_PIN as Byte = 13 ' may be modified as required
Public Const SCL_PIN as Byte = 14
Sub Main()
Dim A(1 to 56) as Byte
Call OpenSerialPort(1, 19200)
Call DummyArray(A, 56) ' dummy up the array with some values
Call PrintArray(A, 56)
Call DS1307PutRAM(A, 8, 56) ' write 56 bytes to RAM
Call DS1307GetRAM(A, 8, 56)
Call PrintArray(A, 56)
End Sub
Sub DS1307PutRAM(ByRef A() as Byte, ByVal Adr as Byte, ByVal Num as Byte)
Dim N as Integer
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(Adr) ' first address to write
Call I2C_Nack()
For N = 1 to CInt(Num)
Call I2C_Out_Byte(A(N))
Call I2C_Nack()
Next
Call I2C_Stop()
End Sub
Sub DS1307GetRAM(ByRef A() as Byte, ByVal Adr as Byte, ByVal Num as Byte)
Dim N as Integer
Call I2C_Start()
Call I2C_Out_Byte(&HD0)
Call I2C_Nack()
Call I2C_Out_Byte(Adr) ' first address to read
Call I2C_Nack()
Call I2C_Stop()
Call I2C_Start()
Call I2C_Out_Byte(&HD1) ' read
Call I2C_Nack()
For N = 1 to CInt(Num)
A(N) = I2C_In_Byte()
If (N <> CInt(Num)) Then
Call I2C_Ack() ' no ack after the last byte
End If
Next
Call I2C_Stop()
End Sub
Sub DummyArray(ByRef A() as Byte, ByVal Num as Byte)
' simply fill the array with some numbers
Dim N as Integer
For N = 1 to CInt(Num)
A(N) = 100 + CByte(N)
Next
End Sub
Sub PrintArray(ByRef A()as Byte, ByVal Num as Byte)
Dim N as Integer
For N = 1 to CInt(Num)
Call PutBFixed2(A(N))
Call PutByte(Asc(" "))
If (((N+1) MOD 8) = 0) Then
Call NewLine()
End If
Next
End Sub
Sub PutBFixed2(ByVal X as Byte)
Dim Y as Byte
Y = X\10 + Asc("0")
Call PutByte(Y)
Y = (X MOD 10) + Asc("0")
Call PutByte(Y)
End Sub
' I2C_BX24.Bas
Attribute VB_Name = "I2C_BX24"
'-------------------
Option Explicit
' This module is a collection of low level I2C routines intended to be
' included in a project using such I2C devices as the Microchip 24 series
' EEPROMs, MAX518 D/A, PCF8574 I/O Expander, DS1803 Digital Pot, PCF8591
' A/D plus D/A and many other devices.
'
' Public Sub I2C_out_byte(ByVal O_byte As Byte) - sends O_byte to I2C
' slave, most significant bit first.
'
' Public Sub I2C_nack() - provides high Z on SDA for one clock pulse
' allowing slave to acknowledge receipt of a byte.
'
' Public Function I2C_in_byte(ByRef I_byte As Byte) - receives a byte from
' I2C slave.
'
' Public Sub I2C_ack() - send ack to slave by bringing SDA low for one
' clock pulse.
'
' Public Sub I2C_start() - initiates sequence by bringing SDA low while
' SCL is high. (Could be Private rather than Public).
'
' Public Sub I2C_stop() - terminates sequence by bringing SDA high
' while SCL is high. (Could be Private rather than Public).
'
' Public Sub I2C_high_sda() - bring SDA high (high Z)
'
' Public Sub I2C_high_scl() - bring SCL high (high Z)
'
' Public Sub I2C_low_sda() - bring SDA low, hard logic zero
'
' Public Sub I2C_low_scl() - bring SCL low, hard logic zero
'
' Note that SDA_PIN and SCL_PIN should be publicly defined in the calling
' module
'
' For example;
' Const SDA_PIN as Byte = 13
' Const SCL_PIN as Byte = 14
'
' Copyright, Peter H. Anderson, Baltimore, MD, Sept, '99
' Nov, '99 - Revised for BX24.
' Mar, '00 - I2C_In_Byte was made a function. Prior to this time it was a
' Sub where the result was passed by reference.
'
' ----------
Public Sub I2C_out_byte(ByVal O_byte As Byte)
DIM N as Byte
For N = 1 TO 8 Step 1
If (O_byte >= 128) then ' most sig bit is a one
Call I2C_high_sda()
'Call PutB(1) ' used for debugging
Else
Call I2C_low_sda() ' set SDA and then clock
'Call PutB(0) ' used for debugging
End If
Call I2C_high_scl()
Call I2C_low_scl()
O_byte = O_byte * 2 ' shift left
Next
' Call NewLine() ' used for debugging
End Sub
Public Function I2C_in_byte() as Byte
DIM N as Byte, Y as Byte, I_Byte as Byte
I_Byte = 0
For N = 1 to 8 Step 1
Call I2C_high_scl() ' bring clock high
Y = GetPin(SDA_PIN) ' read SDA
' Call PutB(Y)
Call I2C_low_scl()
I_byte = I_byte * 2 + Y ' shift left and insert Y
Next
' Call NewLine()
I2C_In_Byte = I_Byte
End Function
Public Sub I2C_nack() ' allows slave to acknowledge
Call I2C_high_sda() ' SDA high
Call I2C_high_scl() ' and then clock
Call I2C_low_scl()
End Sub
Public Sub I2C_ack() ' send ack to slave by bringing SDA low
Call I2C_low_sda()
Call I2C_high_scl()
Call I2C_low_scl()
Call I2C_high_sda() ' be sure SDA is again high
End Sub
Public Sub I2C_start() ' bring SDA low while SCL is high
Call I2C_low_scl()
Call I2C_high_sda()
Call I2C_high_scl()
Call I2C_low_sda()
Call I2C_low_scl()
End Sub
Public Sub I2C_stop() ' bring SDA high while SCL is high
Call I2C_low_scl()
Call I2C_low_sda()
Call I2C_high_scl()
Call I2C_high_sda()
End Sub
Public Sub I2C_high_sda()
Call PutPin(SDA_PIN, 2) ' tristate
End Sub
Public Sub I2C_high_scl() ' tristate
Call PutPin(SCL_PIN, 2)
End Sub
Public Sub I2C_low_sda()
Call PutPin(SDA_PIN, 0) ' hard logic zero
End Sub
Public Sub I2C_low_scl()
Call PutPin(SCL_PIN, 0) ' hard logic zero
End Sub