From Swordfish Wiki

SwordfishUser: DS1307

This code is a modified version of a DS1307 Real Time Clock (RTC) module originally coded by John Barrat. It's very easy to use and allows you to read and write seconds, minutes, hours, day, date, month and year information. In addition, 56 bytes of onboard SRAM can be accessed using the DS1307 modules ReadByte() and WriteByte() routines. The module also allows you to operate the device in either 24 hour or 12 hour format, with PM indicator.

The module code is split into two parts. The first module holds time and date structures and should be named "RTC.bas". The second module is the main DS1307 driver code and should be named "DS1307.bas". I put the time and date structures in a seperate file to allow other modules to be created using the same structures as the DS1307 module. For example, converting day and month ordinal values into string values.

Sample Code

// these options are the DS1307 connection - use software I2C...
#option DS1307_SI2C = true
#option I2C_SDA = PORTB.0
#option I2C_SCL = PORTB.1

// some LCD options - works on a Proton Development Board...
#option LCD_DATA = PORTD.4 
#option LCD_RS = PORTE.0
#option LCD_EN = PORTE.1

// import modules...
include "LCD.bas"
include "DS1307.bas" 
include "convert.bas"
include "utils.bas"

// if the DS1307 device has not been enabled, we need to give
// it some default values - here we set for 2 o'clock  
// on the 19th April 2007...
if not Enabled then
   Time.Hour = 14
   Time.Minute = 0
   Time.Second = 00
   Date.Day = 19
   Date.Month = 04
   Date.Year = 7
   DS1307.Write(Time,Date)
endif

// initilaise LCD...
SetAllDigital
Cls

// keep displaying the time and date...
while true
   DS1307.Read(Time, Date)
   LCD.WriteAt(1,1,DecToStr(Time.Hour, 2),":",DecToStr(Time.Minute,2),":",DecToStr(Time.Second,2))
   LCD.WriteAt(2,1,DecToStr(Date.Day,2),"/",DecToStr(Date.Month,2),"/",DecToStr(Date.Year,2))
wend

DS1307 Module

The DS1307 module uses a file called "RTC.bas". This holds the Time and Date data structures, which looks like this

module RTC

// time mode
public structure TTimeMode
   Is12Hour as boolean    // 12 or 24 hour clock
   PM as boolean          // holds the PM indicator
end structure

// time data structure...
public structure TTime
   Second as byte         // Second (0..59)
   Minute as byte         // Minute (0..59)
   Hour as byte           // Hour   (0..11 or 0..23)
   Mode as TTimeMode      // 12 or 24 hour clock, PM indicator
end structure

// date data structure...
public structure TDate
   Day   as byte        // Date  (0..31)
   Month as byte        // Month (1..12)
   Year  as byte        // Year  (0..99)
   DayOfWeek as byte    // day of the week (1..7)
end structure 

Now the main "DS1307.bas" module code...

module DS1307

// choose hardware or software I2C (default is hardware I2C)
#option DS1307_SI2C = false
#if IsOption (DS1307_SI2C) and not (DS1307_SI2C in (true, false))
   #error DS1307_SI2C, "Invalid Option, DS1307_SI2C must be true or false"
#endIf

// import modules...
include "Convert.bas" // BCD routines
include "RTC.bas"     // time and date structures

// software or hardware I2C... 
#if (_mssp > 0) and not DS1307_SI2C
   include "I2C.bas"
#else
   include "SI2C.bas"
#endif

// the module uses 'generic' I2C sub and function calls which are mapped onto either 
// hardware or software I2C - depending on the #option DS1307_SI2C...
dim 
   I2CWriteByte as WriteByte,
   I2CReadByte as ReadByte,
   I2CInitialize as Initialize,
   I2CStart as Start,
   I2CStop as Stop,
   I2CRestart as Restart

// local module constants...
const
   RTC_DEV_ADDR    = $D0,   // DS1307 device Address
   RTC_TIME        = $00,   // Address for time
   RTC_WDAY        = $03,   // Address for day of week number
   RTC_DATE        = $04,   // Address for date
   RTC_CONTROL     = $07,   // Address for control byte
   RTC_NVRAM       = $08,   // NVRAM start
   RTC_NVRAM_MAX   = $38    // NVRAM address max (56 decimal)

