DS1994 Memory/Time iButton - Page 3


Closed Thread
Page 3 of 4 FirstFirst 1234 LastLast
Results 31 to 45 of 48

Hybrid View

  1. #1
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    This is a great thread, because it's demonstrating and reminding us of a whole heap of things... and these are useful things...

    So far...

    1. We've been reminded of a little known but very useful variable called R2 in the DIV32 command.

    2. We've manipulated a 32 bit variable which on the face of it seemed impossible with PBP, and reduced it to something useful and manageable.

    3. We've converted Gregorian Date (DAY, MONTH, YEAR) into a Julian Date (Linear DAYS).

    4. We've converted Julian Date (Linear DAYS) back into a Gregorian Date (DAY, MONTH, YEAR). This has been mentioned you can't do it with only 16-bit variables.

    5. We've discovered a way of saving a Date (as DAY, MONTH and YEAR) compactly as two BYTES (great for space saving when Data-Logging).

    6. Better than that we've discoverd a way to save DAY, MONTH, YEAR, HOUR, MINUTE and SECOND, as only FOUR bytes. Again, beat that for a Data-Logging application.

    Just using those you could enter two dates, and not only determine the DAYS between them, but you could determine it to the SECOND.

    7. We've demonstrated a method of 16 by 17 bit multiplication... to produce a 32 Bit result.

    And we've done it all in 'pure' PBP with no Assembler or other 'bought-in' foreign routines. That way, everybody can follow it and learn something to their benefit.

    And this thread isn't done yet...

  2. #2
    Join Date
    Feb 2004
    Location
    Germany
    Posts
    762


    Did you find this post helpful? Yes | No

    Default

    Melanie,

    shouldn't it be . . .

    IF TempA=3

    Code:
    CalculateLinearFromDate:
    
    	DAYS=0
    	IF YEAR>0 then
    		For CounterA=0 to YEAR-1
    			TempA=(countera)//4
    			LCDOUT $FE,$8e,dec2 tempa
    			TempB=365
    			If TempA=0 then TempB=TempB+1
    			DAYS=DAYS+TempB
    			Next CounterA
    		endif
    	IF MONTH>1 then
    		For CounterA=1 to MONTH-1
    			Read (CounterA+20),ByteA
    		
    '-----------------------------------------------
                            If TempA=3 then
    '-----------------------------------------------
    				If CounterA=2 then ByteA=ByteA+1
    				endif
    			DAYS=DAYS+ByteA
    			Next CounterA
    		endif
    	DAYS=DAYS+DAY-1
    	Return

  3. #3
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    Nope.

    TempA=CounterA//4

    2000//4=0
    2004//4=0
    etc etc

    OK, CounterA holds 0 for 2000, 4 for 2004 etc etc, the '2000' is implied.

    TempA=0 only when there is a leap year...

    We use it twice in the routine... once with whole years by adding a day to any leap year. But when we calculate out a date that ends on a leap year itself, we have to add 1 additional day to February's month total. So that Februarys days read from EEPROM (or LOOKUP) is adjusted.

    That particular routine I did check before I posted it... and I've since checked the CalculateLinearSeconds one too, and both work as expected. I'll post the Data-entry routines shortly.

    Meanwhile... you can do a test like this to check for yourself...

    DAY=24
    MONTH=12
    YEAR=66 ' 2066 Implied
    Gosub CalculateLinearFromDate
    '
    ' at this point DAYS=24464
    '
    HOURS=14
    MINUTES=37
    SECONDS=46
    Gosub CalculateLinearSeconds
    LCDOut $FE,$C0,"$",HEX4 TempA,HEX4 TempB

    Your LCD should display $7DFD25BA

    This equates to the decimal number 2113742266.

    A quick calculator check of (24464*86400)+(14*3600)+(37*60)+46 confirms we're doing something right!

    Now feed that figure back through the routines I posted yesterday and you get... surprise, surprise...


  4. #4
    Join Date
    Feb 2004
    Location
    Germany
    Posts
    762


    Did you find this post helpful? Yes | No

    Default

    Try it with:

    DAY=28 Month=2 Year=4
    DAY=29 Month=2 Year=4
    DAY=1 Month=3 Year=4

    and doublecheck the above with year=8

  5. #5
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    You're both right and wrong...

    I couldn't figure why my test program works and you say it didn't... it took me ages to discover I've posted the wrong subroutine...

    So yes, there was an erroneous result, but the solution was a rehash of the existing lines... TempA must still stay as If TempA=0...

    I have corrected it now...

    28/2/04 is Days 1519
    29/2/04 is Days 1520
    01/3/04 is Days 1521

    Also now valid for DAYS=2980, 2981, 2982 etc up the leap years.

  6. #6
    Join Date
    Feb 2004
    Location
    Germany
    Posts
    762


    Did you find this post helpful? Yes | No

    Default

    The change TempA=0 to TempA=3 on the line marked was only a workaround, but it would have done the trick with the initial routine (I think).

  7. #7
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    Right now you're pausing every Second and redisplaying whilst clearing the screen every time. This has a number of drawbacks... (1) it will cause your LCD to 'flicker' every time you display... (a more professional way is to clear the display only every 'n' seconds)... (2) the 1 second delay can cause an unacceptible 'lag' when somebody presses Buttons (to enter the Setup routine for example)... and (3) can cause a strange effect when you're watching seconds ticking by, as every now and again you get the feeling a Second is longer than it should be, because you're adding one 'software' second (plus propogation delay in your software program) to your RTC second and they can get out of step...

    Fisrt we've added some more variables...

    KeyBut var BYTE
    TimeOut var BYTE
    UserField var BYTE
    UserMax var BYTE
    UserMin var BYTE
    UserPos var BYTE

    and we've increased your DOW array...

    DOW var BYTE [5]

    and introduced a constant...

    TimeoutConstant con 200

    ... more about these later.

    My Buttons are connected on PortB and I'm using pull-ups (pin goes Low on Button Press). At the start of my proram I have the following defines...

    ButtonUp var PortB.0
    ButtonDown var PortB.1
    ButtonSet var PortB.2

    and I've also put...

    OPTION_REG.7=0

    ...at the start where I first initialse my PIC. Change these around, (along with my Getkey routine - later) to suit your own arrangement.

    Now we rehash the Main Program Loop like so...

    Code:
    	TimeOut=TimeoutConstant
    Loop:
    	'
    	'	Read iButton
    	'	------------
     	owout iButton,1,[$cc,$f0,$03,$02]
    	owin iButton,0,[ByteD,ByteC,ByteB,ByteA]
    	'
    	'	Display Date & Time
    	'	-------------------
    	Gosub CalculateLinearDAYS
    	GOSUB CalculateDateFromLinear
    	If TimeOut = > TimeoutConstant then 
    		LCDOut $FE,1
    		TimeOut=0
    		endif
    	LCDOut $FE,$80, STR DOW\3,". ", dec2 Day,".",dec2 month,".","20",dec2 year
    	LCDOut $FE,$C4,DEC2 HOURS,":",DEC2 MINUTES,":",DEC2 SECONDS
    
    	' Note the $FE,$C4 above... saves you a few bytes...
    
    	TimeOut=TimeOut+1
    	Gosub GetKey
    	If KeyBut < > 3 then goto Loop
    	'
    	'	Setup Date & Time
    	'	-----------------
    	DOW(0)=YEAR
    	DOW(1)=MONTH
    	DOW(2)=DAY
    	DOW(3)=HOURS
    	DOW(4)=MINUTES
    	Gosub EditDateTime
    	If TimeOut=0 then	' Only Save if SET Button Pressed
    		YEAR=DOW(0)	' ie not TimeOut
    		MONTH=DOW(1)
    		DAY=DOW(2)
    		HOURS=DOW(3)
    		MINUTES=DOW(4)
    		SECONDS=0
    		Gosub CalculateLinearFromDate
    		Gosub CalculateLinearSeconds
    		ByteA=TempA.HighByte
    		ByteB=TempA.LowByte
    		ByteC=TempB.HighByte
    		ByteD=TempB.LowByte
    		'
    		' Set your iButton here
    		'
    		endif
    	TimeOut=TimeoutConstant ' This causes a Clear Screen in our main Loop
    	Goto Loop
    Now you'll only get a flicker once every 20 Seconds, and with our GetKey subroutine we have a worst case lag of 100mS. We've also created a neat way of dropping into our SetUp at that point.

    You'll also see I'm using two new variables KeyBut and TimeOut, both of which are BYTES. Keybut returns a value from 0-7 (per the GetKey routine table below) depending on what Button or combination of Buttons are pressed. TimeOut is an incremental 100mS counter. It is reset to zero should any key be pressed... more about this later... Finally I use a Keyboard Loop-Time of 100mS. I have found that less than that and Button autorepeat is too fast to handle easily. More than that, and autorepeat feels sluggish, and you get bored holding the Button. Change this value to suit your personal preference - but in doing so you may also need to change the TimeoutConstant value.

    Code:
    	'
    	'	Subroutine Scans Buttons
    	'	------------------------
    		' KeyBut - 0 = Invalid (SET+UP+DOWN Pressed)
    		'	 - 1 = Invalid (SET+UP Pressed)  
    		'	 - 2 = Invalid (SET+DOWN Pressed)
    		'	 - 3 = SET Pressed
    		'	 - 4 = Invalid (UP+DOWN Pressed)
    		'	 - 5 = UP Pressed
    		'	 - 6 = DOWN Pressed
    		'	 - 7 = No Buttons Pressed
    GetKey:
    	KeyBut=0			' Zero any previous Result First
    	KeyBut.0=ButtonDown		' Read Input Buttons
    	KeyBut.1=ButtonUp
    	KeyBut.2=ButtonSet
    	If KeyBut < > 7 then TimeOut=0	' Resets Timeout Counter
    	Pause 100			' Allows for 10cps auto-repeat
    	Return
    Now for the EditDateTime Routine... you'll notice I've increased the size of your DOW array to 5 elements as I'm going to use that as my editing array since there are 5 things I need to edit... YEAR, MONTH, DAY, HOUR and MINUTE and I really need a byte for each... and since DOW is unused during SetUp, this seems a good use of otherwise unused resources to me.

    I've put the EditDateTime into a subroutine, because you may want to use the same routine for entering and setting the iButton alarms later as your program gets more sophisticated.

    This Date & Time subroutine is BULLET-PROOF. There's nothing worse than attempting to enter the 31st of April, or 29th of February in a non-leap year. Makes your code look amateurish and quickly causes loss or credibility with clients. Try entering an invalid Date or Time setting - I think you'll find you can't break it.

    The subroutine also assumes DOW is preloaded with a valid date and Time on entry (even if it's just a simple 1/1/2000 00:00), usually you would read the RTC and if it's got a sensible Time & Date you would preload the figures with that... (when setting an Alarm for example, you would want the previous setting to be displayed so you can edit it).

    Look-out for the bonus features... (a) if you don't press any Buttons for 20 seconds, then you will be returned to the main Loop without any new settings being saved (that's where that TimeOut variable comes in)... and (b) of course you've got that 10Hz autorepeat on the Buttons (except SET).

    Code:
    	'
    	'	Subroutine for Date and Time Entry
    	'	----------------------------------
    EditDateTime:
    	LCDOut $FE,1,"Set Date & Time"
    	LCDOut $FE,$C0,"20",DEC2 YEAR,"/",DEC2 MONTH,"/",DEC2 DAY
    	LCDOut $FE,$CB,DEC2 HOURS,":",DEC2 MINUTES
    	UserField=0
    EditDateTimeLoop:
    	UserMin=0:UserMax=99:UserPos=$C2
    	If UserField=1 then
    		UserMin=1:UserMax=12:UserPos=$C5
    		endif
    	If UserField=2 then
    		UserMin=1:UserMax=31:UserPos=$C8
    		If DOW(1)=2 then
    			CounterA=DOW(0)//4
    			If CounterA=0 then 
    				UserMax=29
    				else
    				UserMax=28
    				endif
    			endif
    		If DOW(1)=4 then UserMax=30
    		If DOW(1)=6 then UserMax=30
    		If DOW(1)=9 then UserMax=30
    		If DOW(1)=11 then UserMax=30
    		endif
    	If UserField=3 then
    		UserMax=23:UserPos=$CB
    		endif
    	If UserField=4 then
    		UserMax=59:UserPos=$CE
    		endif
    	Gosub GetKey
    	If KeyBut=3 then goto EditDateTimeLoop
    EditDateTimeFieldLoop:
    	LCDOut $FE,UserPos,DEC2 DOW(UserField),$FE,$0E,$FE,UserPos+1
    EditDateTimeIdleLoop:
    	Gosub GetKey
    	If KeyBut=5 then
    		DOW(UserField)=DOW(UserField)+1
    		If DOW(UserField)>UserMax then DOW(UserField)=UserMin
    		Goto EditDateTimeFieldLoop
    		endif
    	If KeyBut=6 then
    		If DOW(UserField) > UserMin then
    			DOW(UserField)=DOW(UserField)-1
    			else
    			DOW(UserField)=UserMax
    			endif
    		Goto EditDateTimeFieldLoop
    		endif
    	If KeyBut < > 3 then 
    		TimeOut=TimeOut+1
    		If TimeOut < TimeoutConstant then goto EditDateTimeIdleLoop
    		Goto EditDateTimeExit
    		endif
    	LCDOut $FE,$0C
    	UserField=UserField+1
    	If UserField < 5 then goto EditDateTimeLoop
    EditDateTimeExit:
    	LCDOut $FE,$0C,$FE,$01
    	While KeyBut < > 7
    		Gosub GetKey
    		Wend
    	Return
    Note also the creative use of Curson ON and Cursor OFF, so that the user is guided to take their finger OFF the SET Button and progress to editing...

    Have fun

    Melanie

  8. #8
    Join Date
    Feb 2004
    Location
    Germany
    Posts
    762


    Did you find this post helpful? Yes | No

    Default

    WOW

  9. #9
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    When you're done, you can create Ralph1994 and send it with a resume of what it does to MeLabs for inclusion in their Submitted Programs section... people must be getting bored with my offerings.

  10. #10
    Join Date
    Sep 2006
    Posts
    42


    Did you find this post helpful? Yes | No

    Default ibutton 1990a

    Quote Originally Posted by Melanie
    When you're done, you can create Ralph1994 and send it with a resume of what it does to MeLabs for inclusion in their Submitted Programs section... people must be getting bored with my offerings.
    hi,

    i succeed to read ibutton (1990a) and display it on lcd..but iam not able to store serial# on variable..i want to compare ibutton's serial nos.iam trying to read multiple ibuttons and store their sr# in eprom.. if sr# is 1 of the stored # then do something...

    Thanking you

    Regards.

  11. #11
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    Bah... you can end up improving code until the cows come home...

    In the EditDateTime subroutine...
    Code:
    	If UserField=2 then 
    		UserMin=1:UserPos=$CB
    		Read DOW(1)+20,UserMax
    		If UserMax=28 then
    			CounterA=DOW(0)//4
    			If CounterA=0 then UserMax=29
    			endif
    		endif
    Is a bit more professional and saves 34 bytes.

  12. #12
    Join Date
    Feb 2004
    Location
    Germany
    Posts
    762


    Did you find this post helpful? Yes | No

    Default

    Melanie,

    UserPos should be $c8, not $cb


    Code:
    If UserField=2 then 
    		UserMin=1:UserPos=$CB '<--------------------- 
    		Read DOW(1)+20,UserMax
    		If UserMax=28 then
    			CounterA=DOW(0)//4
    			If CounterA=0 then UserMax=29
    			endif
    		endif
    regards

    Yup - you're right - Melanie

  13. #13
    Join Date
    May 2004
    Location
    brighton
    Posts
    149


    Did you find this post helpful? Yes | No

    Smile

    Hi Nav / Mel
    I have being reading the trend DS1994 Memory/Time iButton and it is very very interesting and just need your help in using the program.
    I am using a DS1307 RTC of which i read the following variables

    Date =23
    Month=03
    Year=05
    Hour =21
    Mins =30
    Seconds=30
    to give me 23-03-05 21:30:30 (my data & time)
    which are all byte variables

    But i want to convert this to Linear DAYS and add 365 but can't figure out which subroutine to use as from my understand the subroutines are looking for a 32bit number

    Could you be kind enough to explain to me

    Best Regards
    Isaac

  14. #14
    Join Date
    Feb 2004
    Location
    Germany
    Posts
    762


    Did you find this post helpful? Yes | No

    Default

    ISAAC,

    the Subroutine "CalculateLinearFromDate" isn't really that complex, is it?

    with your variables beeing:

    Date =23
    Month=03
    Year=05
    Hour =21
    Mins =30
    Seconds=30

    all you need to do is:
    rename your VAR "Date" to "DAY"
    (or create an alias)
    and declare the following variables in addition:

    CounterA VAR Byte
    TempA VAR WORD
    TempB VAR WORD
    DAYS WAR WORD

    once you have read the DS1307 just

    GOSUB CalculateLinearFromDate

    and you will find the result in "DAYS"
    regards

    Ralph

    _______________________________________________
    There are only 10 types of people:
    Those who understand binary, and those who don't ...
    _______________________________________________



  15. #15
    Join Date
    Jan 2005
    Location
    Australia
    Posts
    20


    Did you find this post helpful? Yes | No

    Question

    Hi Ralph & Melanie,

    How to calculate the elapsed hours between 16:30:45 (HH:MM:SS), 28/05/2005 (DD/MM/YYYY) and 02:26:38, 01/08/2004.

    Assume the elapsed time is limited to less than one year. Can I use the CalculateLinearFromDate subroutine to do the job?

    Best regards,
    Yuantu Huang

Similar Threads

  1. Writing & Reading to iButton EEPROM
    By crhomberg in forum Code Examples
    Replies: 2
    Last Post: - 6th October 2008, 19:40
  2. DS1920 IButton
    By scottl in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 2nd November 2007, 00:39
  3. iButton
    By menze in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 26th June 2006, 23:48
  4. RS485 - ibutton network
    By ccsparky in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 6th June 2005, 21:48
  5. Dallas DS1994 iButton CLOCK
    By NavMicroSystems in forum Code Examples
    Replies: 0
    Last Post: - 29th September 2004, 22:19

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts