1
1
Timers
2
- ------
2
+ ======
3
+
4
+ .. highlight :: c++
5
+
6
+ Generally, timers in Sming fall into two categories: Callback Timers and Polled Timers
7
+
8
+ Callback Timers
9
+ ---------------
10
+
11
+ A callback timer is operated by programming a time interval, then arming it. When the timer
12
+ 'fires' a function of your choosing gets called. Timers can be 'one-shot', for timing single
13
+ events, or 'auto-reset' repetitive timers. A repetitive timer will ensure that time intervals
14
+ between successive callbacks are consistent.
15
+
16
+ There are two categories of callback timer.
3
17
4
18
Hardware timers
5
19
The ESP8266 has two main hardware timers. Timer1 is a countdown timer, which triggers
@@ -24,3 +38,96 @@ Software timers
24
38
and delegate callback functions so you can use it with class methods, capturing lambdas, etc.
25
39
26
40
The *SimpleTimer * class uses less RAM, but only supports regular function callbacks.
41
+
42
+ Polled timers
43
+ -------------
44
+
45
+ Polled timers can be used to measure elapsed time intervals or to check for timeouts within code loops.
46
+ Traditionally one might do this as follows::
47
+
48
+ #define TIMEOUT_MS 100
49
+
50
+ int timeout = millis() + TIMEOUT_MS;
51
+ while(millis() < timeout) {
52
+ // do some stuff
53
+ }
54
+ int elapsed = millis() - start;
55
+ Serial.print("Elapsed time: ");
56
+ Serial.print(elapsed);
57
+ Serial.println("ms");
58
+
59
+ This looks OK, and will work until millis() approaches MAXINT at which point it falls over, a little under 25 days.
60
+ With microseconds it'll happen in less than an hour. It should always be coded like this::
61
+
62
+ int start = millis();
63
+ while(millis() - start < TIMEOUT_MS) {
64
+ // do some stuff
65
+ }
66
+
67
+ The easy way to get it right is to use a Polled Timer, like this::
68
+
69
+ OneShotFastMs timer(TIMEOUT_MS);
70
+ while(!timer.expired()) {
71
+ // do some stuff
72
+ }
73
+ auto elapsed = timer.elapsedTime(); // This obtains a `Time` object, containing a value plus time unit
74
+ Serial.print("Elapsed time: ");
75
+ Serial.println(elapsed); // Includes units in the elapsed time interval
76
+
77
+ If you prefer to use microseconds, use *OneShotFastUs * instead. You can work with other units
78
+ of time like this::
79
+
80
+ OneShotElapseTimer<NanoTime::Seconds>;
81
+
82
+ Another advantage of polled timers is speed. Every call to millis (or micros) requires a calculation
83
+ from clock ticks into milliseconds (or microseconds). It's also a function call.
84
+
85
+ Polled timers measure time using hardware clock ticks, and queries the hardware timer register directly.
86
+ The code is also compiled inline so there is no function call overhead. This makes them a much better
87
+ choice for tight timing loops.
88
+
89
+ See *PolledTimer.h * for more details.
90
+
91
+ Clocks
92
+ ------
93
+
94
+ Timers and their capabilities can vary considerably. For example, Timer1 can be configured with
95
+ a prescaler of 1, 16 or 256 which affects both the resolution and range of the timer. One might
96
+ also consider the CPU cycle counter to have a selectable prescaler of 1 or 2, depending on
97
+ whether it's running at 80MHz or 160MHz.
98
+
99
+ Each hardware timer has an associated *Clock * definition in `Platform/Clocks.h `, each of which
100
+ simply defines the properties for each Clock source. It's defined as a class template.
101
+
102
+ Clocks are made more useful by *TimeSource *, another class template defined in *NanoTime.h *.
103
+ Any time you need to convert between time values and tick values, it'll be through a method
104
+ of a TimeSource.
105
+
106
+ Let's say we want a microsecond source using Timer2::
107
+
108
+ TimeSource<Timer2Clock, NanoTime::Microseconds, uint32_t> t2source;
109
+
110
+ We can now call methods of *t2source * like this::
111
+
112
+ // What's the maximum Timer2 value in microseconds?
113
+ Serial.println(t2source.maxClockTime());
114
+
115
+ // How many clock ticks per microsecond ?
116
+ Serial.println(t2source.ticksPerUnit()); // 5/1
117
+
118
+ // How many clock ticks for 100us ?
119
+ Serial.println(t2source.template timeConst<100>().ticks());
120
+
121
+ Note that all of these values are computed at compile time. Some runtime conversions::
122
+
123
+ Serial.println(t2source.timeToTicks(100));
124
+ Serial.println(t2source.ticksToTime(10000));
125
+
126
+ The results of conversions are rounded rather than truncated, which provides more accurate
127
+ results and reduces timing jitter.
128
+
129
+ For debugging purposes you can print a description::
130
+
131
+ Serial.println(t2source.toString()); // "Timer2Clock/5MHz/32-bit/microseconds"
132
+
133
+ See *NanoTime.h * for further details.
0 commit comments