SPIN Code for scheduling an event every 10 minutes based upon RTC time?

I am putting the final touches on a pump controller for a pond and have one last feature I need to add. Currently, it sets the pump speed based upon an array of 24 speeds (one for each hour of the day) and I am simply using the hour to set the speed according to the array. There is a scenario where the pump will change the speed on it's own as part of a backwash process, but after the backwash, the pump always returns to low speed. If this happens at the beginning of an hour that should be running on high, than the pump will run at low for most of the hour. So, the thought is to send the speed every 10 minutes so if a backwash occurred, the pump only runs on low for a max of 10 minutes.

Is there an easy way to divide the "minutes" variable by 10 and if it returns a whole value, trigger an event? Then I am sending the speed every 10 minutes for the corresponding hour.


  • 11 Comments sorted by Date Added Votes
  • JasonDorieJasonDorie Posts: 1,930
    edited April 2017 Vote Up0Vote Down
    Minutes modulo 10

    In C: result = minutes % 10
    In Spin: result := minutes // 10

    If the result is zero, (and previous result was not) trigger the event.
  • AribaAriba Posts: 2,178
    edited April 2017 Vote Up0Vote Down
    Make this Test in a loop that is faster than 1 minute
      if minutes // 10 == 0   'first minute of every 10 minutes?
        if flag              'not sent yet?
          'Send Speed here
          flag := 0          'now it's sent
        flag := 1
  • Thanks guys. I had looked at the modulus command years ago but couldn't wrap my head around it and haven't had a use for it, or so I thought. Looks like an easy way to wrap this up!
  • Tracy AllenTracy Allen Posts: 6,199
    edited April 2017 Vote Up0Vote Down
    Watch out though, if your "minutes" variable is in BCD format as typical of RTCs. Modulo //10 will not get you the result you want, unless you convert the BCD to flat binary first. For example $30 minutes in BCD is 48 in decimal, and 48 // 10 = 8.

    If you want to divide your hour up into six minute intervals, then you can directly use //6 with either the BCD or the flat number. Math fact: If a number is evenly divisible by 6, its BCD representation is also evenly divisible by 6. For example, $48 minutes is 72 in decimal, and both 48 and 72 as decimal are divisible by 6.

    My preference is to convert the entire BCD time string to minutes or seconds past midnight, 0 to 1439 in the case of minutes. Then you can modulo that with any convenient factor that divides 1440 evenly. 10 minutes, 6 minutes, 15 minutes, whatever.
  • Is it not possible to let the backwash process do the lookup when it ends?
    Just a thought!
    Yes Frida is my watchdog!
  • Excellent point, but unfortunately, I don't have access to much of the existing controller since it is sealed and under warranty. If I could open it, I know I could tap in to the signals that manage the backwash. I only have access to the 3 speed terminals for dry contact remote switches. I do have plenty of Dwyer pressure sensors that may get installed as a future phase that would allow me to determine the speed and direction based upon pressure at 3 key points in the system. However, the client has not determined if they want to go to that phase yet. The main purpose of adding those components is to allow automatic shutdown of a UV light embedded into the line in case there is flow loss that would cause the light to overheat.
  • Can you mask off bit 3 or 4 of the minutes and send the speed if it is zero? IOW does it matter if the speed is sent a little more or less frequently?
    In science there is no authority. There is only experiment.
    Life is unpredictable. Eat dessert first.
  • Peter JakackiPeter Jakacki Posts: 6,903
    edited April 2017 Vote Up0Vote Down
    I normally have a cog running background timers including a soft RTC, plus raw milliseconds runtime etc. The advantage of always running a soft RTC is that this can be loaded up from a real RTC or network but the application only needs to read the soft RTC. However in Tachyon I would just set an ALARM action for 600,000 milliseconds in this case as timer structures are linked dynamically when first invoked. For instance:
    --- define a timer variable
    TIMER pumptimer
    --- use the runtime address of RUNFAST as the alarm action
    ' RUNFAST pumptimer ALARM
    --- Set the timer to count down 10 mins
    600,000 pumptimer TIMEOUT

    In Spin I have done something similar although simpler. The background cog has a WAITCNT for 1ms and checks a set of timers counting them down if they are set and when they reach zero they can execute an ALARM function etc. You can of course synchronize this to an RTC if need be but that would only need to happen once at start-up and maybe resynch at midnight.
    Tachyon Forth - compact, fast, forthwright and interactive
    Tachyon Forth News Blog
    Brisbane, Australia
  • What Peter suggests is what I usually do as well. Having a dedicated clock cog is very convenient.
  • JonnyMac has posted a timer object that may be of use for this.
    In science there is no authority. There is only experiment.
    Life is unpredictable. Eat dessert first.
  • JonnyMacJonnyMac Posts: 5,977
    edited April 2017 Vote Up0Vote Down
    You can even create an embedded object like this:
      long  bcog
      long  bstack[32]
      long  millis
      byte  scs
      byte  mns
      byte  hrs
      byte  day
    pri background | t
      millis := 0                                                   ' clear millis
      bytefill(@scs, 0, 4)                                          '  and rtc vars
      t := cnt
        waitcnt(t += MS_001)
    pri update_rtc
      if ((++millis // 1000) == 0)                                  ' update millis
        if (++scs == 60)
          scs := 0
          if (++mns == 60)
            mns := 0
            if (++hrs == 24)
              hrs := 0
              if (++day == 7)
                day := 0
    Many of my projects have a background cog that runs at 1ms; this lets me keep a millis value that I can use for differential timing (where cnt would not be convenient). Even in Spin one can do a lot of work in 1ms, so other background processes can be added to the background loop.
    Jon McPhalen
    Hollywood, CA
    It's Jon or JonnyMac -- please do not call me Jonny.
Sign In or Register to comment.