; ************************************************************************** ; * * ; * Real-Time Clock for the PICAXE-18X PICAXERT.BAS * ; * * ; ************************************************************************** SYMBOL VERSION_MAJOR = 1 ' 1.0 SYMBOL VERSION_MINOR = 0 ; .------------------------------------------------------------------------. ; | | ; | Version 1.0 | ; | Last Update 2004-08-26 | ; | | ; | Target PICAXE-18X | ; | Compiler Used Revolution Programming Editor 4.1.4 | ; | Memory Used Approx 1355 bytes of 2048 | ; | | ; | Author The Happy Hippy | ; | Web Site www.hippy.freeserve.co.uk/picaxert.htm | ; | Email hippy@psynet.net | ; | | ; | Copyright (C) 2004, The Happy Hippy | ; | | ; `------------------------------------------------------------------------' ; ************************************************************************** ; * * ; * Daylight Saving Time Configuration * ; * * ; ************************************************************************** ; If you don't wish Daylight Saving Time to be implemented, then set ; the DST_DISABLE definition below to $FF ... SYMBOL DST_DISABLE = $00 ' $00 = Enabled, $FF = Disabled ; One of the following Daylight Saving Time Locales must be selected ; by uncommenting its block, even if Daylight Saving Time has been ; disabled. Additional Locales may be added as required. ; .------------------------------------------------------------------------. ; | | ; | Europe / British Summer Time | ; | | ; `------------------------------------------------------------------------' SYMBOL DST_ENTER_SUNDAY = $FF ' Last Sunday SYMBOL DST_ENTER_MONTH = 2 ' March SYMBOL DST_ENTER_DOM = 30 SYMBOL DST_ENTER_TIME = 01 ' 01:00:00 SYMBOL DST_LEAVE_SUNDAY = $FF ' Last Sunday SYMBOL DST_LEAVE_MONTH = 9 ' October SYMBOL DST_LEAVE_DOM = 30 SYMBOL DST_LEAVE_TIME = 02 ' 02:00:00 ; .------------------------------------------------------------------------. ; | | ; | Australia - South Australia, Victoria, Australian Capital | ; | Territory, New South Wales, Lord Howe Island | ; | | ; `------------------------------------------------------------------------' ; SYMBOL DST_ENTER_SUNDAY = $FF ' Last Sunday ; SYMBOL DST_ENTER_MONTH = 9 ' October ; SYMBOL DST_ENTER_DOM = 30 ; SYMBOL DST_ENTER_TIME = 02 ' 02:00:00 ; SYMBOL DST_LEAVE_SUNDAY = $FF ' Last Sunday ; SYMBOL DST_LEAVE_MONTH = 2 ' March ; SYMBOL DST_LEAVE_DOM = 30 ; SYMBOL DST_LEAVE_TIME = 03 ' 03:00:00 ; .------------------------------------------------------------------------. ; | | ; | Tasmania | ; | | ; `------------------------------------------------------------------------' ; SYMBOL DST_ENTER_SUNDAY = 1 ' First Sunday ; SYMBOL DST_ENTER_MONTH = 9 ' October ; SYMBOL DST_ENTER_DOM = 1 ; SYMBOL DST_ENTER_TIME = 02 ' 02:00:00 ; SYMBOL DST_LEAVE_SUNDAY = $FF ' Last Sunday ; SYMBOL DST_LEAVE_MONTH = 2 ' March ; SYMBOL DST_LEAVE_DOM = 30 ; SYMBOL DST_LEAVE_TIME = 03 ' 03:00:00 ; .------------------------------------------------------------------------. ; | | ; | New Zealand | ; | | ; `------------------------------------------------------------------------' ; SYMBOL DST_ENTER_SUNDAY = 1 ' First Sunday ; SYMBOL DST_ENTER_MONTH = 9 ' October ; SYMBOL DST_ENTER_DOM = 1 ; SYMBOL DST_ENTER_TIME = 02 ' 02:00:00 ; SYMBOL DST_LEAVE_SUNDAY = 1 ' Third Sunday ; SYMBOL DST_LEAVE_MONTH = 2 ' March ; SYMBOL DST_LEAVE_DOM = 15 ; SYMBOL DST_LEAVE_TIME = 03 ' 03:00:00 ; .------------------------------------------------------------------------. ; | | ; | United States, Canada, Mexico and Cuba | ; | | ; `------------------------------------------------------------------------' ; SYMBOL DST_ENTER_SUNDAY = 1 ' First Sunday ; SYMBOL DST_ENTER_MONTH = 3 ' April ; SYMBOL DST_ENTER_DOM = 1 ; SYMBOL DST_ENTER_TIME = 02 ' 02:00:00 ; SYMBOL DST_LEAVE_SUNDAY = $FF ' Last Sunday ; SYMBOL DST_LEAVE_MONTH = 9 ' October ; SYMBOL DST_LEAVE_DOM = 30 ; SYMBOL DST_LEAVE_TIME = 03 ' 03:00:00 ; ************************************************************************** ; * * ; * ; * * ; ************************************************************************** ' Timer 1 Registers SYMBOL T1CON = $10 SYMBOL T1MSB = $0F SYMBOL T1LSB = $0E ' Peripheral Interrupt Register SYMBOL PIR1 = $0C ' Timer 1 Control Bit Settings SYMBOL T1RUN = 1 ' 0/1 SYMBOL T1PS = 3 ' 0..3 SYMBOL T1OSCEN = 0 ' 0/1 SYMBOL T1SYNC = 0 ' 0/1 SYMBOL T1CS = 0 ' 0/1 SYMBOL T1ON = 1 ' 0/1 ' Timer 1 Control Bits in T1CON SYMBOL T1RUN_K = T1RUN * %01000000 SYMBOL T1PS_K = T1PS * %00010000 SYMBOL T1OSCEN_K = T1OSCEN * %00001000 SYMBOL T1SYNC_K = T1SYNC * %00000100 SYMBOL T1CS_K = T1CS * %00000010 SYMBOL T1ON_K = T1ON * %00000001 ' Timer 1 Status Bits in PIR1 SYMBOL T1IF_K = %00000001 SYMBOL T1IF_K_NOT = T1IF_K ^ $FF ; ************************************************************************** ; * * ; * ; * * ; ************************************************************************** SYMBOL RX = 2 SYMBOL RX_PIN = pin2 SYMBOL RX_BAUD = N4800 SYMBOL SYNCH = 0 SYMBOL SYNCH_PIN = pin0 SYMBOL YEAR_BASE = 2000 SYMBOL ENTER_DST_DAY = $60 SYMBOL LEAVE_DST_DAY = $61 SYMBOL SAVE_MONTH = $62 SYMBOL SAVE_DAY = $63 ' Variables SYMBOL jiffy = w0 ' b1:b0 SYMBOL secs = b2 SYMBOL mins = b3 SYMBOL hour = b4 SYMBOL day = b5 SYMBOL month = b6 SYMBOL year = b7 SYMBOL dayOfWeek = b8 SYMBOL daysInMonth = b9 SYMBOL jiffyInc = w5 ' b11:b10 SYMBOL editPtr = b10 SYMBOL char = b11 SYMBOL tempWord = w6 ' b12:b11 SYMBOL temp = b12 SYMBOL leapYear = b13 SYMBOL index = b13 ; ************************************************************************** ; * * ; * ; * * ; ************************************************************************** InitialiseRtc: 'pause 5000 'for year = 0 to 5 'tempWord=YEAR_BASE+year 'sertxd(#tempWord," : ") 'for month = 0 to 11 'gosub finddaysinmonth 'day = daysinmonth-1 ' gosub finddayofweek ' lookup dayofweek,("MTWHFSU"),dayofweek ' sertxd(" ",dayofweek) 'next 'sertxd(cr,lf) 'next 'end 'year=5 ' month = 2 ' March-1 ' day = 30 ' Last day of March-1 ' GOSUB FindDayOfWeek 'sertxd(#year,"-",#month,"-",#day," ",#dayofweek,cr,lf) ' month = 9 ' March-1 ' day = 30 ' Last day of March-1 ' GOSUB FindDayOfWeek 'sertxd(#year,"-",#month,"-",#day," ",#dayofweek,cr,lf) year = 4 month = 10-1 day = 31-1 hour = 01 mins = 59 secs = 45*2 InitialiseTimer: temp = T1RUN_K | T1PS_K | T1OSCEN_K | T1SYNC_K | T1CS_K | T1ON_K POKE T1CON,temp POKE T1LSB,0 POKE T1MSB,0 PEEK PIR1,temp temp = temp & T1IF_K_NOT POKE PIR1,temp jiffyInc = 1024 FOR index = 0 TO T1PS jiffyInc = jiffyInc * 2 NEXT GOSUB FindDstDays GOSUB FindDaysInMonth ; ************************************************************************** ; * * ; * ; * * ; ************************************************************************** ReadTimer: IF SYNCH_PIN = 1 THEN NoSynchronise SynchroniseTime: mins = 0 secs = 0 jiffy = 0 POKE T1LSB,0 POKE T1MSB,0 IF mins >= 30 THEN SynchroniseForward GOTO UpdateSynchronisedClock NoSynchronise: IF RX_PIN <> 0 THEN EnterEditor PEEK PIR1,temp index = temp & T1IF_K IF index = 0 THEN ReadTimer temp = temp & T1IF_K_NOT POKE PIR1,temp jiffy = jiffy + jiffyInc IF jiffy < 15625 THEN ReadTimer jiffy = jiffy - 15625 UpdateClock: secs = secs + 1 % 120 temp = secs & 1 IF temp <> 0 THEN ReadTimer IF secs <> 0 THEN ShowtheTime mins = mins + 1 % 60 IF mins <> 0 THEN ShowTheTime SynchroniseForward: hour = hour & $1F + 1 % 24 UpdateSynchronisedClock: IF dayOfWeek <> 6 THEN NotleavingDst ' Not Sunday IF month <> DST_ENTER_MONTH THEN NotEnteringDst IF hour <> DST_ENTER_TIME THEN NotEnteringDst PEEK ENTER_DST_DAY,temp ' Is it right day ? IF temp <> day THEN ShowTheTime ' No hour = hour + 1 ' Jump forward GOTO ShowTheTime NotEnteringDst: IF month <> DST_LEAVE_MONTH THEN NotLeavingDst IF hour <> DST_LEAVE_TIME THEN NotLeavingDst PEEK LEAVE_DST_DAY,temp ' Is it right day ? IF temp <> day THEN ShowTheTime ' No hour = hour - 1 | $80 ' Jump backwards NotleavingDst: IF hour <> 0 THEN ShowTheTime day = day + 1 % daysInMonth dayOfWeek = dayOfWeek + 1 % 7 IF day <> 0 THEN ShowTheTime month = month + 1 % 12 IF month <> 0 THEN UpdateDaysInMonth year = year + 1 GOSUB FindDstDays UpdateDaysInMonth: GOSUB FindDaysInMonth ShowTheTime: GOSUB ShowTimeLongFormat IF dayOfWeek <= 4 THEN NoWeekdayAlarm PEEK $50,temp IF temp <> hour THEN NoWeekdayAlarm PEEK $51,temp IF temp <> mins THEN NoWeekdayAlarm SERTXD( " !" ) GOTO NoDailyAlarm NoWeekdayAlarm: index = dayOfWeek+1*2+$50 PEEK index,temp IF temp <> hour THEN NoDailyAlarm index = index+1 PEEK index,temp IF temp <> mins THEN NoDailyAlarm DailyAlarm: SERTXD( " *") NoDailyAlarm: SERTXD( CR,LF ) GOTO ReadTimer ; ************************************************************************** ; * * ; * Interactive Editor for setting the date, time and alarms * ; * * ; ************************************************************************** EnterEditor: hour = hour & $1F ' Clear BST flag editPtr = 0 SetDowAndShowEditTime: GOSUB FindDayOfWeek GOSUB FindDaysInMonth ShowEditTime: SERTXD( CR,LF,"@" ) GOSUB ShowTimeShortFormat GOSUB ShowAlarmTimes SERTXD( CR,LF ) ' 123456789-123456789-123456789-123456789-123456789-123456789-1234567 ' 1 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 ' YYYY-MM-DD HH:MM:SS Xh:Xm Mh:Mm Th:Tm Wh:Wm Hh:Hm Fh:Fm Sh:Sm Uh:Um ' 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ' Y M D H M S Xh Xm Mh Mm Th Tm Wh Wm Hh Hm Fh Fm Sh Sm Uh Um LOOKUP editPtr,(1,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60,63,66),temp FOR index = 1 TO temp SERTXD( " " ) NEXT IF editPtr <> 0 THEN StartEditing SERTXD("YY") StartEditing: LOOKUP editPtr,("YMDHNSXXMMTTWWHHFFSSUU"),char SERTXD(char) LOOKUP editPtr,("YMDHNShmhmhmhmhmhmhmhm"),char SERTXD(char,CR,LF,"=") GetNextChar: SERIN RX,RX_BAUD,char SERTXD( char ) IF char = CR OR char = "S" THEN FinishedEditing IF char = "?" THEN ShowEditTime IF char = "#" THEN ZeroField IF char = "X" THEN DisableAlarm temp = 1 IF char = ">" OR char="," THEN SelectField IF char = "+" THEN UpdateField temp = -1 IF char = "<" THEN SelectField IF char = "-" THEN UpdateField temp = 0 IF char >= "0" AND char <= "9" THEN UpdateField GOTO GetNextChar SelectField: editPtr = EditPtr + temp IF editPtr > 21 THEN EnterEditor GOTO ShowEditTime UpdateField: IF editPtr > 5 THEN PeekField secs = secs / 2 LOOKUP editPtr,(year,month,day,hour,mins,secs), index secs = secs * 2 GOTO UpdateFieldVar PeekField: index = editPtr-6+$50 PEEK index,index UpdateFieldVar: index = index + temp IF temp <> 0 THEN UpdatedFieldVar index = index * 10 + char - "0" UpdatedFieldVar: LOOKUP editPtr,(0,12,daysInMonth,24,60,60,24,60,24,60,24,60,24,60,24,60,24,60,24,60,24,60),temp IF temp = 0 OR index < temp THEN SetFieldVar IF index = temp THEN ZeroField index = temp - 1 GOTO SetFieldvar ZeroField: index = 0 SetFieldVar: IF editPtr > 5 THEN PokeFieldVar BRANCH editPtr,(SetYear,SetMonth,SetDay,SetHour,SetMins,SetSecs) SetYear: year = index : GOTO SetDowAndShowEditTime SetMonth: month = index : GOTO SetDowAndShowEditTime SetDay: day = index : GOTO SetDowAndShowEditTime SetHour: hour = index : GOTO ShowEditTime SetMins: mins = index : GOTO ShowEditTime SetSecs: secs = index*2 : GOTO ShowEditTime PokeFieldVar: temp = editPtr-6+$50 POKE temp,index GOTO ShowEditTime DisableAlarm: IF editPtr <= 5 THEN getNextChar temp = editPtr-6 & $FE + $50 POKE temp,99 GOTO ShowEditTime FinishedEditing: SERTXD( LF ) IF char = "S" THEN SynchroniseTime GOSUB ShowTimeLongFormat SERTXD( CR,LF ) GOTO InitialiseTimer ; ************************************************************************** ; * * ; * Display the current date and time, in long and short (ISO) formats * ; * * ; ************************************************************************** ; Format = ddd, ddxx mmm yyyy hh:mm xm : yyyy-mm-dd hh:mm:ss ; ; Example = Wed, 18th Aug 2004 01:30 PM : 2004-08-18 13:30:12 ShowTimeLongFormat: ;peek enter_bst_day,temp ;temp=temp+1 ;sertxd(#temp," ") ;peek leave_bst_day,temp ;temp=temp+1 ;sertxd(#temp," ") FOR index = 0 TO 2 temp = dayOfWeek * 3 + index ' 0 1 2 3 4 5 6 LOOKUP temp,("MonTueWedThuFriSatSun"),temp SERTXD( temp ) NEXT SERTXD(", ") temp = day + 1 SERTXD ( #temp ) index = day + 1 % 10 IF index > 3 THEN ShowDayTh IF day < 3 OR day > 19 THEN ShowDayTag ShowDayTh: index = 0 ShowDayTag: LOOKUP index,("tsnr"),temp SERTXD( temp ) LOOKUP index,("htdd"),temp SERTXD( temp," " ) FOR index = 0 TO 2 temp = month * 3 + index ' 0 1 2 3 4 5 6 7 8 9 10 11 LOOKUP temp,("JanFebMarAprMayJunJulAugSepOctNovDec"),temp SERTXD( temp ) NEXT tempWord = YEAR_BASE + year SERTXD( " ",#tempWord," " ) temp = hour & $1F % 12 IF temp <> 0 THEN NotOn12HourMark temp = 12 NotOn12HourMark: IF temp >= 10 THEN No12HourLeadingZero SERTXD( "0" ) No12HourLeadingZero: SERTXD( #temp,":" ) IF mins >= 10 THEN No12MinsLeadingZero SERTXD( "0" ) No12MinsLeadingZero: SERTXD( #mins," " ) index = "X" IF hour > 23 THEN NotPm index = "A" temp = hour & $1F IF temp < 12 THEN NotPm index = "P" NotPm: SERTXD( index,"M : ") ShowTimeShortFormat: tempWord = YEAR_BASE + year SERTXD(#tempWord,"-") temp = month + 1 IF temp >= 10 THEN NoMonthLeadingZero SERTXD( "0" ) NoMonthLeadingZero: SERTXD ( #temp,"-" ) temp = day + 1 IF temp >= 10 THEN NoDayLeadingZero SERTXD( "0" ) NoDayLeadingZero: SERTXD ( #temp," " ) temp = hour & $1F IF temp >= 10 THEN NoHourLeadingZero SERTXD( "0" ) NoHourLeadingZero: SERTXD ( #temp,":" ) IF mins >= 10 THEN NoMinsLeadingZero SERTXD( "0" ) NoMinsLeadingZero: SERTXD ( #mins,":" ) temp = secs / 2 IF temp >= 10 THEN NoSecsLeadingZero SERTXD( "0" ) NoSecsLeadingZero: SERTXD ( #temp ) RETURN ; ************************************************************************** ; * * ; * Display a list of the Weekday and Daily Alarm times * ; * * ; ************************************************************************** ShowAlarmTimes: FOR index = 0 TO 7 ' X M T W H F S U SERTXD( " " ) temp = index * 2 + $50 PEEK temp,temp IF temp >= 10 THEN NoAlarmHourLeadingZero SERTXD( "0" ) NoAlarmHourLeadingZero: SERTXD( #temp,":") temp = index * 2 + $51 PEEK temp,temp IF temp >= 10 THEN NoAlarmMinsLeadingZero SERTXD( "0" ) NoAlarmMinsLeadingZero: SERTXD( #temp ) NEXT RETURN ; ************************************************************************** ; * * ; * Determine how many days there are in the month * ; * * ; ************************************************************************** FindDaysInMonth: ' J F M A M J J A S O N D LOOKUP month,(31,28,31,30,31,30,31,31,30,31,30,31), daysInMonth IF month <> 1 THEN NotFebruary GOSUB IsItLeapYear daysInMonth = daysInMonth + leapYear NotFebruary: RETURN ; ************************************************************************** ; * * ; * Determine if a year is a leap year or not * ; * * ; ************************************************************************** ; Sets 'leapYear' to 0 if not a leap year, 1 if it is ; ; If year is divisible by 400 then it is a leap year, else ; If year is divisible by 100 then it is not a leap year, else ; If year is divisible by 4 then it is a leap year, else ; It is not a leap year IsItLeapYear: tempWord = YEAR_BASE + year % 400 IF tempWord = 0 THEN IsLeapYear tempWord = YEAR_BASE + year % 100 IF tempWord = 0 THEN IsNotLeapYear tempWord = YEAR_BASE + year % 4 IF tempWord <> 0 THEN IsNotLeapYear IsLeapYear: leapYear = 1 RETURN IsNotLeapYear: leapYear = 0 RETURN ; ************************************************************************** ; * * ; * Find the days we enter and leave Daylight Saving Time * ; * * ; ************************************************************************** FindDstDays: FindEnterDstDay: POKE SAVE_MONTH,month POKE SAVE_DAY,day month = DST_ENTER_MONTH day = DST_ENTER_DOM GOSUB FindDayOfWeek index = ENTER_DST_DAY temp = DST_ENTER_SUNDAY GOTO FindDstSunday FindleaveDstDay: month = DST_LEAVE_MONTH day = DST_LEAVE_DOM GOSUB FindDayOfWeek index = LEAVE_DST_DAY temp = DST_LEAVE_SUNDAY FindDstSunday: IF dayOfWeek = 6 THEN FindDstSundayDone day = day + temp dayOfWeek = dayOfWeek + temp IF dayOfWeek < 6 THEN FindDstSunday FindDstSundayDone: day = day | DST_DISABLE POKE index, day IF index = ENTER_DST_DAY THEN FindLeaveDstDay PEEK SAVE_MONTH,month PEEK SAVE_DAY,day ; ************************************************************************** ; * * ; * Determine Day Of Week from current date * ; * * ; ************************************************************************** FindDayOfWeek: GOSUB IsItLeapYear LOOKUP month,(0,0,3,3,4,4,5,5,5,6,6,7),temp IF leapYear = 0 THEN NoLeapFindDayOfWeek LeapFindDayOfWeek: tempWord = month * 31 - temp + 1095 IF month < 1 THEN FindDayOfWeek2 tempWord = tempWord + 1 GOTO FindDayOfWeek2 NoLeapFindDayOfWeek: tempWord = month * 31 - temp tempWord = YEAR_BASE + year - 1 % 4 * 365 + tempWord FindDayOfWeek2: tempWord = YEAR_BASE + year - 1973 / 4 * 1461 + day + tempWord dayOfWeek = tempWord % 7 ' 0 = Monday RETURN ; ************************************************************************** ; * * ; * End of Real-Time Clock for the PICAXE-18X * ; * * ; **************************************************************************