IntRTCC

PIC18 RTCC Module

This module allows you to use the on-board internal RTCC of many of the newer PIC18F devices.

From the datasheet:

The key features of the Real-Time Clock and Calendar (RTCC) module are:

  • Time: hours, minutes and seconds
  • 24-hour format (military time)
  • Calendar: weekday, date, month and year
  • Alarm configurable
  • Year range: 2000 to 2099
  • Leap year correction
  • BCD format for compact firmware
  • Optimized for low-power operation
  • User calibration with auto-adjust
  • Calibration range: ?2.64 seconds error per month
  • Requirements: external 32.768 kHz clock crystal
  • Alarm pulse or seconds clock output on RTCC pin

The RTCC module is intended for applications, where accurate time must be maintained for an extended period with minimum to no intervention from the CPU. The module is optimized for low-power usage in order to provide extended battery life while keeping track of time. The module is a 100-year clock and calendar with automatic leap year detection. The range of the clock is from 00:00:00 (midnight) on January 1, 2000 to 23:59:59 on December 31, 2099. Hours are measured in 24-hour (military time) format. The clock provides a granularity of one second with half-second visibility to the user.

The main limitation of the internal RTCC over an external solution is there is no independent battery backup for the module (Hint! hint! Microchip. A BATVCC input would be useful!) When the PIC power goes, the RTCC stops and loses its time. The module is unaffected by all other reset conditions however.

The module can be configured to run off an external 32.768 kHz crystal on the Timer1 input (SOSC) or from the internal RC oscillator (if present).

Usage

Structures

These two structures are provided to simplify access to the various registers.

TTime

	Second as byte
	Minute as byte
	Hour as byte

TDate

	Day as byte
	Month as byte
	Year as byte
	DayOfWeek as byte

Subroutines

The following subroutines are provided to control the module.

sub RTCEnable(pState as boolean)

	pState - State. Can be TRUE (run RTCC) or FALSE (stop RTCC).

Starts or Stops the RTCC module running (if an appropriate clock is present).

sub AlarmEnable(pState as boolean)

	pState - State. Can be TRUE (Alarm Enabled) or FALSE (Alarm Disabled).

Enables or Disables the Alarm function of the module.

compound sub Read(ReadItem)

	ReadItem - Item to Read.

Reads realtime clock registers. Readitem can be a TTime Structure or TDate Structure, in which the current values are updated.

compound sub Write(ReadItem)

	WriteItem - Item to Write.

Writes realtime clock registers. Writeitem can be a TTime Structure or TDate Structure, from which the updated values are written.

compound sub GetAlarm(ReadItem)

	ReadItem - Item to Read.

Reads Alarm value registers. Readitem can be a TTime Structure or TDate Structure, in which the current values are updated.

compound sub Write(ReadItem)

	WriteItem - Item to Write.

Writes Alarm value registers. Writeitem can be a TTime Structure or TDate Structure, from which the updated values are written.

sub SetAlarmMode(pMask As Byte, pChime As Boolean = false, pRepeat As Byte = $00)

	pMask - Sets the Alarm trigger mask. Can be:

		EveryHalfSec
		EverySecond
		Every10Secs
		EveryMinute
		Every10Mins
		EveryHour
		EveryDay
		EveryWeek
		EveryMonth
		EveryYear

	pChime - Sets whether the Alarm should repeat indefinitely, ignoring the pRepeat value.
	pRepeat - Sets a limited number of times the Alarm should repeat (up to 255).

Configures the Alarm settings.

sub OutputEnable(pState As Boolean, pMode As Byte = OUTAlarm)

	pState - State. Can be TRUE (OE pin is enabled) or FALSE (OE Pin is disabled).
	pMode - Output mode. Can be:
		OUTClock - Source clock (INTRC or EXT32).
		OUTSecond - Toggles at 1 Hz (as per RTCC).
		OUTAlarm - Toggles on Alarm event.

Sets whether the RTCC Output PIN is enabled, and if so, which mode the Pin operates in.

sub Initialize() Initializes the module to a default time and starts the module running.

