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]); }