Welcome to the Parallax Discussion Forums, sign-up to participate.

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

Posts: 2,724
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.

• Posts: 1,930
edited April 2017
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.
• Posts: 2,178
edited April 2017
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
else
flag := 1
```
• Posts: 2,724
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!
• Posts: 6,199
edited April 2017
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.
• Posts: 121
Is it not possible to let the backwash process do the lookup when it ends?
Just a thought!
Yes Frida is my watchdog!
• Posts: 2,724
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.
• Posts: 7,780
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.
• Posts: 6,903
edited April 2017
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
TACHYON DEMONSTRATOR
Brisbane, Australia
• Posts: 178
What Peter suggests is what I usually do as well. Having a dedicated clock cog is very convenient.
• Posts: 7,780
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.
• Posts: 5,977
edited April 2017
You can even create an embedded object like this:
```var

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
repeat
waitcnt(t += MS_001)
update_rtc

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.