DS1307

SwordfishUser.DS1307 History

Hide minor edits - Show changes to output

April 19, 2007, at 07:39 PM by David Barker -
Changed lines 1-2 from:
This code is a modified version of a DS1307 Real Time Clock (RTC) originally coded by [[Profiles.JohnBarrat | 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.
to:
This code is a modified version of a DS1307 Real Time Clock (RTC) module originally coded by [[Profiles.JohnBarrat | 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.
April 19, 2007, at 07:38 PM by David Barker -
Changed lines 1-4 from:
This code is taken from a group of modules supplied by John Barrat. Before posting the whole set of modules, there are a couple of things I need to speak with John about - in the meantime, here is a modified DS1307 module. I've also supplied a simple test program which I've tested using software I2C. Hopefully we can get the whole set of modules up soon...

[[Profiles.DavidBarker | David Barker]]

to:
This code is a modified version of a DS1307 Real Time Clock (RTC) originally coded by [[Profiles.JohnBarrat | 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.

Changed lines 7-8 from:
// use software I2C for DS1307 ...
to:
// these options are the DS1307 connection - use software I2C...
#option DS1307_SI2C = true
Changed lines 11-12 from:
#option DS1307_SI2C = true
to:

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

Changed lines 18-19 from:
include "USART.bas"
to:
include "LCD.bas"
include "DS1307.bas"
Changed lines 21-38 from:
include "DS1307.bas"

// working variables...
dim
  Time as TTime
,
   Date as TDate,
  SecondsElapsed as byte
 
// program start...
SetBaudrate(br19200)
if not DS1307.Initialize() then
  Time.Hour = 12
  Time
.Mins = 00
 
  Time.PM = true
  Time.Secs = 0
  Date.Day = 01
  Date.Month = 01
  Date.Year = 6
to:
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
Changed lines 35-37 from:

// display the time...
SecondsElapsed = 0
to:
  
// initilaise LCD
...
SetAllDigital
Cls

// keep displaying the time and date...
Changed lines 43-46 from:
   if Time.Secs <> SecondsElapsed then
      USART.Write(DecToStr(Time.Hour,
2),":",DecToStr(Time.Mins,2),":",DecToStr(Time.Secs,2),13,10)
     SecondsElapsed = Time.Secs
  endif
to:
   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))
Added line 49:
The DS1307 module uses a file called "RTC.bas". This holds the Time and Date data structures, which looks like this
Added lines 51-76:
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...
=code [=
Changed lines 79-81 from:
include "Convert.bas"

//
choose hardware or software I2C
to:
// choose hardware or software I2C (default is hardware I2C)
Added lines 81-89:
#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...
Changed lines 96-125 from:
// alias to hardware or software I2C...
dim I2CWrite as WriteByte
dim I2CRead as ReadByte
dim I2CInitialize as Initialize

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

// default clock mode
#if IsOption (DS1307_12HR) and not (DS1307_12HR in (true, false))
  #error DS1307_12HR, "Invalid Option, DS1307_12HR must be true or false"
#endIf
#option DS1307_12HR = true


// save century value in
DS1307 NVRAM
#if IsOption (DS1307
_CENTURY_IN_NVRAM) and not (DS1307_CENTURY_IN_NVRAM in (true, false))
  #error DS1307_CENTURY_IN_NVRAM, "Invalid Option, DS1307_CENTURY_IN_NVRAM must be true or false"
#endIf
#option DS1307
_CENTURY_IN_NVRAM = true

public const
  RTC_DEV_ADDR    = $D0,  // Device Address
 
  RTC_TIME        = $0 // NVRAM Start Address for Time
 
RTC_WDAY        = $3,    // Week day number
  RTC_DATE        = $4,   // NVRAM Start Address for Date
  RTC_CONTROL     = $7,    // NVRAM Address for Control Byte
  RTC_NVRAM
       = $8,    // NVRAM Start of NV RAM
  RTC_NVRAM_TOP  = $37,  // NVRAM Address Top
to:
// 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
 
Changed lines 124-141 from:

// decimal values of Time - must always be presented in 24 hour format
public structure TTime
  Secs  as byte       // Seconds (0 to 59)
  Mins  as byte        // Minutes (0 to 59)
  Hour  as byte        // Hours  (0 to 23)
  PM
    as boolean    // In 12HR mode holds the PM indicator
end structure

// decimal values of Date
public structure TDate
  Day  as byte        // Date  i.e. 0 to 31
  Month as byte        // Month e.g. 12 (December)
  Year  as word        // Year  e.g. 2006
end structure
 
// private vars, subs and functions...
dim FCentury as word
to:
  
// public variables...
public dim
  Time as TTime,   
  Date as TDate
{
****************************************************************************
* Name
    : RTCStartWrite (PRIVATE)                                    *
* Purpose : Starts a RTC write
                                          *
****************************************************************************
}
Changed lines 136-138 from:
   Start
  I2CWrite(RTC_DEV_ADDR)
  I2CWrite(Address)       
to:
   I2CStart
  I2CWriteByte(RTC_DEV_ADDR)
  I2CWriteByte(Address)       
Changed lines 140-145 from:
to:
{
****************************************************************************
* Name    : RTCStartRead (PRIVATE)                                        *
* Purpose : Starts a RTC read                                              *
****************************************************************************
}
Changed lines 148-149 from:
   Restart
  I2CWrite(RTC_DEV_ADDR + 1)
to:
   I2CRestart
  I2CWriteByte(RTC_DEV_ADDR + 1)
Deleted lines 150-154:

sub RTCStop()
  Acknowledge(I2C_NOT_ACKNOWLEDGE)
  Stop
end sub
Changed lines 153-154 from:
* Name    : ReadByte/WriteByte                                            *
* Purpose : These functions provide direct access to the DS1307 Registers  *
to:
* Name    : RTCStop (PRIVATE)                                              *
* Purpose : Stops RTC read or write                                        *
Added lines 156-165:
}
sub RTCStop()
  Acknowledge(I2C_NOT_ACKNOWLEDGE)
  Stop
end sub
{
****************************************************************************
* Name    : ReadRegister (PRIVATE)                                        *
* Purpose : Read DS1307 register ($00..$3F)                                *
****************************************************************************
Changed line 167 from:
public function ReadByte(pAddress as byte) as byte
to:
function ReadRegister(pAddress as byte) as byte
Changed line 169 from:
   Result = I2CRead(I2C_NOT_ACKNOWLEDGE)
to:
   Result = I2CReadByte(I2C_NOT_ACKNOWLEDGE)
Deleted lines 171-176:

public sub WriteByte(pAddress as byte, pData as byte)
  RTCStartWrite(pAddress)
  I2CWrite(pData)
  RTCStop
end sub
Changed lines 174-175 from:
* Name    : CheckRTC                                                       *
* Purpose : Returns true if the RTC has been set up and is running
        *
to:
* Name    : WriteRegister (PRIVATE)                                        *
* Purpose : Write to DS1307 register ($00..$3F)
                           *
Changed lines 178-180 from:
public function CheckRTC() as boolean
  Result =
(ReadByte(RTC_TIME) and $80) = 0 
end function
to:
sub WriteRegister(pAddress as byte, pData as byte)
   RTCStartWrite(pAddress)
   I2CWriteByte(pData)
 
  RTCStop
end sub
Changed lines 185-186 from:
* Name    : WriteNVRam                                                     *
* Purpose : Writes a byte in the NV Ram at the location defined in Address *
to:
* Name    : ReadControl                                                    *
* Purpose : Returns the RTC control byte ($07)                            *
*        : See the control constants RTC_SQWXXXX above                 
*
Changed lines 190-192 from:
public sub WriteNVRam(pAddress as byte, pData as byte)
   WriteByte(pAddress + RTC_NVRAM, pData)
end sub
to:
public function ReadControl() as  byte
   Result = ReadRegister(RTC_CONTROL)
end function 
Changed lines 195-196 from:
* Name    : ReadNVRam                                                      *
* Purpose : Reads a
byte from the NV Ram at the location defined in Address*
to:
* Name    : WriteControl                                                  *
* Purpose : Writes the RTC Control
byte ($07)                              *
*        : See the control constants RTC_SQWXXXX above                   
*
Changed lines 200-202 from:
public function ReadNVRam(pAddress as byte = 0) as byte
  Result = ReadByte(pAddress + RTC_NVRAM)
end function
to:
public sub WriteControl(pData as byte)
   WriteRegister(RTC_CONTROL, pData)
end sub
Changed lines 205-207 from:
* Name    : SetCentury(pYear As Word) As Boolean PRIVATE                  *
* Purpose : Extracts the century from date and updates Century variable if *
*
          if changed saving in NVRAM is option set                       *
to:
* 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)
      *
Deleted lines 208-224:
}
function SetCentury(pYear as word) as boolean
  dim c as word
  c = BCDToDec(DecToBCD(pYear) and $FF00) // Get century
  Result = c <> FCentury // Set Result if different from current century
  FCentury = c          // Update Century
  #if DS1307_CENTURY_IN_NVRAM
      if Result then
        WriteNVRam(RTC_NVRAM_TOP, FCentury / 100) // Save it if enabled
      endif
  #endIf 
end function
{
****************************************************************************
* Name    : Read (OVERLOADED)                                              *
* Purpose : Returns Time, Date or Day in the referenced variable          *
****************************************************************************
Changed lines 210-220 from:
sub ReadItem(byref pTime as TTime)
  RTCStartRead(RTC_TIME
)
  pTime.Secs  = BCDToDec(I2CRead(I2C_ACKNOWLEDGE))
 
  pTime.Mins  = BCDToDec(I2CRead(I2C_ACKNOWLEDGE))
  pTime.Hour  = BCDToDec(I2CRead(I2C_NOT_ACKNOWLEDGE))
  #if DS1307_12HR
  pTime.PM = (pTime.Hour and $20) = 1
  #else
  pTime.PM = false
  #endif
  RTCStop
to:
public sub WriteByte(pAddress as byte, pData as byte)
  if pAddress < RTC_NVRAM_MAX then
     WriteRegister(pAddress + RTC_NVRAM, pData)
  endif
Deleted lines 214-227:

sub ReadItem(byref pDate as TDate)
  RTCStartRead(RTC_DATE)
  pDate.Day  = BCDToDec(I2CRead(I2C_ACKNOWLEDGE))
  pDate.Month = BCDToDec(I2CRead(I2C_ACKNOWLEDGE))
  pDate.Year  = FCentury + BCDToDec(I2CRead(I2C_NOT_ACKNOWLEDGE))
  RTCStop
end sub
 
sub ReadItem(byref pWDay as byte)
  RTCStartRead(RTC_WDAY)
  pWDay = I2CRead(I2C_NOT_ACKNOWLEDGE)
  RTCStop
end sub
Changed lines 217-218 from:
* Name    : Read                                                           *
* Purpose : Returns Time, Date or Day in the referenced variable
          *
to:
* 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)
      *
Changed lines 222-224 from:
public compound sub Read(ReadItem)
to:
public function ReadByte(pAddress as byte) as byte
  Result = ReadRegister(pAddress + RTC_NVRAM)
end function
Changed lines 227-228 from:
* Name    : WriteItem (OVERLOADED)                                        *
* Purpose : Sets the
Time, Date or Day in BCD format                      *
to:
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Returns
Time in the referenced variable                       *
Changed lines 231-235 from:
sub WriteItem(pTime as TTime)
  RTCStartWrite(RTC_TIME)
  I2CWrite(DecToBCD(pTime.Secs))
  I2CWrite(DecToBCD(pTime.Mins))
  I2CWrite(DecToBCD(pTime.Hour))
to:
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
)
Changed lines 237-251 from:
end sub 

sub WriteItem
(pDate as TDate)
  SetCentury(pDate
.Year)                 // Update the century if necessary
  RTCStartWrite(RTC_DATE)
  I2CWrite(DecToBCD(pDate.Day))
   I2CWrite(DecToBCD(pDate.Month))
  I2CWrite(DecToBCD(pDate.Year - FCentury)) // remove the century component
  RTCStop
end sub 
 
sub WriteItem(pWDay as byte)
  RTCStartWrite(RTC_WDAY)
  I2CWrite(pWDay)
  RTCStop
to:
   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
Changed lines 247-248 from:
* Name    : Write                                                         *
* Purpose : Sets the Time, Date or Day in BCD format
                      *
to:
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Returns Date in the referenced variable
                        *
Changed lines 250-251 from:
}       
public compound sub Write(WriteItem)
to:
}
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
Changed lines 266-273 from:
* Name    : Initialize (pCentury As Byte) As Boolean                      *
* Purpose : Initializes the I2C bus
                                       *