Sample code

The sample code presented demonstrates most of the basic functionality of the module. It has been tested on a 18F27J53 device in both External and Internal Oscillator modes. No external hardware besides power (3v3) and a USB connection are required.

Device = 18F27J53
Clock = 48

Public Config
   OSC = INTOSCPLLO,                  ' internal osc 8MHz
   PLLDIV = 2,                        ' usb 48MHz
   CPUDIV = OSC1,                     ' 48MHz cpu clock
   FCMEN = OFF,
   IESO = OFF,
   WDTEN = OFF,
   WDTPS = 2048,
   STVREN = ON,
   XINST = OFF
   'DEBUG = OFF

'#option OSCSOURCE = EXT32		// set to EXT32 for external 32.768 kHz Crystal on Timer1
#option OSCSOURCE = INTRC		// set to INTRC for internal 32.768 kHz Oscillator

// Enable this option to use with the Microchip USB HID bootloader
'#option org_reset = $1000

Include "system.bas"
Include "IntRTCC.bas" 			// Needs to be near top as it has a config line?
Include "usbcdc.bas"
Include "convert.bas"
Include "string.bas"

Dim Timer As TTime
Dim Time As TTime
Dim Date As TDate
Dim ResponseString As String
Dim OutputMode As Byte

Sub MenuDisplay()
	CDC.Write("D: Set Date", 13, 10)
	CDC.Write("T: Set Time", 13, 10)
	CDC.Write("I: Initalise RTCC", 13, 10)
	CDC.Write("P: Set Output pin mode", 13, 10)
	CDC.Write("A: Set One-off Alarm Time", 13, 10)
	CDC.Write("M: Set Minute Chime",13, 10)
	CDC.Write("S: Stop Alarm", 13, 10)
End Sub

