Multiple time stamp checks on a microcontroller

Sometimes you need to manage multiple events with a microcontroller that all require different timing.  For example, you might want to control a servomotor (which requires a 20 millisecond delay), blink an LED once a second, and read some sensors (which should be read as frequently as possible.  One way to handle this is to keep track of a time stamp for each event.  You constantly read the millis() and if enough time has elapsed since the last time a particular event occured, you do it again.

For example, to make an LED blink once a second while constantly reading a switch, you can do this (adapted from the Arduino BlinkWithoutDelay tutorial):

int switchPin = 2;             // switch on digital pin 2
int ledPin = 13;                // LED connected to digital pin 13
int value = LOW;               // previous value of the LED
long previousMillis = 0;      // will store last time LED was updated
long interval = 1000;         // interval at which to blink (milliseconds)

void setup() {
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
}

void loop() {
  // read the switch:
  int switchState = digitalRead(switchPin);
  Serial.println(switchState);

  // check to see if it's time to blink the LED; that is, is the difference
  // between the current time and last time we blinked the LED bigger than
  // the interval at which we want to blink the LED.
  if (millis() - previousMillis > interval) {
    previousMillis = millis();   // remember the last time we blinked the LED

    // if the LED is off turn it on and vice-versa.
    if (value == LOW)
      value = HIGH;
    else
      value = LOW;
    digitalWrite(ledPin, value);
  }
}

That works fine for two events, the switch, which is read constantly, and the LED, which blinks once a second. The if statement that checks the millis() is what I’m referring to as the time stamp block, because it checks the time and takes note of when something happens. The example that follows checks three analog inputs and uses them to change the interval times on three blinking LEDs. Each LED has its own time stamp, and its own interval. Each interval is controlled by its own analog input.

This approach can be expanded to include many different events, each with its own time stamp and delay interval. You have to be careful not to use delay() in a program like this, because it will affect the timing of the main loop.

/*
  Multiple blink without Delay

  Turns on and off multiple LEDs connected to digital pin,
  without using the delay() function.  This means that other code

  can run at the same time without being interrupted by the LED code.

  Three LEDs are attached to pins 2, 3, and 4.
  Three potentiometers are attached to analog inputs 0,1, and 2.

  Turning each pot changes the delay time on the corresponding LED.

  Uses three arrays:
    timeStamp[] holds the times that the LEDs last changed
    interval[] holds the delay times between each LED's changes
    pinState[] holds the states of the three LEDs

   This code is unusually terse for Arduino code;  it's meant to
   demonstrate how you can use arrays as well.

 Created 30 Sep 2008
 by Tom Igoe
*/

long timeStamp[3];    // the times that the LEDs last changed
long interval[3];     // the time between changes for each LED
int pinState[3];      // the state (high or low) of each LED

void setup()
{
// initialize the digital outputs:
  for (int pinNum = 2; pinNum < 5; pinNum++) {
    pinMode(pinNum, OUTPUT);      // sets each digital pin as output
  }
}

void loop() {
// loop from 0 to 2, thisPin will be the analog pin numbers,
// and thisPin + 2 will be the digital out pin numbers:
  for (int thisPin = 0 ; thisPin < 3; thisPin++) {
    // read an analog pin. You want to read the sensors
    // as frequently as possible so that the system is very
    // responsive.  So this is not in a timestamp loop:
    int analogReading = analogRead(thisPin);
    // set the interval using the analog reading:
    interval[thisPin] = analogReading;

    // here comes the timestamp loop.
    // if the interval for this LED has passed,
    // then toggle the LED:
    if (millis() - timeStamp[thisPin] > interval[thisPin]) {
      toggleLED(thisPin+2);
       // remember the last time we blinked the LED:
      timeStamp[thisPin] = millis();
    }
  }
}

void toggleLED(int whichPin) {
  // if this variable is 0, set it to 1, and vice versa:
  pinState[whichPin -2] = !pinState[whichPin -2];
  // use the variable's value to set the LED:
  digitalWrite(whichPin, pinState[whichPin -2]);
}