// public constants - used in calls to ReadControl() and WriteControl()...
public const   
   RTC_SQWE        = $10,   // Squarewave enable
   RTC_SQWF_1HZ    = $0,    // Squarewave frequency  1Hz
   RTC_SQWF_4KHz   = $1,    // Squarewave frequency  4.096KHz
   RTC_SQWF_8KHz   = $2,    // Squarewave frequency  8.192KHz 
   RTC_SQWF_32KHz  = $3,    // Squarewave frequency 32.768KHz  
   RTC_SQWOUT_H    = $80    // Set Squarewave output to high when disabled

// public variables...
public dim
   Time as TTime,    
   Date as TDate
{
****************************************************************************
* Name    : RTCStartWrite (PRIVATE)                                        *
* Purpose : Starts a RTC write                                             *
****************************************************************************
}
sub RTCStartWrite(Address as byte) 
   I2CStart
   I2CWriteByte(RTC_DEV_ADDR)
   I2CWriteByte(Address)        
end sub
{
****************************************************************************
* Name    : RTCStartRead (PRIVATE)                                         *
* Purpose : Starts a RTC read                                              *
****************************************************************************
}
sub RTCStartRead(Address as byte)
   RTCStartWrite(Address)
   I2CRestart
   I2CWriteByte(RTC_DEV_ADDR + 1)
end sub
{
****************************************************************************
* Name    : RTCStop (PRIVATE)                                              *
* Purpose : Stops RTC read or write                                        *
****************************************************************************
}
sub RTCStop()
   Acknowledge(I2C_NOT_ACKNOWLEDGE)
   Stop
end sub
{
****************************************************************************
* Name    : ReadRegister (PRIVATE)                                         *
* Purpose : Read DS1307 register ($00..$3F)                                *
****************************************************************************
}         
function ReadRegister(pAddress as byte) as byte
   RTCStartRead(pAddress)
   Result = I2CReadByte(I2C_NOT_ACKNOWLEDGE)
   RTCStop
end function
{
****************************************************************************
* Name    : WriteRegister (PRIVATE)                                        *
* Purpose : Write to DS1307 register ($00..$3F)                            *
****************************************************************************
}         
sub WriteRegister(pAddress as byte, pData as byte)
   RTCStartWrite(pAddress)
   I2CWriteByte(pData)
   RTCStop
end sub
{
****************************************************************************
* Name    : ReadControl                                                    *
* Purpose : Returns the RTC control byte ($07)                             *
*         : See the control constants RTC_SQWXXXX above                    *
****************************************************************************
}         
public function ReadControl() as  byte
   Result = ReadRegister(RTC_CONTROL)
end function  
{
****************************************************************************
* Name    : WriteControl                                                   *
* Purpose : Writes the RTC Control byte ($07)                              *
*         : See the control constants RTC_SQWXXXX above                    *
****************************************************************************
}         
public sub WriteControl(pData as byte)
   WriteRegister(RTC_CONTROL, pData)
end sub
{
****************************************************************************
* Name    : WriteByte                                                      *
* Purpose : Writes a byte to NV Ram. The RAM is physically located at      *
*         : $08..$3F - this routine uses address $00..$37 (56 bytes)       *
****************************************************************************
}         
public sub WriteByte(pAddress as byte, pData as byte)
   if pAddress < RTC_NVRAM_MAX then
      WriteRegister(pAddress + RTC_NVRAM, pData)
   endif
end sub
{
****************************************************************************
* Name    : ReadByte                                                       *
* Purpose : Reads a byte from NV Ram. The RAM is physically located at     *
*         : $08..$3F - this routine uses address $00..$37 (56 bytes)       *
****************************************************************************
}         
public function ReadByte(pAddress as byte) as byte
   Result = ReadRegister(pAddress + RTC_NVRAM)