Sub Menu(pMenuOption As String)

	If pMenuOption <> " " Then
		CDC.Write(">: Option: " + pMenuOption, 13, 10)
	EndIf  

	Select pMenuOption
		Case " "   // Menu
			MenuDisplay()
		Case "D"   
	    	CDC.Write("Set Day (1-31): ")				// Get Day
			CDC.Read(ResponseString)
			Date.Day = StrToDec(ResponseString)			// Put it into the Date Structure
			CDC.Write(DecToStr(Date.Day), 13, 10)

			CDC.Write("Set Month (1-12): ")				// Get Month
			CDC.Read(ResponseString)
			Date.Month = StrToDec(ResponseString)		// Put it into the Date Structure
			CDC.Write(DecToStr(Date.Month), 13, 10)

			CDC.Write("Set Year (0-99): ") 				// Get year
			CDC.Read(ResponseString)
			Date.Year = StrToDec(ResponseString)		// Put it into the Date Structure
			CDC.Write(DecToStr(Date.Year), 13, 10)

			CDC.Write("Set Day of week (0-Sun, 1-Mon, 2-Tues, 3-Weds, 4-Thurs, 5-Fri, 6-Sat): ")
			CDC.Read(ResponseString)
			Date.DayOfWeek = StrToDec(ResponseString)	// Put it into the Date Structure
			CDC.Write(DecToStr(Date.DayOfWeek), 13, 10)

			IntRTCC.Write(Date)							// Set the Date parameters using the Date Structure

		Case "T"
            CDC.Write("Set 24 Hour (0-23): ")			// Get Hours
			CDC.Read(ResponseString)
			Time.Hour = StrToDec(ResponseString)		// Put it into the Time Structure
			CDC.Write(DecToStr(Time.Hour), 13, 10)

			CDC.Write("Set Minutes (0-59): ")			// Get Hours
			CDC.Read(ResponseString)
			Time.Minute = StrToDec(ResponseString)		// Put it into the Time Structure
			CDC.Write(DecToStr(Time.Minute), 13, 10)

			CDC.Write("Set Seconds (0-59): ")			// Get Hours
			CDC.Read(ResponseString)
			Time.Second = StrToDec(ResponseString)		// Put it into the Time Structure
			CDC.Write(DecToStr(Time.Second), 13, 10)

			IntRTCC.Write(Time)							// Set the Time parameters using the Time Structure

		Case "I"
			IntRTCC.Initialize()						// Initialise to module defaults			

		Case "P"
			CDC.Write("Set Output Pin (0-Off, 1-Output Clock, 2-Output Seconds, 3-OutputAlarm): ")
			CDC.Read(ResponseString)
			Select StrToDec(ResponseString)
				Case 0
					OutputEnable(false)					// Get Hours
					CDC.Write("Output Off", 13, 10)
				Case 1
					OutputEnable(true, OUTClock)		// Output the source clock (intRC or T0)
					CDC.Write("Output Clock", 13, 10)
				Case 2
					OutputEnable(true, OUTSecond)		// Output seconds (toggle every second)
					CDC.Write("Output Seconds", 13, 10)
				Case 3
					OutputEnable(true, OUTAlarm)		// Output the Alarm
					CDC.Write("Output Alarm", 13, 10)
			End Select

		Case "A"
  			CDC.Write("Set 24 Hour (0-23): ")			// Get Hours
			CDC.Read(ResponseString)
			Time.Hour = StrToDec(ResponseString)		// Put it into the Time Structure
			CDC.Write(DecToStr(Time.Hour), 13, 10)

			CDC.Write("Set Minutes (0-59): ")			// Get Minutes
			CDC.Read(ResponseString)
			Time.Minute = StrToDec(ResponseString)		// Put it into the Time Structure
			CDC.Write(DecToStr(Time.Minute), 13, 10)

			CDC.Write("Set Seconds (0-59): ")			// Get Seconds
			CDC.Read(ResponseString)
			Time.Second = StrToDec(ResponseString)		// Put it into the Time Structure
			CDC.Write(DecToStr(Time.Second), 13, 10)

			IntRTCC.SetAlarm(Time)                      // Set the Alarm parameters using the Time Structure
			SetAlarmMode(EveryDay)						// Will trigger once at the set time of day
			OutputEnable(true, OUTAlarm)                // Set the output pin to Output the alarm signal
			AlarmEnable(true)                           // Enable the alarm

		Case "M"
			CDC.Write("Set Seconds (0-59): ")           // Get time
			CDC.Read(ResponseString)
			Time.Second = StrToDec(ResponseString)      // Put it into the Time Structure
			CDC.Write(DecToStr(Time.Second), 13, 10)

			IntRTCC.SetAlarm(Time)                      // Set the Alarm parameters using the Time Structure
			SetAlarmMode(EveryMinute, true)				// Will trigger repeatedly each minute (Pin should toggle every minute at seconds set)
			OutputEnable(true, OUTAlarm)                // Set the output pin to Output the alarm signal
			AlarmEnable(true)                           // Enable the alarm

		Case "S"
			AlarmEnable(false) 							// Disable the Alarm

	End Select
End Sub		

#if OSCSOURCE = EXT32 
	// Start up the timer1 Oscillator if using it
	T1CON.3 = 1

#endif

ReadTerminator = #13
OutputMode = OUTAlarm

Clear(Timer)
Output(PORTB.4)											// RTCC output pin

// wait for connection...
Repeat
Until Attached

IntRTCC.RTCEnable(true)									// Enable the RTCC

While true

   If DataAvailable Then								// Get responses from CDC terminal
        CDC.Read(ResponseString)
		Menu(Str.Uppercase(ResponseString))
   EndIf

   IntRTCC.Read(Time, Date)								// Read the RTCC into the Time & Date structures

   If Time <> Timer Then								// Displays updated time every second when the second field changes
		Timer = Time
		CDC.Write(DecToStr(Time.Hour, 2),":",DecToStr(Time.Minute,2),":",DecToStr(Time.Second,2), " ")
		CDC.Write(DaysOfWeek(Date.DayOfWeek), " ", DecToStr(Date.Day,2),"/",DecToStr(Date.Month,2),"/",DecToStr(Date.Year,2), 13, 10)
	EndIf

Wend

IntRTCC Module

