I know I'm a pain...
but
does anyone have a piece of PBP-code that converts the binary data from a DS1994 iButton to "readable" time and date ?
Thanks!
I know I'm a pain...
but
does anyone have a piece of PBP-code that converts the binary data from a DS1994 iButton to "readable" time and date ?
Thanks!
60+ Views on this posting (so far) and no reply.
So may I assume there are 60+ people interested in a solution?
Has really nobody used the DS1994 yet?
I have a bunch of DS1994 sitting in a drawer and think they are a good replacement for DS1307 or PCF8583 as they have an embedded crystal and Lithium Backup Battery (that lasts 10+ years) and they are 1-wire.
In addition there is 4k of NV-RAM on Chip.
They count seconds from a reference Date and Time.
How to calculate Year, Month, Day, Day of Week and Time from this DoubleWord Counter
using the Integer Brain of a PIC?
(ok, the counter is actually 5 Bytes, but I don't need the Least Significant Byte that counts fractional seconds)
Any Input is appreciated!
regards
Ralph
Last edited by NavMicroSystems; - 10th August 2004 at 00:13.
Does really nobody have any Input?
(Or do you just nor want to share it?)
Melanie?
I have not used this part before.
When I've a moment free I'll download the Datasheet and see what's cooking...
Melanie thanks for your response.
I have used a number of 1-wire devices and iButtons in the past.
So reading from and writing to the DS1994 is no problem.
The "Time" reading from the DS1994 is a 5 Byte value
that contains the number of seconds (and fractional seconds) elapsed since the counter has been started.
The least significant of those 5 bytes contains fractional seconds.
So we actually have only to deal with a four bytes (or Dword) seconds counter.
To set the Clock choose a reference date, calculate the number of seconds that have elapsed from then til "NOW" and write this to the DS1994 as the "start-value"
All this works fine and the clock is running.
But how do I calculate Year, Month, Day, Day of Week and Time from that DWord Counter to have something more readable to display having only the poor integer math of the PIC?
Best regards
Ralph
Hello Nav!
Nav>>I know I'm a pain...but<<
forgot "in the" <chuckle>.... No, just kidding here. Giving a friend a hard time.
Nav>>does anyone have a piece of PBP-code that converts the binary data from a DS1994 iButton to "readable" time and date ?<<
I have never used a DS1994, or any RTC before. I am getting a little interested in them right now... I biggest problem with RTC, is I want "forever", instead of 10 years <g>. I would like to know what you come up with on these RTC chips. I may order one, next time I order from allelectronics.com
Dwayne
Ability to Fly:
Hurling yourself towards the ground, and missing.
Engineers that Contribute to flying:
Both optimists and pessimists contribute to the society. The optimist invents the aeroplane, the pessimist the parachute
Pilots that are Flying:
Those who know their limitations, and respect the green side of the grass...
Let's hope for a "MN1994.txt"
("MN1307.txt was excellent!)
Last edited by NavMicroSystems; - 14th August 2004 at 03:08.
Some progress has been made.
I managed to calculate the number of Days, Hours, Minutes and Seconds
elapsed since the reference date (01/01/2000 00:00:00)
from the DoubleWord seconds counter reading.
So far I can display the correct time from the iButton reading.
Next steps will be:
- calculation of Year, Date and Day of Week.
- A "Set Clock" Routine.
- automatic DST adjustment.
Your Input is still appreciated.
regards
I've got as far as downloading the Datasheet... looks like a linear extension of Julian Date kind of application... this is a bad two weeks for me (lots of work plus being an Olympics fan I'm in Athens at the weekends!)... but I'll see what I can do after.
Thank you for reminding me Ralph... I thought if I stayed nice and quiet and kept my head down the problem will go away...
To achieve the answer is easy... to write it up so you all know how we get to it is what I wasn’t looking forward to doing... ah well, here goes an hour out of my life... and as always I draw your attention to the fact that there are many ways to get to the result - this is just one that’s simple and easy to grasp...
1. Firstly let’s stand back and look at the big picture and try to understand it...
The problem is that we have linear seconds represented as a 32 bit number which in theory we can’t handle. What we need to achieve is linear DAYS, with the remainder in the form of HOURS, MINUTES and SECONDS. That remainder of HOURS, MINUTES and SECONDS we can display as our REAL-TIME CLOCK component, whilst the linear DAYS we can then simply add to a reference point (ie a PIC version of a JULIAN DATE) to give us our YEAR, MONTH and DAY.
There are two further problems here... not too obvious but pretty serious if you think about it, and that is (a) We can’t take significant time to calculate the result (after all it’s a clock and really you’d like to see the seconds ticking by and still have time to do something else), and (b) We can’t use up serious amount of codespace (what’s the point of using the equivalent of floats and then not having any space left in your PIC).
Here’s our known limitations so far... We can’t have numbers bigger than 16-bits (65535), and we can’t have a divisor bigger than 15 bits (32767) if we decide to use DIV32 which is the only large calibre weapon in our maths arsenal. We could embed Microchips 32-bit Assembler routines but that will burn codespace and anyway, that’s cheating, quite apart from the fact that as soon we write a single line of Assembler, half the readers of this forum will immediately drop-out through lack of understanding or interest.
2. How do we reduce the numbers to something manageable?
What we ideally want to do is divide our 32-Bit number by 86400 (the number of seconds in a day). Well, the divisor is already 17 bits, and that’s two bits more than DIV32 can handle... looks on the surface like we’re losing this one - but are we?
Let’s analyse those 32 bits... what have we got?
The lower 16 bits are seconds from zero, up to 65535. The upper 16 bits are multiples of 65536 seconds. If we load the two upper bytes as a word, then each count represents 65536 seconds. What is 65536 seconds? It is 18 HOURS, 12 MINUTES and 16 SECONDS. Knowing this, we can simply explode our most significant word into multiples of HOURS, MINUTES and SECONDS...
3. Let’s program...
ByteA var BYTE
ByteB var BYTE
ByteC var BYTE
ByteD var BYTE
DAYS var WORD
HOURS var BYTE
MINUTES var BYTE
SECONDS var BYTE
TempA var WORD
TempB var WORD
TempHOURS var WORD
TempMINUTES var WORD
TempSECONDS var WORD
Now assume we’ve read our 32-Bit number from the RTC into variables ByteA, ByteB, ByteC and ByteD where ByteA holds our Most Significant Bits, and ByteD holds the Least Significant Bits.
TempA.Highbyte=ByteA
TempA.Lowbyte=ByteB
TempB=TempA*18
DAYS=DIV32 24
HOURS=R2
TempB=TempA*12
TempHOURS=DIV32 60
MINUTES=R2
TempB=TempA*16
TempMINUTES=DIV32 60
SECONDS=R2
This now completely resolves our most significant byte:-
DAYS holds our resolved days.
HOURS and TempHOURS together hold the Hours quotient
MINUTES and TempMINUTES together hold the Minutes quotient
SECONDS holds the Seconds quotient
Now for our least Significant 16 Bits...
TempA.Highbyte=ByteC
TempA.Lowbyte=ByteD
TempHOURS=TempHOURS+(TempA/3600)+HOURS
TempA=TempA//3600
TempMINUTES=TempMINUTES+(TempA/60)+MINUTES
TempA=TempA//60
TempSECONDS=TempA+SECONDS
And finally, let’s resolve the issue in it's entirity...
TempMINUTES=TempMINUTES+(TempSECONDS/60)
SECONDS=TempSECONDS//60
TempHOURS=TempHOURS+(TempMINUTES/60)
MINUTES=TempMINUTES//60
DAYS=DAYS+(TempHOURS/24)
HOURS=TempHOURS//24
So at the end of this, we have DAYS (a word variable which can be used to offset our Reference Point), HOURS, MINUTES and SECONDS, the latter all being BYTE variables. The only clever thing we have used, is a little known system variable called R2 which holds the remainder from a DIV32 execution. Before anyone asks that they've never hear of R2, that little golden nugget on this forum was brought to you by Darrel Taylor in the Code Examples section. Bet nobody's paid attention!
4. Let’s work through a random example…
10154 days, 18 Hours, 48 Minutes and 52 seconds… is 877373332 Seconds, which equates to the 32 bit number… $344BA794… (assuming my math serves me correctly)…
Does it work? As if you need to ask!Code:' ' Software Defines ' ---------------- ByteA var BYTE ByteB var BYTE ByteC var BYTE ByteD var BYTE DAYS var WORD HOURS var BYTE MINUTES var BYTE SECONDS var BYTE TempA var WORD TempB var WORD TempHOURS var WORD TempMINUTES var WORD TempSECONDS var WORD ' ' Enter Test Data ' --------------- ByteA=$34 ByteB=$4B ByteC=$A7 ByteD=$94 ' ' Calculate and Display ' --------------------- Loop: Gosub CalculateLinearDAYS LCDOut $FE,$01,"Days=",#DAYS LCDOut $FE,$C0,"Time=",DEC2 HOURS,":",DEC2 MINUTES,":",DEC2 SECONDS Pause 1000 Goto Loop ' ' Calculate Linear DAYS ' --------------------- CalculateLinearDAYS: TempA.Highbyte=ByteA TempA.Lowbyte=ByteB TempB=TempA*18 DAYS=DIV32 24 HOURS=R2 TempB=TempA*12 TempHOURS=DIV32 60 MINUTES=R2 TempB=TempA*16 TempMINUTES=DIV32 60 SECONDS=R2 ' TempA.Highbyte=ByteC TempA.Lowbyte=ByteD TempHOURS=TempHOURS+(TempA/3600)+HOURS TempA=TempA//3600 TempMINUTES=TempMINUTES+(TempA/60)+MINUTES TempA=TempA//60 TempSECONDS=TempA+SECONDS ' TempMINUTES=TempMINUTES+(TempSECONDS/60) SECONDS=TempSECONDS//60 TempHOURS=TempHOURS+(TempMINUTES/60) MINUTES=TempMINUTES//60 DAYS=DAYS+(TempHOURS/24) HOURS=TempHOURS//24 Return End
Now… having got this to work, your hour is up, and JULIAN DATE routines is another story…
Melanie
Melanie,
many thanks for taking the time to teach us in math,
I like your approach.
In the meantime I have found a slightly different solution that works.
But I still feel it takes too much code space and memory.
After I have cleaned up the code (hopefully tomorrow) I will post my example.
BTW.
I followed the discussion" PBP vs. PROTON+"
I have tried my DWORD calculations using PROTON+
and feel it does not really help.
If one writes own double precision math routines in PBP
the same result can be achieved.
PROTON+ (and its math routines) do not save any memory or code space
as they don't (and can't) do any magic.
best regards:
Ralph
Last edited by NavMicroSystems; - 27th September 2004 at 01:18.
As we all know, Julian Date was fixed by Julius Caesar, this was a guy that played with PICs a lot - and look where it got him. The problem we have is that PBP doesn’t handle Roman Numerals too well, and whilst the idea of having a Linear Date is a good (and very useful) one, generally, we only have to handle the Century that we’re in. So let’s start our PIC’s handling of a Linear Date from 1st January 2000... this way an integer variable (counting in DAYS) can ‘theoretically’ handle over 170 years worth of data.
Now I don’t know about you, but it’s highly unlikely that any of my designs are still going to be working in the year 2170 (in best engineering tradditions they're only guaranteed to work until the warranty expires), and I’m sure not going to be fielding the tech-support calls. If you find that the date gets screwed past 05/06/2179 (integer value 65534), don't email me - I'm not interested.
Converting Linear DAYS Back to a Date in the form of YEAR, MONTH and DAY is a little tricky... This is a clumsy way of working out the result, however, the routine I actually use I’m not willing to share, so you’ll have to make do with this one I threw together this morning... starting at January 1 2000 it’s good for almost 180 years (and being a thoughtful kinda girl, I've accounted for the fact that Year 2100 is NOT a Leap Year)...
The Subroutine shares variables that I've used earlier in this thread, and is called with the Linear Date held in the variable DAYS, and returns with a useable YEAR, MONTH and DAY.
MelanieCode:CounterA var BYTE DAY var BYTE DAYS var WORD MONTH var BYTE TempA var WORD TempB var WORD YEAR var BYTE ' ' Subroutine Calculates Date from Linear Days ' ------------------------------------------- CalculateDateFromLinear: YEAR=0 DAYS=DAYS+1 For CounterA=4 to 183 TempA=CounterA//4 TempB=365 If TempA=0 then If CounterA<>104 then TempB=TempB+1 endif If DAYS>TempB then YEAR=YEAR+1 DAYS=DAYS-TempB else Goto CalculateMonth endif Next CounterA ' add 2000 to the YEAR value, ie YEAR=4 implies 2004. CalculateMonth: MONTH=0 CalculateMonthLoop: Lookup2 MONTH,[31,28,31,30,31,30,31,31,30,31,30,31],DAY IF TempA=0 then IF YEAR<>100 then If MONTH=1 then DAY=DAY+1 Endif Endif If DAYS>DAY then DAYS=DAYS-DAY MONTH=MONTH+1 Goto CalculateMonthLoop Endif MONTH=MONTH+1 DAY=DAYS Return
Melanie,
thanks again !!
your code is smaller than my one and I will use it for the DS1994.
You could save another 79 words of codespace by replacing the LOOKUP2 with LOOKUP.
Best regardsCode:CalculateMonthLoop: Lookup2 MONTH,[31,28,31,30,31,30,31,31,30,31,30,31],DAY
Ralph
I originally used LOOKUP2 because my first rough code this morning used the last day of each month cumulative, which means as you get towards the end of the year the DAY spills out of a byte variable, before I changed the code to the version I actually posted, and forgot to change it back.
You can of course save yourself another 14 words of codespace by not caring that your code runs past year 2100 and removing the century leap-year correction. As if we're going to lose sleep over it...
Great,
those 14 plus another 20 by moving the LOOKUP Table to EEPROM
regards
Bookmarks