end function 
{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Returns Time in the referenced variable                        *
****************************************************************************
}         
sub ReadItem(byref pTime as TTime)
   RTCStartRead(RTC_TIME)
   Time.Second  = BCDToDec(I2CReadByte(I2C_ACKNOWLEDGE))
   Time.Minute  = BCDToDec(I2CReadByte(I2C_ACKNOWLEDGE))
   Time.Hour  = I2CReadByte(I2C_NOT_ACKNOWLEDGE)
   RTCStop
   Time.Mode.Is12Hour = Time.Hour.Booleans(6)
   if Time.Mode.Is12Hour then
      Time.Mode.PM = Time.Hour.Booleans(5)
      Time.Hour = Time.Hour and $1F
   endif   
   Time.Hour = BCDToDec(Time.Hour)
   pTime = Time
end sub
{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Returns Date in the referenced variable                        *
****************************************************************************
}
sub ReadItem(byref pDate as TDate)
   RTCStartRead(RTC_DATE)
   Date.Day   = BCDToDec(I2CReadByte(I2C_ACKNOWLEDGE))
   Date.Month = BCDToDec(I2CReadByte(I2C_ACKNOWLEDGE))
   Date.Year  = BCDToDec(I2CReadByte(I2C_NOT_ACKNOWLEDGE))
   RTCStop

   // day of week...
   RTCStartRead(RTC_WDAY)
   Date.DayOfWeek = BCDToDec(I2CReadByte(I2C_NOT_ACKNOWLEDGE))
   RTCStop 
   pDate = Date  
end sub
{
****************************************************************************
* Name    : Read                                                           *
* Purpose : Returns Time or Date in the referenced variable                *
****************************************************************************
}         
public compound sub Read(ReadItem)
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Sets the Time in BCD format                                    *
****************************************************************************
}         
sub WriteItem(pTime as TTime)
   Time = pTime
   pTime.Hour = DecToBCD(pTime.Hour) 
   if pTime.Mode.Is12Hour then
      pTime.Hour.Booleans(5) = pTime.Mode.PM
      pTime.Hour.Booleans(6) = pTime.Mode.Is12Hour
   endif
   RTCStartWrite(RTC_TIME)
   I2CWriteByte(DecToBCD(pTime.Second))
   I2CWriteByte(DecToBCD(pTime.Minute))
   I2CWriteByte(pTime.Hour)
   RTCStop
end sub   
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Sets the Date in BCD format                                    *
****************************************************************************
}         
sub WriteItem(pDate as TDate)
   Date = pDate
   RTCStartWrite(RTC_DATE)
   I2CWriteByte(DecToBCD(pDate.Day))
   I2CWriteByte(DecToBCD(pDate.Month))
   I2CWriteByte(DecToBCD(pDate.Year))
   RTCStop

   // day of week...
   RTCStartWrite(RTC_WDAY)
   I2CWriteByte(DecToBCD(pDate.DayOfWeek))
   RTCStop   
end sub   
{
****************************************************************************
* Name    : Write                                                          *
* Purpose : Sets the Time or Date                                          *
****************************************************************************
}         
public compound sub Write(WriteItem)
{
****************************************************************************
* Name    : Enabled                                                        *
* Purpose : Returns true if the RTC has been set up and is running         *
****************************************************************************
}         
public function Enabled() as boolean
   Result = (ReadRegister(RTC_TIME) and $80) = 0  
end function
{
****************************************************************************
* Name    : Initialize (PRIVATE)                                           *
* Purpose : Initializes the module                                         *
****************************************************************************
}         
sub Initialize()
   Date.Day = 1        // 1st
   Date.Month = 1      // January
   Date.Year = 0       // 2000
   Date.DayOfWeek = 6  // Saturday
   Time.Hour = 0       // 12 midnight
   Time.Minute = 0
   Time.Second = 0
   clear(Time.Mode)    // 24 hour clock
   I2CInitialize
end sub

// initialize the module...
Initialize
Retrieved from https://www.sfcompiler.co.uk/wiki/pmwiki.php?n=SwordfishUser.DS1307
Page last modified on April 19, 2007, at 07:39 PM