{
*****************************************************************************
*  Name    : IntRTCC.BAS                                                    *
*  Author  : Nathan Herbert                                                 *
*  Notice  : Copyright (c) 2012 							                *
*          : All Rights Reserved                                            *
*  Date    : 27/09/2012                                                     *
*  Version : 1.0                                                            *
*  Notes   :                                                                *
*          :                                                                *
*****************************************************************************
}
Module IntRTCC

	#option OSCSOURCE = INTRC

	#if IsOption(OSCSOURCE) And Not (OSCSOURCE in (INTRC, EXT32))
   		#error OSCSOURCE, "Invalid option. OSCSOURCE type not recognized. INTRC or EXT32 Only."
	#endif

	#if OSCSOURCE = INTRC 
		Config RTCOSC = INTOSCREF
		#warning "Internal RC Accuracy is poor, even when calibrated."
	#else
	 	Config RTCOSC =  T1OSCREF
	#endif

	Include "convert.bas"

	// 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)
	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 (0..6)
	End Structure 	

	Dim
		RTCEn			As RTCCFG.Booleans(7),
		RTCWren			As RTCCFG.Booleans(5),
		RTCSync			As RTCCFG.Booleans(4),
		RTCOe			As RTCCFG.Booleans(2),
		RTCCalib		As RTCCAL,
		RTCPinConfig 	As PADCFG1,
		RTCConfig 		As RTCCFG,
		RTCValLow		As RTCVALL,
		RTCValHigh		As RTCVALH,
		MemControl		As EECON2,
		AlarmEn			As ALRMCFG.booleans(7),
		AlarmChime		As ALRMCFG.booleans(6),
		AlarmConfig		As ALRMCFG,
		AlarmRepeat		As ALRMRPT,
		AlarmValLow		As ALRMVALL,
		AlarmValHigh	As ALRMVALH

	Const 
		// RTCPTR and ALMPTR pointer values
		// RTCVAL<15:8>
		VALYear		= %00100011,
		VALDay		= %00100010,
		VALHours	= %00100001,
		VALSeconds	= %00100000,
		// RTCVAL<7:0>
		VALMonth	= %00100010,
		VALWeekday	= %00100001,
		VALMinutes	= %00100000

Public Const
   		DaysOfWeek(7) As String = ("Sun","Mon","Tue","Wed","Thu","Fri","Sat"),

   		// Output Configuration
		OUTClock	= %00000100,
		OUTSecond	= %00000010,
		OUTAlarm	= %00000000,

		// Alarm settings					DoW		Month	Day		Hours	Minutes	Seconds	 (X = don't care)
		EveryHalfSec	= %00000000,	//	X		X X		X X		X X		X X		X X		
		EverySecond		= %00000100,	//	X		X X		X X		X X 	X X		X S
		Every10Secs		= %00001000,	//	X		X X 	X X 	X X		X X		X S
		EveryMinute		= %00001100,	//	X		X X 	X X 	X X		X X		S S
		Every10Mins		= %00010000,	//	X		X X 	X X 	X X		X M		S S
		EveryHour		= %00010100,	//	X		X X 	X X 	X X		M M		S S
		EveryDay		= %00011000,	//	X		X X 	X X 	H H		M M		S S
		EveryWeek		= %00011100,	//	D		X X 	X X 	H H		M M		S S
		EveryMonth		= %00100000,	//	X		X X 	D D 	H H		M M		S S
		EveryYear		= %00100100		//	X		M M 	D D 	H H		M M		S S

{
****************************************************************************
* Name    : RTCWriteEnable (PRIVATE)                                   	   *
* Purpose : Enables or Disables writes to RTCC registers                   *
****************************************************************************
}
Sub RTCWriteEnable(pState As Boolean)
	// The lock sequence seems to need to be ASM in order to 
	// ensure the commands occur in the time required.
	// An interrupt occuring during the sequence would
	// disrupt it. So rather than disable the interrupts,
	// I prefer to just repeat the sequence until occurs
	// uninterrupted.

	Repeat
		If pState = true Then      ' Lock sequence 
			Asm
				movlb	0x0F          		
				movlw	0x55                
				movwf	EECON2
				movlw	0xAA
				movwf	EECON2
				bsf		RTCCFG,5
			End Asm	
    	Else     ' Unlock sequence
    		Asm
				movlb	0x0F          		
				movlw	0x55                
				movwf	EECON2
				movlw	0xAA
				movwf	EECON2
				bcf		RTCCFG,5
			End Asm
		EndIf
	Until RTCWren = pState
