Shop OBEX P1 Docs P2 Docs Learn Events
Capture Time, day, month and weekday in RTC — Parallax Forums

Capture Time, day, month and weekday in RTC

RTC_DEMO.spin Version 1.01
│ Author: Mathew Brown │
│ Copyright (c) 2008 Mathew Brown │
RealTimeClock.spin Version 1.01

Hello all!

How someone can capture data in the refered objects to triger events in specific date in timeline dayly or weekly or monthly?

Thanks in advance.

Comments

  • JonnyMacJonnyMac Posts: 8,923
    edited 2023-02-01 22:13

    You should post a link to that code -- better yet, given its age, post the code.

  • masselonmasselon Posts: 51
    edited 2023-02-02 03:57
    {
    
    ┌──────────────────────────────────────────┐
    │ RTC_DEMO.spin            Version 1.01    │
    │ Author: Mathew Brown                     │               
    │ Copyright (c) 2008 Mathew Brown          │               
    │ See end of file for terms of use.        │                
    └──────────────────────────────────────────┘
    
    Demonstation program, to show the use of the "RealTimeClock.spin" object
    Sends time, and date data to prop-plug debug port, on clock update, every second.
    
    ------------------------------------------------------  
    Revision 1.01 changes:-
    Added day of week functionality to demonstration   .... To reflect updated RTC object.
    ------------------------------------------------------
    
    }}
    
    CON ''System Parameters
    
      _CLKMODE = XTAL1 + PLL16X                             {Clock type HS XTAL, + P.L.L. with 16x multiplier}
      _XINFREQ = 5_000_000                                  {Crystal frequency 5.000Mhz}       
      '(16*5Mhz) = 80.000Mhz clock
    
      _STACK = 1024                                         {reserve 1K of longs for stack... overkill!!}
    
    CON ''Date string return format type constants..
    
      UkFormat = 0                                          'False (zero)
      UsaFormat = 1                                         'True (non-zero)
    
    VAR
    
      byte Counter
      byte Secs                                             'Seconds passed
    
    OBJ
    
      RTC: "RealTimeClock"
      CommPort : "FullDuplexSerial" 
    
    PUB Main  'Real time clock demonstration
    
      'Start debug comm interface, using prop-plug
      CommPort.Start(31, 30, 0, 115200)
    
      'Start Real time clock
      RTC.Start
    
      'Preset time/date... nice demostration of rollovers..
      RTC.SetTime(23,59,50)                                 '10 seconds to midnight
      RTC.SetDate(31,12,07)                                 'New years eve, 2007
    
    '-------------------------------------------------------------------------------------------------------
    '-------------------------------------------------------------------------------------------------------
    
      repeat
    
        'Wait for next second to pass, rather than constantly sending time/date to debug comms
        Secs := RTC.ReadTimeReg(0)                          'Read current second
        repeat while Secs == RTC.ReadTimeReg(0)             'Wait until second changes
    
    '-------------------------------------------------------------------------------------------------------
    
        'Spit out start of message to terminal
        CommPort.Str(String("Time:"))
    
        'Spit out string time to terminal
        CommPort.Str(RTC.ReadStrTime)
    
        'Spit out more of message to terminal
        CommPort.Str(String("  ..  Date:"))
    
         'Spit out string day of week to terminal
        CommPort.Str(RTC.ReadStrWeekday)
    
         'Spit out padding space
        CommPort.Tx(" ")
    
        'Spit out string date to terminal ... as UK date formatted string
        CommPort.Str(RTC.ReadStrDate(UkFormat))  '<- Change "UkFormat" to "UsaFormat", for USA date formatted string
    
    '-------------------------------------------------------------------------------------------------------
    
        'Spit out raw data message to terminal
        CommPort.Str(String("  ..  Raw data: "))
    
        'Spit out time keeping registers raw data
        Repeat Counter from 0 to 6
    
          CommPort.Dec(RTC.ReadTimeReg(Counter))
    
          If Counter == 6
            Commport.tx(13)   '<CR> to terminate transmitted line 
          else
            CommPort.Tx(",")  'Comma seperator
    
    
    *******===========************
    
    {
    
    ┌──────────────────────────────────────────┐
    │ RealTimeClock.spin       Version 1.01    │
    │ Author: Mathew Brown                     │               
    │ Copyright (c) 2008 Mathew Brown          │               
    │ See end of file for terms of use.        │                
    └──────────────────────────────────────────┘
    
    Real time clock object/methods.
    
    Starts a real time clock in a new cog.
    This clock tracks both time, and date, and includes days in month/leap year day corrections.
    
    Time/date can be set using the following...
    
    1) Via direct writes to timekeeping registers
    2) Via time & date setting methods
    3) Via loading with a 32 bit packed Microsoft format time
    
    Time/date can be read using the following...
    
    1) Via direct reads from timekeeping registers
    2) Via return as strings representing time / date
    3) Via return of a 32 bit packed Microsoft format time
    
    ------------------------------------------------------
    Revision 1.01 changes:-
    Added day of week funtionality.
    ------------------------------------------------------  
    }}
    
    VAR
    
      ''Global vars...
      long Cog                                              'Cog issued tracking
      long RtcStack[32]                                     'Stack for RTC object in new cog
    
      'The following must be contigious...
      '[
      Byte LclRtc[7]                                        'Local real time clock counters
      Byte TimeDate[7]                                      'Time/date return registers
      ']
    
    
    PUB Start:Success 'Start the RTC object in a new cog...
    
      If not cog                                            'RTC not already started
        Success := Cog := Cognew(RtcMain(@LclRtc),@RtcStack)  'Start in new cog
    
    PUB Stop 'Stops the Real Time Clock object, frees a cog.
    
      If Cog
        Cogstop(Cog)
    
    PUB ReadTimeReg(Index):Value 'Allows calling object to query timekeeping registers, individually
    
    { Index = 0, indexes seconds       .. 'value' in range 0 to 59
      Index = 1, indexes minutes       .. 'value' in range 0 to 59
      Index = 2, indexes hours         .. 'value' in range 0 to 23
      Index = 3, indexes days          .. 'value' in range 1 up-to 31 (month dependant)
      Index = 4, indexes months        .. 'value' in range 1 to 12
      Index = 5, indexes years         .. 'value' in range 0 to 99    (00 = 2000.... 99 = 2099)
      Index = 6, indexes day of week   .. 'value' in range 1 to 7     (1 = Sunday.... 7 = Saturday)       
    }
    
      Value := byte[@TimeDate][Index]                       'Read data from double buffered read registers
    
      If Lookdown(Index:3,4,6)                              'Adjust 0 indexed days/months/day of week, to 1 indexed
        Value++
    
    PUB WriteTimeReg(Index,Value) 'Allows calling object to write to timekeeping registers, individually
    
    { Index = 0, indexes seconds       .. 'value' in range 0 to 59
      Index = 1, indexes minutes       .. 'value' in range 0 to 59
      Index = 2, indexes hours         .. 'value' in range 0 to 23
      Index = 3, indexes days          .. 'value' in range 1 up-to 31 (month dependant)
      Index = 4, indexes months        .. 'value' in range 1 to 12
      Index = 5, indexes years         .. 'value' in range 0 to 99    (00 = 2000.... 99 = 2099)
      NOTE:- WEEKDAY IS CALCULATED AUTOMATICALLY, BASED UPON TODAYS DATE    
    }
    
      If Lookdown(Index:3,4)                                'Adjust 1 indexed days/months, to zero indexed
        Value--
    
      byte[@LclRtc][Index] := Value                         'Write data to master time keeping registers
    
    PUB SetTime(Hours,Minutes,Seconds) 'Set time
    'Has method dependency 'WriteTimeReg'
    
      WriteTimeReg(2,Hours)                                 'Write hours data
      WriteTimeReg(1,Minutes)                               'Write minutes data
      WriteTimeReg(0,Seconds)                               'Write seconds data
    
    PUB SetDate(Day,Month,Year) 'Set Date
    'Has method dependency 'WriteTimeReg'
    
      WriteTimeReg(3,Day)                                   'Write day data
      WriteTimeReg(4,Month)                                 'Write month data
      WriteTimeReg(5,Year)                                  'Write year data
    
    PUB ReadStrDate(UsaDateFormat):StrPtr 'Returns pointer, to string date,either as UK/USA format
    'Has method dependency 'ReadTimeReg' & 'IntAscii'   
    
      StrPtr := String("??/??/20??")                        'Return string
    
      If UsaDateFormat
    
        'TRUE .... USA format date string
        IntAscii(StrPtr,ReadTimeReg(4))                     'Overwrite first two chars in string with month number 01-12
        IntAscii(StrPtr+3,ReadTimeReg(3))                   'Overwrite next two chars, after "/" with day number 01-31
        IntAscii(StrPtr+8,ReadTimeReg(5))                   'Overwrite next two chars, after "20" with year number 00-99
    
      else
    
        'FALSE .... UK format date string
        IntAscii(StrPtr,ReadTimeReg(3))                     'Overwrite first two chars in string with day number 01-31
        IntAscii(StrPtr+3,ReadTimeReg(4))                   'Overwrite next two chars, after "/" with month number 01-12
        IntAscii(StrPtr+8,ReadTimeReg(5))                   'Overwrite next two chars, after "20" with year number 00-99
    
    PUB ReadStrTime:StrPtr 'Returns pointer, to string time
    'Has method dependency 'ReadTimeReg' & 'IntAscii'
    
      StrPtr := String("??:??:??")                          'Return string  
    
      IntAscii(StrPtr,ReadTimeReg(2))                       'Overwrite first two chars in string with hour number 00-23
      IntAscii(StrPtr+3,ReadTimeReg(1))                     'Overwrite next two chars, after "/" with minutes number 00-59
      IntAscii(StrPtr+6,ReadTimeReg(0))                     'Overwrite next two chars, after "/" with seconds number 00-59
    
    PUB ReadStrWeekday:StrPtr 'Returns pointer, to a 3 letter string, representing the day of the week
    
      StrPtr := @DayOfWeek + (4* Byte[@TimeDate][6]) 
    
    PUB ReadMsTime:MsTime  'Returns current time & date, as compressed 32 BIT Microsoft Time format
    'Has method dependency 'ReadTimeReg'
    
      ''Create 32 bit packed Microsoft format date/time
      MsTime := ((ReadTimeReg(5)+20)<<25)                   'Bits 31 - 25 are years since 1980
      MsTime += (ReadTimeReg(4)<<21)                        'Bits 24 - 21 are month (1 to 12)
      MsTime += (ReadTimeReg(3)<<16)                        'Bits 20 - 16 are day (1 to 31)
      MsTime += (ReadTimeReg(2)<<11)                        'Bits 15 - 11 are hour (0 to 23)
      MsTime += (ReadTimeReg(1)<<5)                         'Bits 10 - 5 are minute (0 to 59) 
      MsTime += (ReadTimeReg(0)>>1)                         'Bits 4 - 0 are seconds/2 (0 to 30)
    
    PUB WriteMsTime(MsTime) 'Sets time/date registers using compressed 32 BIT Microsoft Time format
    'Has method dependency 'WriteTimeReg'
    
      WriteTimeReg(0,(2*MsTime) & %11111 )                  'Extract seconds from MsTime & write to time register
      WriteTimeReg(1,(MsTime>>5) & %111111)                 'Minutes
      WriteTimeReg(2,(MsTime>>11) & %11111)                 'Hours
      WriteTimeReg(3,(MsTime>>16) & %11111)                 'Days
      WriteTimeReg(4,(MsTime>>21) & %1111)                  'Months
      WriteTimeReg(5,(MsTime>>25)-20)                       'Years
    
    
    PRI IntAscii(Pointer,Number) 'Low level conversion of integer 00-99, to two ASCII chars...
    
      byte[Pointer][0] := (Number/10) +"0"                  'First character is tens (division by 10, + ASCII offset)
      byte[Pointer][1] := (Number//10) +"0"                 'Second character is units (modulus 10 + ASCII offset)
    
    PRI RtcMain(Pointer)|SysCnt,Counter,LapsedDays 'Timekeeping method.. runs in a new cog
    'All timekeeping registers are zero indexed!!!
    
      SysCnt := Cnt                                         'Set timer reference
    
      repeat                                                'Do forever
    '-------------------------------------------------------------------------------------------------------
    'Wait until 1 second has passed
    
        SysCnt += ClkFreq                                   'Increment timer reference count + 1 second
        waitcnt(SysCnt)                                     'Wait for 1 second to expire
    
    '-------------------------------------------------------------------------------------------------------
    'Make leap year correction to month length lookup table
    
        If (Byte[Pointer][5]&3)
    
          byte[@MonthLen][1] := 28 'Modify table data for February, for not Leap year
    
        else
    
          byte[@MonthLen][1] := 29 'Modify table data for February, for Leap year
    
    '-------------------------------------------------------------------------------------------------------
    'Modify rollover table, so that days rollover entry is correct for days in this month...
    
        byte[@RollOvers][3] := byte[@MonthLen][ Byte[Pointer][4] ] 'Modify table data for month rollover data
    
    '-------------------------------------------------------------------------------------------------------
    'Increment time
    
        repeat Counter from 0 to 5                          '6 time/date fields to possibly increment/rollover
    
          ++Byte[Pointer][Counter]                          'Increment time
          Byte[Pointer][Counter] //= byte[@RollOvers][Counter] 'Perform modulus (rollover)
    
          If Byte[Pointer][Counter]                         'Test for rolled-over to zero...   If not rolled-over...
            quit                                            'Exit repeat loop
    
    '-------------------------------------------------------------------------------------------------------
    'Calculate the day of the week, based upon todays date
    
       LapsedDays := 6                                      '1st January 2000, was a Saturday
    
       LapsedDays +=  Byte[Pointer][5] * 365                'Add 365 days, for each full year passed
       LapsedDays += (Byte[Pointer][5] +3 )/4               'Peform leap year corrections...
    
       Repeat Counter from 0 to Byte[Pointer][4]            'Add days for full months passed this year
         LapsedDays += (Byte[@MonthIdx][Counter])           '... Using month length lookup table (previously leap year corrected!!)  
    
       LapsedDays +=  Byte[Pointer][3]                      'Add current day of this month
    
       Byte[Pointer][6] := LapsedDays // 7                  'Write data, modulus 7 ... 7 days in a week
    
    '-------------------------------------------------------------------------------------------------------
    'Write double buffered time/date data, for use by main object
    
        'Copy double buffered data
        Bytemove((Pointer+7),Pointer,7)                     'Copy data
    
    
    
    
    DAT
    
      '[ The following must be contigous
      MonthIdx  byte 0                                      'January .. 0 days to add to lapsed days, for day of week calculation
      MonthLen  byte 31,28,31,30,31,30,31,31,30,31,30,31    'Month lengths lookup table
      ']
    
      RollOvers byte 60,60,24,31,12,100                     'Time/date rollover limits sec,min,hrs,days,month,year
      DayOfWeek byte "Sun",0,"Mon",0,"Tue",0,"Wed",0,"Thu",0,"Fri",0,"Sat",0
    
    DAT
         {<end of object code>}
    
    {{
    
  • evanhevanh Posts: 15,187
    edited 2023-02-02 00:28

  • JonnyMacJonnyMac Posts: 8,923
    edited 2023-02-02 06:26

    You should post a link to that code -- better yet, given its age, post the code.

    My fault for not being more specific; embedding snippets okay (please learn to use code block in the format menu), but copy-and-paste of the whole file, especially without code formatting is not the way to go. See Evan's post on how to attach files.

    That said, I waded through. You could create trigger values in the mstime format provided by then object, the read the current rtc in the format and do a simple compare. It should be easy.

    pub pack_mstime(yr, mo, dy, hr, mn, sc) : result
    
    ' YYYYYYY_MMMM_DDDDD__hhhhh_mmmmmm_sssss
    
      yr += 20                                                      ' make relative to 1980  
    
      result := yr << 25
      result |= mo << 21
      result |= dy << 16
      result |= hr << 11
      result |= mn <<  5
      result |= sc >>  1                                            ' 0 to 29 in 2-sec increments 
    

    The bigger question becomes.... what do you do on a power loss when your RTC is running in a cog? How does it get reset correctly when power is restored? You might consider an external RTC module that has a battery back-up. These are typically I2C and can usually share the EEPROM I2C pins.

  • Hi @masselon
    I've added 3 backticks around your code snippet for you. That enables code view. If you edit your own post above, you can see what I did so that you'll know next time.

    If you need any more help with the feature, please ask anytime.

  • @ JonnyMac
    "That said, I waded through. You could create trigger values in the mstime format provided by then object, the read the current rtc in the format and do a simple compare. It should be easy."

    A question:

    Since the PUB Main execute a infinite loop, how do I do to make the code skip the loop to execute the new Pub (pack_mstime (yr, mo, dy, hr, mn, sc) : result) and compare if hr, e.g, is = 20?

    Thanks

  • JonnyMacJonnyMac Posts: 8,923
    edited 2023-02-03 16:28

    You would need to use pack_mstime() before your loop to create trigger values. Inside your loop you would test by calling the current time in MS format and comparing it to your triggers. Note that the MS format has a 2-second resolution, so you need to have some kind of flag that tells you not to use that flag again until you have a real retrigger event. These things take planning and thought. I wrote code for a gentleman whose elderly mom needed reminders to take medicine at specific times of day. As I had created a P1-based WAV player for EFX-TEK, we adapted it to an audio reminder by adding an RTC module and creating triggers in a table that the software accessed.

  • Great Great
    Done!!!!

    Thank you Jon McPhalen

Sign In or Register to comment.