Shop OBEX P1 Docs P2 Docs Learn Events
Keeping "time" using "IF" — Parallax Forums

Keeping "time" using "IF"

Zap-oZap-o Posts: 452
edited 2011-09-06 14:40 in Propeller 1
Why is this not working? I want to run code but keep 1 second time
var 
   second 

Pub time | TimeNow

    TimeNow := Cnt 
    Second := 0          
    Repeat   
       
        IF ((TimeNow += clkfreq) == 1000) ' one second 
                                TimeNow := Cnt   
                                Second += 1       
                                usb.str(string("DEBUG $F0")) 

       else 
                        'run other code

Comments

  • tonyp12tonyp12 Posts: 1,951
    edited 2011-09-01 09:29
    If think the propblem is here: TimeNow += clkfreq) == 1000

    You time it to 1/1000 of a second, so their is big chance that you miss the window.

    So try >1000

    But the next TimeNow have to be adjusted by how far over 1000 you were.
    So better of starting out from scratch with Phil's code below.
    As the right way is to take current cnt and "pre calculate" slots that are extactly a clfreq's apart.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-09-01 09:38
    Try it this way:
      next_time := cnt + clkfreq
      second := 0
    
      repeat
        if (cnt - next_time => 0)
          next_time += clkfreq
          second++
          usb.str(string("DEBUG $F0"))
        else
          'Do oither stuff.
    

    You don't want to update next_time until it increments up to or past the target value. Also, in order to keep your seconds counter from "slipping", you want to increment next_time by clkfreq rather than restarting it. The above code will do that.

    -Phil
  • Zap-oZap-o Posts: 452
    edited 2011-09-01 09:53
    Phil that code works but there are issues. Ill see if i can understand what it is that you are doing and try to make it better.

    - when i first start the code its sending debug string several times out of sync
    - its always over the time so my clock will begin to drift
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-09-01 10:06
    I thought one needed to subtract the current time from a previous time for this type of code to work correctly.
    now_time := cnt
      second := 0
     
      repeat
        if (cnt - now_time => clkfreq)
          now_time += clkfreq
          second++
          usb.str(string("DEBUG $F0"))
        else
          'Do other stuff.
    

    I think this code is rollover safe.

    Duane
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-09-01 10:06
    Zap-o,

    You may have copied a bad version of my program before I corrected it. If your IF statement includes "next_time - cnt", it's the wrong version.

    Here's my test program, which works:
    CON
    
      _clkmode      = xtal1 + pll16x
      _xinfreq      = 5_000_000
    
    OBJ
    
      sio   : "FullDuplexSerial"
    
    PUB start | next_time, second
    
      sio.start(31, 30, 0, 9600)
      next_time := cnt + clkfreq
      second := 0
    
      repeat
        if (cnt - next_time => 0)
          next_time += clkfreq
          second++
          sio.dec(second)
          sio.tx(13)
        else
          'Do oither stuff.
    

    BTW, if the "other stuff" takes longer than one second, the stuff after the IF will play catch-up to keep from losing time.

    -Phil
  • Zap-oZap-o Posts: 452
    edited 2011-09-01 10:30
    Well gents ....

    ... So far it works awesome and if I could buy a round of brews I would do do. Thanks again Phil
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-09-01 10:34
    'Glad I could help a fellow Washingtonian!
    and if I could buy a round of brews I would do do.

    If you're ever in Port Townsend, I'll see to it that you get that chance! :)

    -Phil
  • Zap-oZap-o Posts: 452
    edited 2011-09-01 10:44
    That's a deal.
  • Zap-oZap-o Posts: 452
    edited 2011-09-02 13:57
    Any ideas on how I can make this run a little bit longer with out drift? I ran it overnight and after 128 mins it began to drift +1 second (it actually increased the time by a second). After 930 minutes it was at 3 seconds over.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-09-02 14:05
    That's 53 ppm, which may be within your crystal's tolerances. You can correct for the inaccuracy by modifying the value of _xinfreq to correspond to the crystal's actual frequency. Try a value of 5_000_269. That will lengthen the time between "ticks" by the amount of over-speed that you're reporting.

    -Phil
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2011-09-02 14:57
    I have to agree with Phil, the drift is most likely due to tolerance variations of the crystal.

    At first I thought there might be a Counter roll-over issue, but the test code below doesn't show that.


    Basically the code is the same as what Phil posted, but it allows you to 'tail' the Phsa accumulator.
    at 80MHz, it should report a number close to 80000000... the fluctuations that you see are due to conditional processing branches. If there were a roll-over issue the fluctuation would be significant.
    CON
    
      _clkmode      = xtal1 + pll16x
      _xinfreq      = 5_000_000
    
    OBJ
    
      sio   : "FullDuplexSerial"
    
    PUB start | next_time, second
    
      sio.start(31, 30, 0, 9600)
      next_time := cnt + clkfreq
      second := 0
    
    
      ctra         := 0             'Clear it just in case 
      ctra[30..26] := %11111        'LOGIC ALWAYS
      frqa         := 1             'Start Counter
      phsa         := 0             'Clear Accumulator 
    
      repeat
        if (cnt - next_time => 0)
          next_time += clkfreq
          second++
          sio.dec(second)
          sio.tx(9)
          sio.dec(phsa)             'Show Accumulator
          phsa := 0                 'Clear Accumulator
          sio.tx(13)
        else
          'Do oither stuff.
    
  • Zap-oZap-o Posts: 452
    edited 2011-09-03 10:14
    Phil -
    could you clarify how you derived the numbers on this? I want to make sure I learn and not just copy and paste. How did you come up with 53 ppm and what in turn lead you to come up with 5_000_269?

    As a side note: I am using a x-tal that parallax recommends for capacitance and frequency. Its a +/- 50ppm if I recall correctly.

    Beau -
    Do you think that the string I am sending (after the second is incremented) to the computer is causing or influencing the delay? Frankly I don't think it is but I am not an expert yet.:)
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-09-03 10:53
    Your time gained +3 seconds in 930 minutes, which is 55800 seconds.
    +3 / 55800 = +53.763 x 10-6 = +53.763 ppm
    +53.763 ppm x 5 MHz = +268.8 Hz
    5_000_000 + 268.8 = 5_000_269 (rounded up)

    -Phil
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2011-09-03 10:57
    Zap-o,

    The string that you are sending should not have any effect, unless it takes longer than 1 second to send the entire string. The 'time' reference is relative to the counter, so anything that happens in-between is 're-synced' to the counter to within a reasonable time frame. meaning that from second to second, the amount of error does not compound. The difference in speed that you see is the tolerance error of the 5MHz crystal itself. There is nothing wrong with the crystal either, it's simply not spec'd to function as a precision timepiece over extended lengths of time. For that there are specialized IC's that require a precision crystal.... See this guy for as example ... DS1302 ... and the 32.768kHz crystal to go with it.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-09-03 11:03
    Even if the "other stuff" takes more than one second (up to about 26 seconds) on occasion, my code will "catch up" to the correct time.

    -Phil
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-09-03 14:12
    Many of the real time clock chips/crystals are not very accurate either (although they are probably better than the Prop). GPS units are almost inexpensive enough to use for time keeping. There's also the alternative of using a radio to listen in on the clock signal.

    Duane
  • Zap-oZap-o Posts: 452
    edited 2011-09-06 08:13
    Phil

    I think I have to set it as
    80_000_269
    
    instead of
    5_000_269
    

    Testing it today so ill let you all know.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-09-06 08:24
    What? No. You're not using an 80 MHz crystal are you?

    -Phil
  • Zap-oZap-o Posts: 452
    edited 2011-09-06 08:43
    No i am using a 5MHz xtal
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-09-06 09:22
    Then _xinfreq should be set to 5_000_269.

    -Phil
  • Zap-oZap-o Posts: 452
    edited 2011-09-06 09:47
    Yes I did that and the time was way off. I am running it a the 80_000_269 and its working great so far. I am still testing the drift over time issue but looks like this may work.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-09-06 10:12
    Are you sure you're setting _xinfreq and not _clkfreq? You should be setting _xinfreq to 5_000_269. Don't set _clkfreq.

    Do this:
    CON 
      _clkmode = xtal1 + pll16x 
      _xinfreq = 5_000_269
    
    

    -Phil
  • Zap-oZap-o Posts: 452
    edited 2011-09-06 12:53
    Ahhh that is the difference. I do not want to mess up the rest of the program so I just did this.
    CON                                                        
      _clkmode = xtal1 + pll16x                            
      _xinfreq = 5_000_000
    
    Var
    Long second
    
    Pub Main_Loop  |  Time
    
      second := 0
      Time  := Cnt + 80_000_269  
            
      Repeat              
            IF (Cnt - Time => 0)           
                                    Time += 80_000_269  
                                    Second++ 
                                    
          'do other stuff  that is under one second 
    
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-09-06 14:40
    I'm not sure how that would mess up the rest of the program, except to give it a more accurate value for clkfreq. In any event, 80_000_269 is just wrong, based on your figures. You would have to multiply the 269 by the PLL multiplier (16) to get the right correction value to add to 80_000_000. But forget that! My recommendation is definitely to use the _xinfreq method instead. It will not mess up your program but make all your timings (including video and serial I/O, if you use them) more accurate.

    -Phil
Sign In or Register to comment.