PDA

View Full Version : 500 Year Calendar for DT Elapsed Timer



Art
- 11th January 2015, 12:17
Hi Guys,
Here’s my 500 year calendar that can be used with Darrel Taylor’s Elapsed Timer routines (when used as a clock).

There’s a video demonstration coming up shortly :)

This can save you a RTC/Calendar Chip such as Maxim/Dallas 1307/1302 when you are already using the clock routine.
The DS1307 is only accurate to the year 2100, where I have checked accuracy against iOS in the range 1800-2300.

Usage:

Set your variables calday, calmonth, calyear with the input numbers and call setcal subroutine.
If the date made sense, and the year was within range 1800-2300 the flag calbadentry will be zero.
If the year was out of range or you used a number that was too high for day or months (i.e. entered 29th of Feb when it was not a leap year),
the number for day or month will be set to 1, and the value for calbadentry will be 1
for your program to throw an error.
If the year is out of range it gets adjusted back to the upper or lower limit.
The variable caldow will contain the day of the week where zero is Sunday through to 6 for Saturday.

From there you can just check the value of DayChanged with he provided code waiting for the day to change,
and the program routine will increment the date and weekday each day.

The lookup table epochyears contains 12 years that begin on a Monday to make the calendar faster.
The calendar routine only has to iterate from the closest year before the current year the user input.

During testing the weekday and leap year routines were tested against the stock iPhone calendar App.


Implementation:

In the Elasped.bas file, add the DayChanged bit like so:




TicksChanged var bit
SecondsChanged var bit
DayChanged var bit



You will also need to make a small change to the sequence that increments the time variables
to wrap around after 24 hours (if you haven’t done so for a clock already),
and set the DayChanged status every 24 hours.




Ticks = Ticks + 1
if Ticks = 100 then
Ticks = 0
Seconds = Seconds + 1
SecondsChanged = 1
if Seconds = 60 then
Seconds = 0
Minutes = Minutes + 1
endif
if Minutes = 60 then
Minutes = 0
Hours = Hours + 1
endif
if Hours = 24 then <————
Hours = 0
DayChanged = 1 ‘ <—————
endif
endif




In your own main program file, declare some calendar variables:




caldim var byte [12] ' calendar days in months
calday var word ' calendar day
calmonth var word ' calendar month
calyear var word ' calendar year
caldow var byte ' calendar day of the week
calleap var bit ' current year leap status bit
calbadentry var bit ' bad calendar input flag
cacnt var word ' counter for calendar
cwork var word ' work buffer for calendar
xwork var word ' work buffer for calendar
calleapx var bit ' leap year buffer for calendar



