Shop OBEX P1 Docs P2 Docs Learn Events
Clock question — Parallax Forums

Clock question

Bobb FwedBobb Fwed Posts: 1,119
edited 2008-07-01 21:08 in Propeller 1
I am trying to setup a simple clock so every hour I can setup an event.
Also, I want a variable which tracks total number of seconds the program has run.

I have a feeling it has to do with the cnt register rolling over after 32 bits. But there has to be some way to make it work.
It freaks outs after (I assume) cnt gets too high. So I tried to fix it with the "curclk =< (4294967295 - clkfreq)", but now it seems to just stop counting all together. I figured it would roll over and continue once that second had passed. Can someone explain what may be happening.

This code is extracted out of a program I wrote (not exactly, so I am sorry if it doesn't function as is).
CON

  _CLKMODE    = XTAL1 + PLL8X                        ' 10MHz clock
  _XINFREQ    = 5_000_000                            ' 5MHz Crystal

VAR

  long on_seconds                                    ' total seconds since last reboot (max of 136 years -- I think)

PUB Clock | minutes, seconds, time, curclk           ' main program to get, display, and adjust frequencies
  time := cnt + clkfreq                              ' get next time marker
  on_seconds := 0                                   
  seconds := 0
  minutes := 0
  repeat                                             ' repeat forever
    curclk := cnt
    if (curclk => time) AND (curclk =< (4294967295 - clkfreq)) ' if it has been a second
      on_seconds++
      seconds++
      time := time + clkfreq                         ' move marker ahead one second
      if seconds => 60                               ' if it has been a minute
        minutes++
        seconds := 0
        if minutes => 60                             ' if it has been an hour
          minutes := 0
          ''EVENT

Comments

  • RaymanRayman Posts: 14,162
    edited 2008-07-01 00:32
    just enter a loop like this:

    secs:=0 
    cnt1:=cnt
    repeat 
      repeat while (cnt-cnt1)<clkfreq 
      cnt1+=clkfreq 
      secs++
    
  • JamesxJamesx Posts: 132
    edited 2008-07-01 02:33
    If you don't mind a slightly more complicated solution, here is part of a project I've been working on that displays time on the little OLED-96 unit, which I'm using as a watch of sorts. In one cog I toggle a pin every second, and then in another cog I wait for that pin to change, upon which a counter is incremented and turned into a Hr:Min:Sec display. It's not totally accurate, but it's not bad (~ few seconds per hour).

    Here's the first part, that toggles a pin (PinB) every second. It also toggles PinA 10 times a second, although I don't currently use that part.
    This code was derived from a Propeller application note. Also, note that this assumes a 8 MHz osc. and a PLL of 8X.

    J

    PUB Cycle(PinA, PinB)
      ctra    := %00100_000 << 23 + 1 << 9 + PinA  'Establish mode and APIN (BPIN is ignored) 
      frqa    := 1366        'adjusted 6 clicks up for 1 sec slow over 5 min 
      dira[noparse][[/noparse]PinA] := 1                              'Set APIN to output 
      dira[noparse][[/noparse]PinB] := 1
      repeat
        repeat 10                                       'go thru 10 times, making for one sec
            waitpeq(|< PinA, |< PinA, 0)  'Wait for Pin to go high.  
            waitpne(|< PinA, |< PinA, 0)  'Wait for Pin to go low   
        !outa[noparse][[/noparse]PinB]                                    'PinB toggles every second
        !outa[noparse][[/noparse]PinB]  
    
    
  • Mike GreenMike Green Posts: 23,101
    edited 2008-07-01 03:05
    Why not use the system counter? It gets incremented every system clock and contains the absolute time since the last reboot in system clocks modulo 2**32. You can easily have a cog that waits for the next second, then updates an HH:MM:SS clock like
    VAR byte hours, minutes, seconds
    
    PUB clock : time
       time := cnt
       repeat
          waitcnt(time := time + clkfreq)
          if seconds++ == 60
             seconds~
             if minutes++ == 60
                minutes~
                if hours++ == 24
                   hours~
    
  • RaymanRayman Posts: 14,162
    edited 2008-07-01 09:34
    Using waitcnt would work too. But, you'd have to dedicate a cog to the effort. If you use the "repeat while" way, you can do other processing within the loop...
  • Erik FriesenErik Friesen Posts: 1,071
    edited 2008-07-01 14:37
    I have used the counters for a similar purpose.· It doesn't tie up the cog.· It is something like this.· It should be correct unless you do something that takes over 53 seconds.

    pub whatever|seconds
      ctra:=%00100<<26 'note please check this it may be incorrect
      phsa:=0
      frqa:=1
     
      repeat
     
        dosomethingelse
        if phsa>80_000_000
          seconds++
          phsa-=80_000_000
     
     
     
     
     
     
    pub dosomethingelse
     
     
    
  • Ken PetersonKen Peterson Posts: 806
    edited 2008-07-01 15:19
    If you are actively modifying phsa in SPIN, wouldn't you run into clock drift due to the fact that phsa is changing while you modify it? You may have to adjust the 80_000_000 value to compensate. Another way would be to change the value you are comparing phsa against rather than changing phsa.

    repeat
      dosomethingelse
      if testvalue - phsa < 80_000_000
        seconds++
        testvalue += 80_000_000
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2008-07-01 18:29
    Here is what I am using now, seems to works great, doesn't hog a cog either (if you plan on using the loop). It's a combo of some of things above; I also added tracking of hours and days:
    VAR
    
      long on_seconds                                    ' total seconds since last reboot (max of 136 years)
      byte hours, minutes, seconds
      word days                                          ' total days since last reboot
    
    PUB Main | time
      time := cnt                                        ' get next time marker
      on_seconds~                                   
      seconds~
      minutes~
      hours~
      days~
      repeat                                             ' repeat forever 
        if (cnt - time) => clkfreq                       ' if it has been a second
          on_seconds++
          seconds++
          time += clkfreq
          if seconds => 60                               ' if it has been a minute
            minutes++
            seconds~
            if minutes => 60                             ' if it has been an hour
              hours++
              minutes~
              if hours => 24                             ' if it has been a day
                days++
                hours~
    
    
  • RaymanRayman Posts: 14,162
    edited 2008-07-01 18:49
    I've done something like this before (just rearranging your code a bit):
    VAR
    
      long on_seconds                                    ' total seconds since last reboot (max of 136 years)
      byte hours, minutes, seconds
      word days                                          ' total days since last reboot
    
    PUB Main | time
      time := cnt                                        ' get next time marker
      on_seconds~                                   
      seconds~
      minutes~
      hours~
      days~
      repeat                                    ' repeat forever 
        DoSomeStuff    'Do the main things you want
        UpdateTime     'Update the time
     
    PRI UpdateTime 
      repeat while (cnt - time) => clkfreq                       ' if it has been a second
          on_seconds++
          seconds++
          time += clkfreq
          if seconds => 60                               ' if it has been a minute
            minutes++
            seconds~
            if minutes => 60                             ' if it has been an hour
              hours++
              minutes~
              if hours => 24                             ' if it has been a day
                days++
                hours~
    
    

  • Harrison.Harrison. Posts: 484
    edited 2008-07-01 19:51
    Desilva posted a snippet on how to use two cog counters to get a 1-second-tick counter. It works quite well and makes the code a lot easier to work with.

    PUB setupTimer(commPin)
      ctra := constant(%00100<<26) + commPin                ' set NCO mode
      frqa := POSX / CLKFREQ * 2                            ' one second
      ctrb := constant(%01010<<26) + commPin                ' set ctrb to POSEDGE detect
      frqb := 1
    
    PUB getTimer
      return phsb                                           ' timer value is stored in phsb (seconds)
    
    



    Just set commPin to an unused pin within your cog. Call getTimer to get the seconds since you called setupTimer. This works great for things like unix timestamps, etc. In fact, I think there is an object in the OBEX that provides unix timestamp style date functions.
  • RaymanRayman Posts: 14,162
    edited 2008-07-01 21:08
    that's a very neat idea!
Sign In or Register to comment.