Millis Arduino Function: How To Multitasking [Examples]

Last updated on November 20th, 2023

Using the millis() function in Arduino is important for accurate time measurement, important in multitasking scenarios. This post explores its intricacies, guides developers through implementation, and highlights its diverse applications in workflows.

Millis Arduino Function
Millis Arduino Function

Understanding the millis() Function

The millis() function in Arduino tracks time, measuring milliseconds since the program started. It relies on an internal timer that increments every millisecond, enabling precise time management. It is essential for delaying projects, timely operations and task coordination.

Key Characteristics of the millis() Function

  • Data Type: The millis() function returns an unsigned long value, capable of storing a vast range of millisecond counts.
  • Overflow: After approximately 50 days of continuous operation, the millisecond counter overflows, resetting to zero.
  • Precision: While the millis() function provides millisecond-level precision, it’s important to note that it may occasionally skip milliseconds due to internal clock adjustments.

Applications of the millis() Function

  1. Timed Delays: Use millis() to generate correct delay by comparing the current and stored timestamps.
  2. Event Timing: Measure button presses or sensor readings with millis(), track the duration of a specific event.
  3. Task Synchronization: To coordinate tasks in Arduino diagrams, millis() ensures proper order and timing.

Additional Applications of millis()

The millis() function finds applications in various Arduino projects, including:

  • Implementing real-time data acquisition and logging
  • Creating interactive light shows and animations
  • Generating audio tones and sound effects
  • Controlling servo motors and stepper motors with precise timing
  • Synchronizing communication between multiple Arduino devices

Implementing Multitasking with millis()

Using millis() in Arduino enables multitasking by dividing tasks into intervals, ensuring an agile program. Dividing operations and performing them in cycles increases responsiveness and efficiency in project development.

Arduino Millis Example

Example 1: Blinking LEDs with millis()

Consider the task of blinking two LEDs sequentially. The millis() function allows us to control the duration of each LED state and maintain a consistent blinking pattern.

unsigned long previousMillis = 0;
const long ledInterval = 1000; // Blinking interval in milliseconds

void setup() {
  pinMode(13, OUTPUT); // Set LED 1 as output
  pinMode(12, OUTPUT); // Set LED 2 as output
}

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= ledInterval) {
    if (digitalWrite(13, HIGH)) {
      digitalWrite(12, LOW); // LED 1 ON, LED 2 OFF
    } else {
      digitalWrite(13, LOW);
      digitalWrite(12, HIGH); // LED 1 OFF, LED 2 ON
    }
    previousMillis = currentMillis; // Update previous time
  }
}

Example 2: Implementing a Button Debouncing Mechanism

Button debouncing prevents multiple button presses from being registered as a single event due to switch bounce. The millis() function can be used to introduce a delay between button press events, effectively eliminating this issue.

const int buttonPin = 2; // Button connected to pin 2
const long debounceDelay = 50; // Debounce delay in milliseconds

unsigned long lastButtonPress = 0;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP); // Set button pin as input with internal pull-up resistor
}

void loop() {
  if (digitalRead(buttonPin) == LOW) {
    if (millis() - lastButtonPress >= debounceDelay) {
      // Perform action on button press
      Serial.println("Button pressed!");
      lastButtonPress = millis(); // Update last button press time
    }
  }
}

Example 3: Measuring Button Press Duration

In this example, the millis() function is used to measure the duration a button is pressed.

const int buttonPin = 2; // Button connected to pin 2

unsigned long buttonPressStart = 0; // Variable to store button press start time
unsigned long buttonPressDuration = 0; // Variable to store button press duration

void setup() {
  pinMode(buttonPin, INPUT_PULLUP); // Configure pin 2 as an input with pull-up resistor
}

void loop() {
  if (digitalRead(buttonPin) == LOW) { // Check if button is pressed
    if (buttonPressStart == 0) { // If button press is just starting
      buttonPressStart = millis(); // Store button press start time
    }
  } else { // If button is released
    if (buttonPressStart != 0) { // If button press was previously detected
      buttonPressDuration = millis() - buttonPressStart; // Calculate button press duration
      Serial.print("Button press duration: ");
      Serial.println(buttonPressDuration); // Print button press duration

      buttonPressStart = 0; // Reset button press start time
    }
  }
}