reset some variables in a place that is only run once at startup,
and set a default date (be sure the date is in range 1800-2300.




calyear = 2015 ' set default date to 01/01/2015
calday = 0 ' day is incremented to 1 at startup
DayChanged = 1 ' because this day changed flag is set
calmonth = 1 ' month defaults to January



Now somewhere in your main program that cycles, check this code regularly:





‘ program initialisation
‘ tris something = something
‘ some flag = 0
calyear = 2015 ' set default date to 01/01/2015
calday = 0 ' day is incremented to 1 at startup
DayChanged = 1 ' because this day changed flag is set
calmonth = 1 ' month defaults to January


main:

‘ your main program..


' increment date if day changed over
'
if DayChanged = 1 then
calday = calday + 1
if calday > caldim[calmonth-1] then
calday = 1
calmonth = calmonth + 1
endif
if calmonth > 12 then
calmonth = 1
calyear = calyear + 1
endif
'
DayChanged = 0
gosub setcal
endif ' DayChanged
'

goto main










This is the calendar that is called as a subroutine called “setcal”:





‘ 500 year calendar for pic (tested with 16F877A) by Brek Martin (Art) 2015.

‘ This is free software. Please credit the author if it’s reused or distributed.
'
' ******************* set calendar date and find day of week *******************
'
setcal: ' find leap year status
caldim[0] = 31 ' set default days in month table
caldim[1] = 28 ' days in February is changed to 29 by the program
caldim[2] = 31 '
caldim[3] = 30 '
caldim[4] = 31 '
caldim[5] = 30 '
caldim[6] = 31 '
caldim[7] = 31 '
caldim[8] = 30 '
caldim[9] = 31 '
caldim[10] = 30 '
caldim[11] = 31 '
'
calleap = 0 ' clear leap year status
if calyear // 4 = 0 then '
calleap = 1 ' set leap year status
if calyear // 100 = 0 then '
calleap = 0 ' clear leap year status
if calyear // 400 = 0 then '
calleap = 1 ' set leap year status
endif '
endif '
endif '
'
if calleap = 1 then '
caldim[1] = 29 '
endif '
'
calbadentry = 0 ' reset calendar bad entry status
if calmonth = 0 then ' check for invalid date input
calbadentry = 1 '
calmonth = 1 '
endif '
if calmonth > 12 then '
calbadentry = 1 '
calmonth = 1 '
endif '
if calday = 0 then '
calbadentry = 1 '
calday = 1 '
endif '
if calday > caldim[calmonth-1] then
calbadentry = 1 '
calday = 1 '
endif '
if calyear < 1800 then ' implement lower year range restriction
calbadentry = 1 ' prevent far away dates slowing program down
calyear = 1800 '
endif '
if calyear > 2300 then ' implement higher year range restriction
calbadentry = 1 ' in case of errors far into the future
calyear = 2300 '
endif ' the hardware probably won't last that long
'
' day of week
'
xwork = 2310 ' find best epoch year to iterate from
cacnt = 12 '
while xwork >= calyear '
gosub epochyears '
cacnt = cacnt - 1 '
wend '
'
'
cwork = 0 ' working variable for days
'
for cacnt = xwork to calyear - 1' iterate years from epoch year
calleapx = 0 ' clear leap year status
if cacnt // 4 = 0 then '
calleapx = 1 ' set leap year status
if cacnt // 100 = 0 then '
calleapx = 0 ' clear leap year status
if cacnt // 400 = 0 then '
calleapx = 1 ' set leap year status
endif '
endif '
endif '
'
if calleapx = 0 then ' add days over the years from epoch
cwork = (cwork + 365)//7 '
else '
cwork = (cwork + 366)//7 '
endif '
'
next cacnt '
'
if calleap = 1 then ' fix day of month table for current year
caldim[1] = 29 '
else '
caldim[1] = 28 '
endif '
'
cacnt = calmonth-1 ' add days for elapsed months of current year
while cacnt > 0 '
xwork = caldim[cacnt-1] '
cwork = (cwork + xwork)//7 '
cacnt = cacnt - 1 '
wend '
'
cacnt = calday-1 ' add days elapsed of current month
xwork = 0 '
while cacnt > 0 '
xwork = xwork + 1 '
cacnt = cacnt - 1 '
wend '
cwork = (cwork + xwork)//7 '
'
'
caldow = cwork + 1 ' shift range for display so 0=Sunday, 6=Saturday.
if caldow = 7 then caldow = 0 '
return
'
'
epochyears:
lookup2 cacnt,[1798,1849,1900,1951,1990,2035,2052,2091,2125,2153, 2198,2227,2244],xwork
return
'



Cheers, Art.

amgen
- 11th January 2015, 14:59
Man, you must be planning to live a long time !!

Art
- 11th January 2015, 16:50
Not to mention I’ve accomodated those pioneering folk from the past who had to use mechanical clocks.

Man, you must be planning to live a long time !!

Art
- 15th January 2015, 16:01
Here’s the demo video :) What an unfortunate shot! :O

https://www.youtube.com/watch?v=imchcw14Z7I

Art
- 8th May 2015, 11:53
Hi Guys,
This came in handy for me today, so I just wanted to share the tip.
If you are reading UTC time from GPS, and want to display your local time,
there’s no other way but having a complete calendar to know what the date is going to be
if your adjustment of the hours made a day change over.

If you read 22:00 UTC time from the GPS, and in my location, have to add the offset +10,
you would have the time 32:00, and would have watched for 24 hour overflow in an hours buffer,
so the time would be displayed correctly as 08:00. The day could have been incremented on the
overflow of the hours buffer as well, but it could have also been the last day of the month or year,
and you need to know how many days are in the particular month for the current year.

This all didn’t really occur to me until I next read the time from a GPS module,
but the limitation has hit me before.
Cheers, Art.

Art
- 8th July 2017, 08:53
Hi Guys :)
This might be of use to someone familiar with PBP, but looking at Arduino or something like that.
The exact same code ported to C, and demonstrated with a graphic GUI.
Although the graphic GUI is freshly done in C, it’s using the same “setcal" subroutine above,
as a C function, which at least demonstrates how to use lookup tables, arrays, loops, and some arithmetic.

https://www.youtube.com/watch?v=Pz4LFrRloBQ

Ioannis
- 8th July 2017, 10:16
Very nice!

And very quick LCD update! Like!

Ioannis

Art
- 12th July 2017, 15:16
Thanks Ioannis :)
The graphics stuff is all new C started in 2016, but I think that part would be better in PBP or asm,
just that it wouldn’t run on dspic, and it appears the dspic asm isn’t the familiar 8 bit RISC asm.

Ioannis
- 12th July 2017, 17:27
Maybe if/when the PBP24 or PBP32 will be available, we will see dreams coming true!

Until then, keep up the good work and let us see your achievements.

Ioannis