should I be declaring last_ms
as a global variable instead of
static?
Local static is better, as it limits the scope of the variable to just
where it is needed. Consider making it global only if the code is part
of a tutorial meant for beginners which may be confused by the keyword
static
.
should this code be at the beginning or end of loop?
The conditional early return only makes sense if loop()
has nothing
more to do once the sensor data is handled, thus this should go at the
very end of loop()
. However, if loop()
does more than just handle
this data, I think it would be cleaner to avoid the early return: either
put this in a separate function (which can return early), or condition
the handling of the sensor on ms - last_ms >= 10
.
My understanding is we are basically checking how long the previous
loop took.
No. The test is looking at how much time has elapsed since the previous
time last_ms
was updated, which could be many loop()
iterations ago.
But doesn't that mean that we might still get deviation from 100 Hz
due to the time it takes to complete loop (about 2-5ms in my case), so
effectively it's 10 ms + loop complete time?
Indeed. With this logic, 10 ms is the minimum time between calls
to sensor_data()
. If you want to ensure an accurate average polling
time, you should update last_ms
by adding 10. You will still have
sole jitter though.
A small note about millis()
: since the value is updated every
1.024 ms, it occasionally has to jump by two units at once, and has
therefore 1 ms of jitter. For a period as short as 10 ms, I
would rather use micros()
. For example:
const uint32_t POLLING_PERIOD = 10000; // 1e4 us = 10 ms
// Call this from loop()
void handle_sensor()
{
static uint32_t last_us;
if (micros() - last_us < POLLING_PERIOD) return;
last_us += POLLING_PERIOD;
sensor_data();
// ...
}
Edit: About why last_us
has to be incremented by a constant
amount, consider this alternative:
void handle_sensor()
{
static uint32_t last_us;
uint32_t now = micros()
if (now - last_us < POLLING_PERIOD) return;
last_us = now;
sensor_data();
// ...
}
The code following the if ... return;
line will be executed when the
tested condition is false, i.e. when now - last_us >= POLLING_PERIOD
.
It may happen that we sometimes have strict equality (now - last_us == POLLING_PERIOD
) but, since any code execution takes time, sometimes
now - last_us
will be strictly larger than POLLING_PERIOD
. Every
time this happens last_us
will be incremented by more than
POLLING_PERIOD
. This means that the small timing errors accumulate.
If, instead, last_us
is updated by adding a constant amount, we still
have timing errors (because of the time needed to execute any code), but
they are not cumulative. In other words, we have jitter, but the
average polling frequency is right.