End Sub

{
****************************************************************************
* Name    : SetConfig 		                                         	   *
* Purpose : 											                   *
****************************************************************************
}
Sub SetRTCPointer(pState As Byte)

	RTCConfig = RTCConfig And %11111100			// Clear the PTR bits
	RTCConfig = RTCConfig Or pState				// Set PTR bits to required

End Sub

{
****************************************************************************
* Name    : SetConfig 		                                         	   *
* Purpose : 											                   *
****************************************************************************
}
Sub SetAlarmPointer(pState As Byte)

	AlarmConfig = AlarmConfig And %11111100		// Clear the PTR bits		
	AlarmConfig = AlarmConfig Or pState			// Set PTR bits to required

End Sub

{
****************************************************************************
* Name    : RTCEnable 		                                         	   *
* Purpose : Enables or Disables the RTCC 				                   *
****************************************************************************
}
Public Sub RTCEnable(pState As Boolean)
	RTCWriteEnable(true)
	RTCEn = pState
	RTCWriteEnable(false)
End Sub

{
****************************************************************************
* Name    : AlarmEnable 	                                         	   *
* Purpose : Enables or Disables the Alarm 				                   *
****************************************************************************
}
Public Sub AlarmEnable(pState As Boolean)
	AlarmEn = pState
End Sub

{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Returns Time in the referenced variable                        *
****************************************************************************
}         
Sub ReadItem(ByRef pTime As TTime)
Dim 
	dummy As Byte,
	Temp As TTime,
	Result As Boolean 

	// Read at least twice as per datasheet to ensure we did not read during a rollover
	result = false
	Repeat 
		SetRTCPointer(VALHours)					// Set pointer to start position

		Temp.Hour = BCDToDec(RTCValLow)			// Read Hours
		dummy = RTCValHigh						// Read Dummy to decrement pointer
		Temp.Second = BCDToDec(RTCValLow)		// Read Seconds
		Temp.Minute = BCDToDec(RTCValHigh)		// Read Minutes

		SetRTCPointer(VALHours)					// Set pointer to start position

		pTime.Hour = BCDToDec(RTCValLow)		// Read Hours
		dummy = RTCValHigh						// Read Dummy to decrement pointer
		pTime.Second = BCDToDec(RTCValLow)		// Read Seconds
		pTime.Minute = BCDToDec(RTCValHigh)		// Read Minutes

	 	// Do both reads match?
	 	If Temp = pTime Then
	 		result = true
 		EndIf

	 Until result = true

End Sub
{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Returns Date in the referenced variable                        *
****************************************************************************
}
Sub ReadItem(ByRef pDate As TDate)
Dim 
	dummy As Byte,
	Temp As TDate,
	Result As Boolean

	// Read twice as per datasheet to ensure we did not read during a rollover
	result = false
	Repeat 
		SetRTCPointer(VALYear)					// Set pointer to start position

		Temp.Year = BCDToDec(RTCValLow)			// Read Year
		dummy = RTCValHigh						// Read Dummy to decrement pointer
		Temp.Day = BCDToDec(RTCValLow)			// Read Day
		Temp.Month = BCDToDec(RTCValHigh)		// Read month and decrement pointer
		Temp.DayOfWeek = BCDToDec(RTCValHigh)	// Read Day of Week

		SetRTCPointer(VALYear)					// Set pointer to start position

		pDate.Year = BCDToDec(RTCValLow)		// Read Year
		dummy = RTCValHigh						// Read Dummy to decrement pointer
		pDate.Day = BCDToDec(RTCValLow)			// Read Day
		pDate.Month = BCDToDec(RTCValHigh)		// Read month and decrement pointer
		pDate.DayOfWeek = BCDToDec(RTCValHigh)	// Read Day of Week

	 	// Do both reads match?
	 	If Temp = pDate Then
	 		result = true
 		EndIf

	 Until result = true

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)
Dim RTCCurrent As Boolean

	RTCCurrent = RTCEn	                        // Save current state
	RTCEnable(false)							// Ensure the RTCC is not running							
	RTCWriteEnable(true) 						// Enable writes
	SetRTCPointer(VALHours)						// Set pointer to start position
	RTCValLow = DecToBCD(pTime.Hour)            // Get Hours
	SetRTCPointer(VALMinutes)					// Set pointer to Minutes / Seconds
	RTCValLow = DecToBCD(pTime.Second)          // Get Seconds
	RTCValHigh = DecToBCD(pTime.Minute)			// Get Minutes
	RTCEnable(RTCCurrent)						// Reset current state (Will disable writes)							