*          If Clock previously set up and Save Century in NVRAM is enabled*
*          Gets the Century from NVRAM or writes new century into NVRam  *
*          If Clock set and Save Century in NVRAM is not enabled          *
*          pCentury will be used to set the century. If it is not passed  *
*          or set to zero or the clock had not previously been set up    *
*          the function will return false               
                *
to:
* Name    : Read                                                          *
* Purpose : Returns Time or Date in the referenced variable
                *
Changed lines 270-285 from:
public function Initialize(pCentury as byte = 00) as boolean
  I2CInitialize
  Result = CheckRTC
  if Result then
      #if DS1307_CENTURY_IN_NVRAM
        pCentury = ReadNVRam(RTC_NVRAM_TOP)
      #else
        if pCentury > 0 then
            WriteNVRam(RTC_NVRAM_TOP, pCentury)
        else
            Result = False
        endif
      #endIf
      FCentury = pCentury * 100
  endif
end function
to:
public compound sub Read(ReadItem)
Changed lines 273-274 from:
* Name    : Read Control Byte                                             *
* Purpose : Returns the RTC control byte
                                  *
to:
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Sets the Time in BCD format
                                  *
Changed lines 277-279 from:
public function ReadControl() as  byte
   Result = ReadByte(RTC_CONTROL)
end function
 
to:
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
 
Changed lines 292-294 from:
* Name    : Write Control Byte                                            *
* Purpose : Writes the RTC Control byte
                                    *
*          OR the control Constants RTC_SQWXXXX to get the desired setting
*
to:
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Sets the Date in BCD format 
                                  *
Changed lines 296-297 from:
public sub WriteControl(pData as byte = 0)
  WriteByte(RTC_CONTROL, pData)
to:
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
Added lines 342-344:

// initialize the module...
Initialize