#define runEvery(t) for (static uint16_t _lasttime;\
(uint16_t)((uint16_t)millis() - _lasttime) >= (t);\
_lasttime += (t))
Almost every day, new users on the Programming Questions forum are directed to the Blink Without Delay example and struggle to understand it. With a little help, I have come up with this macro to make running things asyncronously a little easier.
Using this macro is easy. You call it like a control statement (such as if, while, or for) and give it the argument of after how many milliseconds it should run, and call it within loop(), like this:
void loop() {
runEvery(500) Serial.println("500 milliseconds have passed since last printed");
runEvery(100) {
Serial.print("Sensor Value: ");
Serial.println(analogRead(A1));
}
}
This will call the first print every 500 milliseconds, and the second set every 100 milliseconds forever.
You just have to make sure that there are no blocking calls (especially delay()) within loop(). However, this is easy if you just use this macro for everything.
Thus, I present the next BlinkWithoutDelay:
// Define the macro. Should be put in Arduino.h eventually
#define runEvery(t) for (static typeof(t) _lasttime;\
(typeof(t))((typeof(t))millis() - _lasttime) > (t);\
_lasttime += (t))
// constants won't change. Used here to
// set pin numbers:
const int ledPin = 13; // the number of the LED pin
// Variables will change:
int ledState = LOW; // ledState used to set the LED
// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000; // interval at which to blink (milliseconds)
void setup() {
// set the digital pin as output:
pinMode(ledPin, OUTPUT);
}
void loop()
{
// here is where you'd put code that needs to be running all the time.
// Run the following block of code every 1 second
runEvery(interval) {
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
Another neat thing about this macro is that it only uses as much memory as it has to. It needs to store the last time the block was run, but this variable will only take up as much space as the argument does. Thus, the macro can deal with delays of up to 50 days, while still only using 1 byte for delays of less than 250 milliseconds. This does contain the caveat that calling the macro with an argument that is close to the maximum value of the type is likely to break things.
Hopefully this will help everyone, and I would appreciate comments. I will submit this as a feature to Arduino once it gets tested a little more.
Edits:
- Changed > to >= in macro
- Made _lasttime always 16 bit
- Fixed parentheses