End Sub   
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Sets the Date in BCD format                                    *
****************************************************************************
}         
Sub WriteItem(pDate As TDate)
Dim RTCCurrent As Boolean

	RTCCurrent = RTCEn 							// Save current state
	RTCEnable(false)							// Ensure the RTCC is not running					
	RTCWriteEnable(true)   						// Enable writes
	SetRTCPointer(VALYear)						// Set pointer to start position
	RTCValLow = DecToBCD(pDate.Year) 			// Get Year
	SetRTCPointer(VALMonth)						// Set pointer to Month / Day
	RTCValLow = DecToBCD(pDate.Day)  			// Get Day
	RTCValHigh = DecToBCD(pDate.Month)   		// Get Month & decrement
	RTCValHigh = DecToBCD(pDate.DayOfWeek)   	// Get Day of week
	RTCEnable(RTCCurrent)						// Reset current state (Will disable writes)				

End Sub   
{
****************************************************************************
* Name    : Write                                                          *
* Purpose : Sets the Time or Date                                          *
****************************************************************************
}         
Public Compound Sub Write(WriteItem)

{
****************************************************************************
* Name    : ReadAlarm (OVERLOAD)                                           *
* Purpose : Returns Alarm Time in the referenced variable                  *
****************************************************************************
}         
Sub ReadAlarm(ByRef pTime As TTime)
Dim dummy As Byte

	SetAlarmPointer(VALHours)					// Set pointer to start position

	pTime.Hour = BCDToDec(AlarmValLow)			// Read Hours
	dummy = AlarmValHigh						// Read Dummy to decrement pointer
	pTime.Second = BCDToDec(AlarmValLow)		// Read Seconds
	pTime.Minute = BCDToDec(AlarmValHigh)		// Read Minutes

End Sub
{
****************************************************************************
* Name    : ReadAlarm (OVERLOAD)                                           *
* Purpose : Returns Alarm Date in the referenced variable                  *
****************************************************************************
}
Sub ReadAlarm(ByRef pDate As TDate)
Dim dummy As Byte

	SetAlarmPointer(VALYear)					// Set pointer to start position

	pDate.Year = BCDToDec(AlarmValLow)			// Read Year
	dummy = AlarmValHigh						// Read Dummy to decrement pointer
	pDate.Day = BCDToDec(AlarmValLow)			// Read Day
	pDate.Month = BCDToDec(AlarmValHigh)		// Read month and decrement pointer
	pDate.DayOfWeek = BCDToDec(AlarmValHigh)	// Read Day of Week

End Sub

{
****************************************************************************
* Name    : Read                                                           *
* Purpose : Returns Time or Date in the referenced variable                *
****************************************************************************
} 
Public Compound Sub GetAlarm(ReadAlarm)

