timers
10gigbill
Posts: 79
in Propeller 1
have been away from the prop for several years. I need 3 separate timers running
minutes to hours, to flag my main program (that will be busy doing other things).
Such as I want to set timer 1 to run x minutes and then set a flag. Timer 2 and 3, similar tasks.
while main program is running and checks for the flags..Should be a simple thing... but ???
' blink...test floor heat control wiring... and timing
' THIS IS WORKING AS IS... chek waits to be called
'*************************************************************************************************
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
K = 2
High = 1
Low = 0
VAR
byte W
long stack1 [40]
byte Q
Pub main
DirA[0..7] := $FF '0-7 is out
dira[8..15] := $FF 'port 8-15 dir is out
dira[16..23] := $FF 'port 16-23 is out
W := 10
cognew (chek (W), @stack1)
Q := 0
repeat while Q == 0 'blink p-6 until times up
waitcnt(10_000_000 + cnt)
outa[6] := 1
waitcnt(10_000_000 + cnt)
outa[6] := 0
Q := 0
chek (5)
repeat while Q == 0 'this never runs
waitcnt(10_000_000 + cnt)
outa[4] := 1
waitcnt(10_000_000 + cnt)
outa[4] := 0
Pub chek (R) 'time routine R times
DirA[0..7] := $FF '0-7 is out
dira[8..15] := $FF 'port 8-15 dir is out
repeat R
waitcnt(70_000_000 + cnt) 'delay 1 sec
outa[1] := 1 'blink p 1
waitcnt(10_000_000 + cnt)
outa[1] := 0
Q := 1 'flag to show times up
return
minutes to hours, to flag my main program (that will be busy doing other things).
Such as I want to set timer 1 to run x minutes and then set a flag. Timer 2 and 3, similar tasks.
while main program is running and checks for the flags..Should be a simple thing... but ???
' blink...test floor heat control wiring... and timing
' THIS IS WORKING AS IS... chek waits to be called
'*************************************************************************************************
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
K = 2
High = 1
Low = 0
VAR
byte W
long stack1 [40]
byte Q
Pub main
DirA[0..7] := $FF '0-7 is out
dira[8..15] := $FF 'port 8-15 dir is out
dira[16..23] := $FF 'port 16-23 is out
W := 10
cognew (chek (W), @stack1)
Q := 0
repeat while Q == 0 'blink p-6 until times up
waitcnt(10_000_000 + cnt)
outa[6] := 1
waitcnt(10_000_000 + cnt)
outa[6] := 0
Q := 0
chek (5)
repeat while Q == 0 'this never runs
waitcnt(10_000_000 + cnt)
outa[4] := 1
waitcnt(10_000_000 + cnt)
outa[4] := 0
Pub chek (R) 'time routine R times
DirA[0..7] := $FF '0-7 is out
dira[8..15] := $FF 'port 8-15 dir is out
repeat R
waitcnt(70_000_000 + cnt) 'delay 1 sec
outa[1] := 1 'blink p 1
waitcnt(10_000_000 + cnt)
outa[1] := 0
Q := 1 'flag to show times up
return
Comments
Spin is not ready for P2 yet, and we do counter thing differently, as well as setting the clock. P2 has a 64 bit clock counter too.
Please use the 'C' code forum attribute in order to preserve the spacing/indent of your code. As it stands right now it is hard to know what you have inside loops or not.
I've posted your code below using the 'C' code forum attribute. See if I have it correctly indented. In its current form it does appear to blink LEDs as you expect. The reason why the p4 LED never blinks is that you invoked the 'chek' routine again after the first loop finishes. The 'chek' loop sets Q equal 1, so the p4 loop never runs because Q is 1.
Note: The first invocation of 'chek' by cognew only runs the specified number of times then stops. The second invocation runs in the same cog as your main code. I don't know if that is what you wanted or not...
I am using the prop to control 2 pumps in a floor heat system. I would like to have 4 timers
running in 4 cogs, so they can all run independently. If a thermostat calls for heat in zone 1
then that pump will run for x time and not be allowed to run again for y time.. same for pump 2.
I would like the main program to run, looking at thermostat inputs and time switches, and
call the timers for the different tasks. I just want to start a timer like an alarm clock, and
have it set a flag when time is up... all causing my hair to turn gray !
Since you are talking about a heating system where changes happen relatively slowly you could do that very simply as Mike suggests and have the code that sets the time for each of the counters set a flag that indicates if the pump is allowed or not allowed to pump.
Given that at any given time you would only have 0, 1, or 2 timers running, it sounds like you could just launch 2 cogs, each having it's own thermostat input, 'run' time, 'no-run' time, and output pin.
Each pump cog starts with a WAITPEQ (or WAITPNE) to wait for the thermostat trigger, then:
starts the pump
waits for 'run' time to expire
stops the pump
waits for 'no-run' time to expire
then loops back to the idle state (WAITPEQ or WAITPNE)
Each pump cog takes responsibility for its own 'run', 'no-run', and 'idle' state, leaving the main program free to do other things. If you use global variables to hold the 'run' and 'no-run' durations then the main program can adjust them without restarting the pump cog program.
If your main program wants to know if a pump is running it can monitor the relevant pump control pin.
Does your main program need to know if the pump cog is in the 'no-run' window?
If so, then you can have the pump cogs set flags in HubRAM, or you could use locks set and cleared by each pump cog to indicate its 'no-run' state, with the main program releasing any lock immediately if it manages to set it.
If the main program just needs to know if the pump cog is in the timing phase ('run' or 'no-run' state), then it would be sufficient to have the pump cog clear the flag or wait until it secures the lock, then run the whole timing cycle before setting the flag or releasing the lock.
You can even have the main program override the pump cog without restarting it, just by including a checking loop before the pump starts. Then any time the main program wants to prevent an idle pump from running it simply sets the flag or lock and holds it until conditions change.
So, for this last approach with locks your pump cog core routine would look something like:
To disable a pump during the timing cycle the main program would need to stop the pump cog, set the lock, and start the pump cog again.
I wrote a simple demo that runs four timers in one cog -- no need to waste cogs with such a simple requirement. The Propeller can do a lot of work in one millisecond, so you can easily add more. This is the essential guts of the timer code:
Yes, it's that easy.
The demo displays each of the timers in clock format (will milliseconds) and lets you toggle the enable control vars; by timer, or you can stop or start all at once.
In your program each of the elements will have a state variable that determines the use of its timer.
Mind you, the simplicity of this code means your timer resolution is +/- one second. That's easily fixed by setting a timing constant which affects the timer loop delay, and scaling/descaling your timer values in and out.
It seems like you're controlling simple IO. Here's a little method that refreshes an output pin based on the state of the timer.
Okay... I've been coding since 6AM and it's past 10PM -- that's enough fun for me. I hope this stuff is useful.
reading my original instruction book propeller manual v 1.1 page 78 about cognew.
It did not mention that when the when the cognew spin method finished, it would
release the cog. So I thought it would stay in the cog. And if I called cognew more
thatn 6 times I would be out of cogs.... Then I read your comments, then I read the
later official Guide page 34, and it sez when method is done it frees up cog...
I am a 76 year old retired engineer, and I am absolutely convinced that instruction manuals
should be written by people who have learned the hard way, and NOT by the guys
that invented the device and know it inside out … This is a Great forum, and you
guys have been very helpful. Thanks.
Indeed, it does. In many of my commercial apps I use a "background" cog that calls other routines; the background cog runs an infinite loop so that it doesn't stop itself.
Here's a real-world example from my HC-8+ controller template; this keeps track of a global milliseconds value (for timing), manages an RG LED to give red, green, and yellow -- with flashing of any two colors -- and process inputs through a couple of shift register. I like keeping my actual "background" method very tidy.