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