{
****************************************************************************
* Name    : WriteAlarm (OVERLOAD)                                          *
* Purpose : Sets the Alarm Time in BCD format                              *
****************************************************************************
}         
Sub WriteAlarm(pTime As TTime)
Dim AlarmCurrent As Boolean

	AlarmCurrent = AlarmEn						// Get current state
	AlarmEnable(false)							// Ensure alarm is disabled
	RTCWriteEnable(true)  						// Enable writes                    
	SetAlarmPointer(VALHours)					// Set pointer to start position
	AlarmValLow = DecToBCD(pTime.Hour) 			// Get Hour
	SetAlarmPointer(VALMinutes)					// Set pointer to Minutes / Seconds
	AlarmValLow = DecToBCD(pTime.Second) 		// Get Seconds
	AlarmValHigh = DecToBCD(pTime.Minute) 		// Get Minutes
	RTCWriteEnable(false) 						// Disable writes
	AlarmEnable(AlarmCurrent) 					// Reset current alarm state

End Sub   
{
****************************************************************************
* Name    : WriteAlarm (OVERLOAD)                                          *
* Purpose : Sets the Alarm Date in BCD format                              *
****************************************************************************
}         
Sub WriteAlarm(pDate As TDate)
Dim AlarmCurrent As Boolean

	AlarmCurrent = AlarmEn						// Get current state
	AlarmEnable(false)     						// Ensure alarm is disabled
	RTCWriteEnable(true)    					// Enable writes
	SetAlarmPointer(VALYear)					// Set pointer to start position
	AlarmValLow = DecToBCD(pDate.Year)  		// Get Year
	SetAlarmPointer(VALMonth)					// Set pointer to Month / Day
	AlarmValLow = DecToBCD(pDate.Day)			// Get Day
	AlarmValHigh = DecToBCD(pDate.Month)		// Get Month & decrement
	AlarmValHigh = DecToBCD(pDate.DayOfWeek)	// Get Day of week
	RTCWriteEnable(false)						// Disable writes
	AlarmEnable(AlarmCurrent)					// Reset current alarm state

End Sub   
{
****************************************************************************
* Name    : SetAlarm			                                           *
* Purpose : Sets the Alarm, with its options		                       *
****************************************************************************
}          
Public Compound Sub SetAlarm(WriteAlarm)

{
****************************************************************************
* Name    : SetAlarmMode		                                           *
* Purpose : Sets the Alarm to the desired mode            		           *
****************************************************************************
}         
Public Sub SetAlarmMode(pMask As Byte, pChime As Boolean = false, pRepeat As Byte = $00)

	// Datasheet says ALRMCFG, ALRMRPT and CHIME should only be changed when RTCSync = 0
	Repeat
	Until RTCSync = false

	AlarmChime = pChime							// Chime? (Repeat the alarm forever, ignores pRepeat) 
	AlarmRepeat = pRepeat  						// Repeat a limited number of times? $00 = Alarm once.

	// Set the Alarm mask (see constants above for logic)
	AlarmConfig = AlarmConfig And %11000011		// Zero the mask bits
	AlarmConfig = AlarmConfig Or pMask 			// Set the mask bits

End Sub

{
****************************************************************************
* Name    : OutputEnable		                                           *
* Purpose : Sets the Output enable to the desired mode                     *
****************************************************************************
}         
Public Sub OutputEnable(pState As Boolean, pMode As Byte = OUTAlarm)

	// Disable Pin to prevent glitching
	RTCOe = false

	// Set desired mode
	RTCPinConfig = RTCPinConfig And %11111001
	RTCPinConfig = RTCPinConfig Or pMode	

	// Set pin state
	RTCOe = pState

End Sub

{
****************************************************************************
* Name    : Initialize 			                                           *
* Purpose : Initializes the module                                         *
****************************************************************************
}         
Public Sub Initialize()
Dim 
	pTime As TTime,
	pDate As TDate

	pDate.Day = 1        	// 1st
	pDate.Month = 1      	// January	
	pDate.Year = 12       	// 2012
	pDate.DayOfWeek = 0		// Sunday
	pTime.Hour = 0       	// 12 midnight
	pTime.Minute = 0
	pTime.Second = 0

	Write(pTime, pDate)					// Write the defaults

	RTCEnable(true)						// Enable the Module

End Sub