Page 1 of 1
Relaying on Timer , more than 24h ...
Posted: 08 January 2011, 2:23 AM
by kurakaira
What is wrong with my reasoning ? , this time
I have a few projects that run 24/7 , i am having a difficulty with the Timer clearing after 24h ..
I rely on the Timer to make a minimum delay before calling different tasks ..
Better suggestions ?
Code: Select all
' All variables Single
StartS = Timer
Do
If Timer < StartS then ' Here the day change should be detected
Call ResetTimers
StartS = Timer
End if
If Timer - Time1S > 0.2 then ' Do something every 200ms
Call Read165
Time1S = Timer
End if
If Timer - Time2S > 1.0 then ' Do something every 1000ms
Call Write595
Time2S = Timer
End if
Loop ' Main loop
Sub ResetTimers()
Time1S = Timer
Time2S = Timer
End Sub
Re: Relaying on Timer , more than 24h ...
Posted: 08 January 2011, 8:40 AM
by dkinzer
kurakaira wrote:Better suggestions ?
Perhaps you could set up an interval timer using SetInterval() and in the task that waits for the interval timer (see WaitInterval()) you can count the number of intervals that have occurred to determine which actions to take.
Re: Relaying on Timer , more than 24h ...
Posted: 08 January 2011, 10:23 AM
by GTBecker
Try this, corrected:
Code: Select all
Dim Time1S as single, Time2S as single
sub Main()
Dim T0 as single, TX as single
Register.RTCTick = 86390 * 512 'This value tests 24 hour rollover
Time1S = Timer
Time2S = Timer
Do
T0 = Timer
Const Period1 as single = 0.2
Tx = T0 - Time1S
If Tx < 0.0 or Tx >= 86400.0 then
Tx = (Tx + 86400.0) mod 86400.0
End If
If Tx >= Period1 then ' Do something every 200ms
Time1S = (Time1S + Period1) mod 86400.0
Call Read165
End if
Const Period2 as single = 1.0
Tx = T0 - Time2S
If Tx < 0.0 or Tx >= 86400.0 then
Tx = (Tx + 86400.0) mod 86400.0
End If
If Tx >= Period2 then ' Do something every 1000ms
Time2S = (Time2S + Period2) mod 86400.0
Call Write595
End if
Loop ' Main loop
end sub
sub Read165()
console.writeline(" " & fmt(Time1S, 2))
call FlashLED(25)
end sub
sub Write595()
console.writeline(fmt(Time2S, 2))
call FlashLED(26)
end sub
Sub FlashLED(byval LED as byte)
Call PutPin(LED, 0) ' LED on.
Call Sleep(2)
Call PutPin(LED, 1) ' LED off.
End Sub
The similar code clusters can surely be generalized into a subroutine.
Posted: 09 January 2011, 10:51 AM
by GTBecker
This apparently simple job - accurately triggering periodic events - illustrates a practical limitation of 32-bit floating point variables in timing.
32-bit Single vars provide for six or seven decimal digits of significance (unless the value is exactly binary), so the inexactness of the value of elapsed time in seconds is clearly exposed in the hundredths digit as the clock nears 24-hours, 86400.00 seconds. Once it rolls over at 86400.0=0.0, that quantization error moves down to the seventh and sixth fraction digit, well below the Fmt(x,2) value, but it doesn't take long for it to reappear.
Truly precise periods are difficult to manage in software, and even digital hardware solutions require that the timebase and the targeted period are related integrally or inversely. Analog time conversion techniques are often used in the most accurate instruments.
Most-precise timing in code will use fixed-point vars (and integer-counting hardware) but, even then, the selection of precise periods that can be expressed is finite.
Posted: 09 January 2011, 11:59 AM
by kurakaira
Thanks for all Your help ,
After figuring out GTBecker's code , it looks just the thing i was aiming at .
I built a lighting control system for a friend's house . ( Luckily for them it only controls the lights downstairs , normal wiring upstairs
The system is a ZX40a reading 6 motion sensors and controlling 14 different light groups , some dimmable .
Main control is by a 4.3" touchscreen , the rest by the motion sensors .
Almost everything runs periodically , Writing to display every 500ms , reading temp sensors every 1000ms and every light group has it's own timer that depends on the group but is generally larger than 4minutes .
The accuracy of doing something periodically is not a problem here , but the ZX stops running the "Timer - Time1S > 0.4" after 24 hours .
I figured that it would not matter if some tasks were not run for a second when detecting and resetting all "Time*S = Timer" , but for some reason my code was not functioning .
I will try to implement the corrected code . ( after i fully understand it ...)
Thanks again !
Posted: 09 January 2011, 19:11 PM
by GTBecker
I said:
GTBecker wrote:... six or seven decimal digits of significance (unless the value is exactly binary)...
FWIW, this code makes that easy to show, too. If the value of Period1 in the code above is changed to 0.03125 (1/32) and Fmt(x,5) is used to display the Timer value, for example, the result is 10 accurate decimal digits even as 24 hours is approached:
Code: Select all
86398.93750
86398.96875
86399.00000
86399.00
86399.03125
86399.06250
86399.09375
86399.12500
86399.15625
86399.18750
86399.21875
86399.25000
86399.28125
86399.31250
86399.34375
86399.37500
86399.40625
86399.43750
86399.46875
86399.50000
86399.53125
86399.56250
86399.59375
86399.62500
86399.65625
86399.68750
86399.71875
86399.75000
86399.78125
86399.81250
86399.84375
86399.87500
86399.90625
86399.93750
86399.96875
0.00000
0.00
0.03125
0.06250
0.09375
0.12500
0.15625
0.18750
0.21875
0.25000
0.28125
0.31250
0.34375
0.37500
0.40625
0.43750
0.46875
0.50000
0.53125
0.56250
0.59375
0.62500
0.65625
0.68750
0.71875
0.75000
0.78125
0.81250
0.84375
0.87500
0.90625
0.93750
0.96875
1.00000
1.00
1.03125
1.06250
1.09375
...
Posted: 09 January 2011, 19:25 PM
by GTBecker
Liam, Don's suggestion might suit your need, and it is easier.
If you write a sub or task that simply loops around a 200mS Delay, Sleep or WaitForInterval, you can run your 200mS functions once per loop and the 1000mS functions once per five loops. No concern for the RTC rollover is necessary.
It works :)
Posted: 27 January 2011, 7:31 AM
by kurakaira
Thank's for all Your help !
The system's been on without a glitch for over a week now .
At first i had trouble resetting a timer whenever motion was detected , but the line , LightTimeS = T0 mod 86400.0 , seems to do the trick .
There are a lot of these timers ...
Code: Select all
Sub Main()
Do
T0 = Timer
Const Period1 as single = 0.2
Tx = T0 - Time1S
If Tx < 0.0 or Tx >= 86400.0 then
Tx = (Tx + 86400.0) mod 86400.0
End If
If Tx >= Period1 then ' Do something every 200ms
Time1S = (Time1S + Period1) mod 86400.0
Call DetectMotion
End if
Loop
End Sub
Sub DetectMotion()
If MotionDetected = 1 then ' Every time motion is detected resets the timer
LightsB = 1
LightTimeS = T0 mod 86400.0
End if
If LightsB = 1 then
Tx = T0 - LightTimeS
If Tx < 0.0 or Tx >= 86400.0 then
Tx = (Tx + 86400.0) mod 86400.0
End If
If Tx >= 360.0 then ' Turn lights off after 6min
LightTimeS = (LightTimeS + 360.0) mod 86400.0
LightsB = 0
End if
End if
End Sub