# Arduino Language Learning: millis() Function
## **What is millis()?**
The **millis()** function is a built-in Arduino function that returns the number of milliseconds since the Arduino board began running the current program. It's like a stopwatch that starts when you upload your code and keeps running until you reset the board.
### **Basic Concept**
Think of `millis()` as a digital clock that:
- **Starts at 0** when your program begins
- **Counts up** continuously in milliseconds
- **Never stops** unless you reset the Arduino
- **Overflows** after about 49.7 days (4,294,967,295 milliseconds)
### **Why Use millis() Instead of delay()?**
- **delay()**: Pauses the entire program (blocking)
- **millis()**: Non-blocking timing (program continues running)
- **Better Performance**: Allows multiple tasks to run simultaneously
- **Responsive**: Keeps your Arduino responsive to inputs
## **Basic millis() Usage**
### **Syntax**
```cpp
unsigned long currentTime = millis();
```
### **Return Type**
- **Type**: `unsigned long`
- **Range**: 0 to 4,294,967,295 (about 49.7 days)
- **Unit**: Milliseconds (1/1000th of a second)
### **Simple Example**
```cpp
void setup() {
  Serial.begin(9600);
  Serial.println("Program started!");
}
void loop() {
  unsigned long currentTime = millis();
  Serial.print("Time since start: ");
  Serial.print(currentTime);
  Serial.println(" milliseconds");
  
  delay(1000);  // Wait 1 second
}
```
**Serial Monitor Output:**
```
Program started!
Time since start: 0 milliseconds
Time since start: 1000 milliseconds
Time since start: 2000 milliseconds
Time since start: 3000 milliseconds
```
## **Converting millis() to Different Units**
### **Seconds**
```cpp
unsigned long seconds = millis() / 1000;
```
### **Minutes**
```cpp
unsigned long minutes = millis() / 60000;  // 60,000 ms = 1 minute
```
### **Hours**
```cpp
unsigned long hours = millis() / 3600000;  // 3,600,000 ms = 1 hour
```
### **Complete Time Display**
```cpp
void setup() {
  Serial.begin(9600);
}
void loop() {
  unsigned long currentMillis = millis();
  
  unsigned long seconds = currentMillis / 1000;
  unsigned long minutes = seconds / 60;
  unsigned long hours = minutes / 60;
  
  // Remove completed units
  seconds = seconds % 60;
  minutes = minutes % 60;
  
  Serial.print("Uptime: ");
  Serial.print(hours);
  Serial.print("h ");
  Serial.print(minutes);
  Serial.print("m ");
  Serial.print(seconds);
  Serial.println("s");
  
  delay(1000);
}
```
**Serial Monitor Output:**
```
Uptime: 0h 0m 1s
Uptime: 0h 0m 2s
Uptime: 0h 0m 3s
...
Uptime: 0h 1m 0s
Uptime: 0h 1m 1s
```
## **Non-blocking Timing with millis()**
### **The Problem with delay()**
```cpp
void loop() {
  // Task 1
  digitalWrite(13, HIGH);
  delay(1000);  // Program stops here for 1 second
  
  // Task 2
  digitalWrite(13, LOW);
  delay(1000);  // Program stops here for 1 second
  
  // Task 3 - This won't run until 2 seconds later!
  Serial.println("Hello");
}
```
### **The Solution with millis()**
```cpp
unsigned long previousMillis = 0;
const long interval = 1000;  // 1 second
void loop() {
  unsigned long currentMillis = millis();
  
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    
    // Task 1: Toggle LED
    static boolean ledState = false;
    ledState = !ledState;
    digitalWrite(13, ledState);
    
    // Task 2: Print message
    Serial.println("Hello");
  }
  
  // Other tasks can run here without delay!
}
```
## **Timing Patterns with millis()**
### **Pattern 1: Simple Interval**
```cpp
unsigned long previousMillis = 0;
const long interval = 2000;  // 2 seconds
void loop() {
  unsigned long currentMillis = millis();
  
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    
    // Code to run every 2 seconds
    Serial.println("2 seconds have passed!");
  }
}
```
### **Pattern 2: Multiple Intervals**
```cpp
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
const long interval1 = 1000;  // 1 second
const long interval2 = 3000;  // 3 seconds
void loop() {
  unsigned long currentMillis = millis();
  
  // Task 1: Every 1 second
  if (currentMillis - previousMillis1 >= interval1) {
    previousMillis1 = currentMillis;
    Serial.println("Task 1: Every second");
  }
  
  // Task 2: Every 3 seconds
  if (currentMillis - previousMillis2 >= interval2) {
    previousMillis2 = currentMillis;
    Serial.println("Task 2: Every 3 seconds");
  }
}
```
### **Pattern 3: One-shot Timer**
```cpp
unsigned long startTime = 0;
const long duration = 5000;  // 5 seconds
boolean timerActive = false;
void loop() {
  unsigned long currentMillis = millis();
  
  // Start timer
  if (!timerActive) {
    startTime = currentMillis;
    timerActive = true;
    Serial.println("Timer started!");
  }
  
  // Check if timer finished
  if (timerActive && (currentMillis - startTime >= duration)) {
    timerActive = false;
    Serial.println("Timer finished! 5 seconds have passed.");
  }
}
```
### **Pattern 4: Countdown Timer**
```cpp
unsigned long startTime = 0;
const long countdownDuration = 10000;  // 10 seconds
boolean countdownActive = false;
void loop() {
  unsigned long currentMillis = millis();
  
  // Start countdown
  if (!countdownActive) {
    startTime = currentMillis;
    countdownActive = true;
    Serial.println("Countdown started!");
  }
  
  // Show remaining time
  if (countdownActive) {
    unsigned long elapsed = currentMillis - startTime;
    unsigned long remaining = countdownDuration - elapsed;
    
    if (remaining > 0) {
      Serial.print("Time remaining: ");
      Serial.print(remaining / 1000);
      Serial.println(" seconds");
    } else {
      countdownActive = false;
      Serial.println("Countdown finished!");
    }
  }
  
  delay(1000);  // Update every second
}
```
## **Timing Statistics with millis()**
### **Average Time Calculation**
```cpp
unsigned long startTime = 0;
unsigned long totalTime = 0;
int loopCount = 0;
void loop() {
  unsigned long loopStart = millis();
  
  // Simulate some work
  delay(random(100, 500));  // Random delay 100-500ms
  
  // Calculate loop time
  unsigned long loopTime = millis() - loopStart;
  totalTime += loopTime;
  loopCount++;
  
  // Calculate and display average
  unsigned long averageTime = totalTime / loopCount;
  
  Serial.print("Loop #");
  Serial.print(loopCount);
  Serial.print(" took ");
  Serial.print(loopTime);
  Serial.print("ms, Average: ");
  Serial.print(averageTime);
  Serial.println("ms");
}
```
### **Performance Monitoring**
```cpp
unsigned long lastReportTime = 0;
const long reportInterval = 5000;  // Report every 5 seconds
int operationsCount = 0;
void loop() {
  // Simulate operations
  for (int i = 0; i < 100; i++) {
    // Some work here
    operationsCount++;
  }
  
  // Report performance every 5 seconds
  unsigned long currentMillis = millis();
  if (currentMillis - lastReportTime >= reportInterval) {
    float operationsPerSecond = (float)operationsCount / 5.0;
    
    Serial.print("Performance: ");
    Serial.print(operationsPerSecond);
    Serial.println(" operations/second");
    
    operationsCount = 0;
    lastReportTime = currentMillis;
  }
}
```
## **Best Practices**
### **1. Use Constants for Intervals**
```cpp
// Good
const long BLINK_INTERVAL = 1000;
const long REPORT_INTERVAL = 5000;
// Avoid
unsigned long previousMillis = 0;
// ... later in code ...
if (currentMillis - previousMillis >= 1000) {
```
### **2. Handle Overflow Safely**
```cpp
// Good - Safe overflow handling
if ((unsigned long)(currentMillis - previousMillis) >= interval) {
    previousMillis = currentMillis;
}
// Avoid - Can fail after overflow
if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
}
```
### **3. Use Descriptive Variable Names**
```cpp
// Good
unsigned long lastBlinkTime = 0;
unsigned long lastReportTime = 0;
// Avoid
unsigned long time1 = 0;
unsigned long time2 = 0;
```
### **4. Group Related Timing Variables**
```cpp
// Good - Grouped timing variables
unsigned long lastBlinkTime = 0;
unsigned long lastReportTime = 0;
const long BLINK_INTERVAL = 500;
const long REPORT_INTERVAL = 2000;
// Avoid - Scattered variables
unsigned long time1 = 0;
const long interval1 = 500;
unsigned long time2 = 0;
const long interval2 = 2000;
```
### **5. Use millis() for Non-blocking Delays**
```cpp
// Good - Non-blocking
unsigned long previousMillis = 0;
const long interval = 1000;
void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    // Do something
  }
  // Other code can run here
}
// Avoid - Blocking
void loop() {
  // Do something
  delay(1000);  // Blocks everything
  // Other code waits
}
```
## **Common Use Cases**
### **1. Non-blocking Delays**
- Replace `delay()` with `millis()` for responsive programs
- Allow multiple tasks to run simultaneously
- Keep Arduino responsive to inputs
### **2. Timing Events**
- Schedule tasks at specific intervals
- Create time-based sequences
- Implement countdown timers
### **3. Performance Monitoring**
- Measure execution time
- Calculate averages and statistics
- Monitor system performance
### **4. State Machines**
- Time-based state transitions
- Create complex timing patterns
- Implement animations and sequences
### **5. Data Logging**
- Timestamp events and data
- Create time-based data records
- Implement periodic reporting
## **Summary**
### **Key Points:**
1. **millis()** returns milliseconds since program start
2. **Non-blocking**: Unlike `delay()`, doesn't pause the program
3. **Overflow**: Occurs after ~49.7 days (4,294,967,295 ms)
4. **Safe Handling**: Use `(unsigned long)` casting for overflow safety
5. **Multiple Tasks**: Enable simultaneous timing of different events
### **When to Use millis():**
- **Non-blocking Delays**: Replace `delay()` for responsive programs
- **Multiple Timers**: Run several timed events simultaneously
- **State Machines**: Time-based state transitions
- **Performance Monitoring**: Measure execution times
- **Data Logging**: Add timestamps to events
### **Next Steps:**
- **Practice**: Try the timing patterns with your Arduino
- **Combine**: Use millis() with other Arduino functions
- **Experiment**: Create your own timing-based projects
- **Explore**: Learn about micros() for microsecond timing
**millis() is essential for creating responsive, multi-tasking Arduino programs. Master it, and you'll be able to create sophisticated timing-based projects!** 
                                
                            
                            TinkerBlock UNO R3 Starter Kit
 Dive into the world of electronics, Arduino programming, and STEM projects with the Lonely Binary TinkerBlock Series Starter Kit. 
- Choosing a selection results in a full page refresh.


 
	   
	 
	   
	 
	   
	 
	   
	 
	   
	 
	   
	 
	   
	