Example 4: Controlling a Servo with Precise Timing

In this example, the millis() function is used to control a servo motor with precise timing.

const int servoPin = 9; // Servo connected to pin 9
Servo myservo; // Create a Servo object

void setup() {
  myservo.attach(servoPin); // Attach servo to pin 9
}

void loop() {
  for (int pos = 0; pos <= 180; pos += 1) { // Sweep servo from 0 to 180 degrees
    myservo.write(pos); // Set servo position
    delay(10); // Delay for 10 milliseconds

    if (pos == 180) { // Reverse servo direction after reaching 180 degrees
      pos = 170;
    }
  }
}

Arduino millis() Example: Traffic Light Control System

In this example, we’ll create a traffic light simulation using the millis() function, demonstrating how to manage timing without resorting to delay() and allowing for multitasking within the Arduino.

Project Overview

The objective is to simulate a traffic light system consisting of three lights: red, yellow, and green. Each light will have its specific duration, and the system will transition between them smoothly using millis().

// Define pin numbers for the traffic lights
const int redLED = 2;
const int yellowLED = 3;
const int greenLED = 4;

// Define durations for each traffic light
const unsigned long redDuration = 5000;    // 5000 milliseconds (5 seconds)
const unsigned long yellowDuration = 2000; // 2000 milliseconds (2 seconds)
const unsigned long greenDuration = 5000;  // 5000 milliseconds (5 seconds)

unsigned long previousMillis = 0;  // Variable to store the last time the lights were updated
int currentLight = redLED;        // Variable to track the current active light

void setup() {
  // Initialize the pins as outputs
  pinMode(redLED, OUTPUT);
  pinMode(yellowLED, OUTPUT);
  pinMode(greenLED, OUTPUT);
}

void loop() {
  unsigned long currentMillis = millis();  // Get the current time

  // Check if it's time to change the lights
  if (currentMillis - previousMillis >= getDuration(currentLight)) {
    previousMillis = currentMillis;  // Save the current time

    // Switch to the next light
    switchLights();
  }
}

void switchLights() {
  digitalWrite(currentLight, LOW);  // Turn off the current light

  // Determine the next light based on the current one
  if (currentLight == redLED) {
    currentLight = greenLED;
  } else if (currentLight == greenLED) {
    currentLight = yellowLED;
  } else {
    currentLight = redLED;
  }

  digitalWrite(currentLight, HIGH);  // Turn on the next light
}

unsigned long getDuration(int light) {
  // Return the duration for the corresponding light
  if (light == redLED) {
    return redDuration;
  } else if (light == yellowLED) {
    return yellowDuration;
  } else {
    return greenDuration;
  }
}

How It Works

  • The code sets the pin for the traffic lights and defines their duration.
  • millis() is used to manage time without interrupting the execution of other tasks.
  • The switchLights() function is responsible for transitioning between different lights based on their duration.
  • The getDuration() function retrieves the specified duration for each light.

This example demonstrates how millis() facilitates multitasking by managing the timing for a traffic light system without delay, allowing for smooth transitions and simultaneous execution of other tasks within an Arduino project. It is imported.

Maximizing millis() Usage with Practical Tips

To optimize the performance and efficiency of the millis() function, consider these valuable tips:

  • Avoid excessive calls to millis() within loops: Frequent calls can impact performance due to overhead.
  • Utilize separate timers for independent tasks: This prevents conflicts and ensures accurate timing.
  • Handle timer overflows gracefully: Implement mechanisms to deal with the reset of the

Feel free to modify and experiment with the code to explore different timing scenarios or add more functionality to expand the project!

Bottom line

The millis() function is a cornerstone of Arduino programming, enabling accurate time measurement and multitasking. Its millisecond-level accuracy and versatility make it essential for a variety of applications, from time-delay to synchronous tasks. Practical examples demonstrate its effectiveness in LED blinking, button debounce, servo control, and traffic light control. Embrace millis() to develop responsive and efficient Arduino projects.

Remember, millis() isn’t just a function; it’s the key to efficient multitasking in Arduino!

Leave a Reply

Your email address will not be published. Required fields are marked *