Video
                                
                                
# Lab: Button Hold Detection
## Objective
Learn to detect and measure how long a button is held down using the TinkerBlock TK04 Push Button module. This lab introduces timing concepts using the `millis()` function and demonstrates how to track button press duration.
## Learning Outcomes
- Understand button hold detection concepts
- Master the `millis()` function for timing
- Learn state tracking with boolean variables
- Implement button press and release detection
- Use timing calculations to measure hold duration
## Required Components

1. **Lonely Binary UNO R3** - Main Arduino board
2. **TinkerBlock UNO R3 Shield** - Expansion shield that plugs onto the UNO R3
3. **TinkerBlock TK04 - Push Button** - Push button module with 4-pin connector
## Theory
### Button Hold Detection
Button hold detection involves:
- **Press Detection**: Identifying when a button transitions from not pressed to pressed
- **Release Detection**: Identifying when a button transitions from pressed to not pressed
- **Timing Measurement**: Calculating the duration between press and release events
### The `millis()` Function
- **Purpose**: Returns the number of milliseconds since the Arduino board began running the current program
- **Range**: Returns an `unsigned long` value (0 to 4,294,967,295)
- **Overflow**: Resets to 0 after approximately 50 days of continuous operation
- **Advantages**: Non-blocking, allows other operations to continue while timing
### State Tracking Variables
- **`pressStartTime`**: Stores the timestamp when button was first pressed
- **`buttonWasPressed`**: Boolean flag to track if button is currently being held
- **State Machine**: Program logic that responds differently based on current state
### Timing Calculation
```cpp
unsigned long holdTime = millis() - pressStartTime;
```
- **Formula**: Current time minus start time equals duration
- **Result**: Time in milliseconds that button was held
- **Data Type**: `unsigned long` to handle large time values
### Key Functions Used
- `pinMode(pin, mode)`: Configures a pin as input or output
- `digitalRead(pin)`: Reads the state of a digital pin (HIGH or LOW)
- `millis()`: Returns milliseconds since program start
- `Serial.begin(baud)`: Initializes serial communication
- `Serial.print()` and `Serial.println()`: Outputs data to Serial Monitor
- `delay(milliseconds)`: Pauses the program for a specified time
## Circuit Diagram

## Connection Instructions
1. **Assemble the Hardware:**
   - Place the TinkerBlock UNO R3 Shield onto the Lonely Binary UNO R3
   - Ensure all pins are properly aligned and seated
   - The shield should fit snugly on top of the Arduino board
2. **Connect the Push Button Module:**
   - Take the TinkerBlock TK04 - Push Button module
   - Align the 4-pin connector with any available 4-pin slot on the shield
   - Gently push the module into the slot until it clicks into place
   - The module will automatically connect:
     - **GND** pin to ground
     - **VCC** pin to 5V power
     - **NC** pin remains unconnected
     - **Signal** pin to digital pin D5
3. **Important Notes:**
   - No breadboard or jumper wires required
   - The TK04 push button has a built-in 10kΩ pull-down resistor
   - The button's built-in LED will light when pressed
## Code
```cpp
// Lab 5: Button Hold Detection
// Push button connected to digital pin D5
// Define the button pin
const int buttonPin = 5;   // Button input pin
// Variables for button hold detection
unsigned long pressStartTime = 0;    // When button was first pressed
bool buttonWasPressed = false;       // Track if button is currently held
void setup() {
  // Configure button pin as input
  pinMode(buttonPin, INPUT);
  
  // Initialize serial communication for debugging
  Serial.begin(9600);
  
  Serial.println("Button Hold Detection Lab Started");
  Serial.println("Press and hold the button to see timing results");
}
void loop() {
  // Read the button state
  int buttonState = digitalRead(buttonPin);
  
  // Detect button press (transition from LOW to HIGH)
  if (buttonState == HIGH && !buttonWasPressed) {
    // Button just pressed - start timing
    pressStartTime = millis();
    buttonWasPressed = true;
    Serial.println("Button pressed - timing started");
  }
  
  // Detect button release (transition from HIGH to LOW)
  else if (buttonState == LOW && buttonWasPressed) {
    // Button released - calculate hold time
    unsigned long holdTime = millis() - pressStartTime;
    Serial.print("Button held for: ");
    Serial.print(holdTime);
    Serial.println(" milliseconds");
    buttonWasPressed = false;
  }
  
  // Small delay to prevent too rapid reading
  delay(10);
}
```
## Code Explanation
### Setup Function
```cpp
void setup() {
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
  Serial.println("Button Hold Detection Lab Started");
}
```
- Configures pin D5 as input for button reading
- Initializes serial communication for debugging
- Prints startup messages to Serial Monitor
### Global Variables
```cpp
unsigned long pressStartTime = 0;    // When button was first pressed
bool buttonWasPressed = false;       // Track if button is currently held
```
- **`pressStartTime`**: Stores the timestamp when button was first pressed
- **`buttonWasPressed`**: Boolean flag to prevent multiple timing starts
### Loop Function - Press Detection
```cpp
if (buttonState == HIGH && !buttonWasPressed) {
  pressStartTime = millis();
  buttonWasPressed = true;
  Serial.println("Button pressed - timing started");
}
```
**Logic:**
- `buttonState == HIGH`: Button is currently pressed
- `!buttonWasPressed`: Button was not previously being held
- **Result**: This is a new button press, so start timing
### Loop Function - Release Detection
```cpp
else if (buttonState == LOW && buttonWasPressed) {
  unsigned long holdTime = millis() - pressStartTime;
  Serial.print("Button held for: ");
  Serial.print(holdTime);
  Serial.println(" milliseconds");
  buttonWasPressed = false;
}
```
**Logic:**
- `buttonState == LOW`: Button is currently released
- `buttonWasPressed`: Button was previously being held
- **Result**: Button was released, so calculate and display hold time
### Timing Calculation
```cpp
unsigned long holdTime = millis() - pressStartTime;
```
- **`millis()`**: Current time in milliseconds
- **`pressStartTime`**: Time when button was first pressed
- **`holdTime`**: Duration button was held (in milliseconds)
## Testing and Verification
1. **Upload the code to Lonely Binary UNO R3**
2. **Open Serial Monitor** in Arduino IDE (Tools → Serial Monitor)
3. **Test different hold durations:**
   - **Short press**: Press and quickly release (should show ~50-200ms)
   - **Medium hold**: Hold for 1-2 seconds (should show ~1000-2000ms)
   - **Long hold**: Hold for 5+ seconds (should show ~5000+ms)
4. **Observe the behavior:**
   - "Button pressed - timing started" appears when button is first pressed
   - "Button held for: X milliseconds" appears when button is released
   - The button's built-in LED should light during the hold period
5. **Verify accuracy:**
   - Compare displayed times with actual hold duration
   - Test multiple times to ensure consistent results
## Troubleshooting
### Button doesn't respond:
- Check if the TinkerBlock shield is properly seated on the Arduino
- Ensure the TK04 module is firmly connected to the shield
- Verify the module is connected to a slot that uses D5 pin
- Check if code uploaded successfully to the Lonely Binary UNO R3
- Open Serial Monitor to see if button states are being read
### Timing seems inaccurate:
- Check if `delay(10)` is present in the loop for stable reading
- Verify `millis()` is being used correctly (not `micros()` or `delay()`)
- Ensure `pressStartTime` is declared as `unsigned long`
- Check for any blocking operations that might affect timing
### Multiple timing starts detected:
- Verify `buttonWasPressed` flag is working correctly
- Check that the flag is reset to `false` when button is released
- Ensure the logic conditions are properly structured
### Serial Monitor shows no output:
- Ensure Serial Monitor is set to 9600 baud rate
- Check that Serial.begin(9600) is in setup()
- Verify the correct COM port is selected in Arduino IDE
- Make sure button is being pressed and released completely
### Hold time shows 0 milliseconds:
- Check if `pressStartTime` is being set correctly
- Verify the button press and release detection logic
- Ensure there are no delays between press detection and timing start
## Experiment Variations
### 1. Hold Time Categories
Categorize hold times into different ranges:
```cpp
void loop() {
  int buttonState = digitalRead(buttonPin);
  
  if (buttonState == HIGH && !buttonWasPressed) {
    pressStartTime = millis();
    buttonWasPressed = true;
    Serial.println("Button pressed - timing started");
  }
  else if (buttonState == LOW && buttonWasPressed) {
    unsigned long holdTime = millis() - pressStartTime;
    
    // Categorize hold time
    if (holdTime < 100) {
      Serial.println("Quick tap detected");
    } else if (holdTime < 1000) {
      Serial.println("Short press detected");
    } else if (holdTime < 3000) {
      Serial.println("Medium hold detected");
    } else {
      Serial.println("Long hold detected");
    }
    
    Serial.print("Duration: ");
    Serial.print(holdTime);
    Serial.println(" milliseconds");
    buttonWasPressed = false;
  }
  
  delay(10);
}
```
### 2. Continuous Hold Monitoring
Monitor hold time continuously while button is held:
```cpp
void loop() {
  int buttonState = digitalRead(buttonPin);
  
  if (buttonState == HIGH && !buttonWasPressed) {
    pressStartTime = millis();
    buttonWasPressed = true;
    Serial.println("Button pressed - timing started");
  }
  else if (buttonState == HIGH && buttonWasPressed) {
    // Button is still held - show current hold time
    unsigned long currentHoldTime = millis() - pressStartTime;
    Serial.print("Still holding... ");
    Serial.print(currentHoldTime);
    Serial.println(" ms");
  }
  else if (buttonState == LOW && buttonWasPressed) {
    unsigned long holdTime = millis() - pressStartTime;
    Serial.print("Button held for: ");
    Serial.print(holdTime);
    Serial.println(" milliseconds");
    buttonWasPressed = false;
  }
  
  delay(100);  // Longer delay for continuous monitoring
}
```
### 3. Hold Time with LED Feedback
Use LED to indicate hold duration:
```cpp
const int ledPin = 13;  // Built-in LED
void loop() {
  int buttonState = digitalRead(buttonPin);
  
  if (buttonState == HIGH && !buttonWasPressed) {
    pressStartTime = millis();
    buttonWasPressed = true;
    digitalWrite(ledPin, HIGH);  // Turn on LED
    Serial.println("Button pressed - timing started");
  }
  else if (buttonState == LOW && buttonWasPressed) {
    unsigned long holdTime = millis() - pressStartTime;
    digitalWrite(ledPin, LOW);   // Turn off LED
    Serial.print("Button held for: ");
    Serial.print(holdTime);
    Serial.println(" milliseconds");
    buttonWasPressed = false;
  }
  
  delay(10);
}
```
### 4. Multiple Button Hold Detection
Detect holds on multiple buttons:
```cpp
const int button1Pin = 5;
const int button2Pin = 6;
unsigned long press1StartTime = 0;
unsigned long press2StartTime = 0;
bool button1WasPressed = false;
bool button2WasPressed = false;
void loop() {
  int button1State = digitalRead(button1Pin);
  int button2State = digitalRead(button2Pin);
  
  // Button 1 logic
  if (button1State == HIGH && !button1WasPressed) {
    press1StartTime = millis();
    button1WasPressed = true;
    Serial.println("Button 1 pressed");
  }
  else if (button1State == LOW && button1WasPressed) {
    unsigned long holdTime = millis() - press1StartTime;
    Serial.print("Button 1 held for: ");
    Serial.print(holdTime);
    Serial.println(" ms");
    button1WasPressed = false;
  }
  
  // Button 2 logic
  if (button2State == HIGH && !button2WasPressed) {
    press2StartTime = millis();
    button2WasPressed = true;
    Serial.println("Button 2 pressed");
  }
  else if (button2State == LOW && button2WasPressed) {
    unsigned long holdTime = millis() - press2StartTime;
    Serial.print("Button 2 held for: ");
    Serial.print(holdTime);
    Serial.println(" ms");
    button2WasPressed = false;
  }
  
  delay(10);
}
```
## Questions for Understanding
1. What is the difference between `millis()` and `delay()`?
2. Why do we use `unsigned long` for timing variables?
3. What is the purpose of the `buttonWasPressed` flag?
4. How does the program distinguish between a new press and a continued hold?
5. What happens if you hold the button for more than 50 days?
6. Why do we use `delay(10)` in the main loop?
7. How could you modify the code to detect double-clicks?
8. What is the advantage of using `millis()` over counting loop iterations?
## Next Steps
- Try implementing button debouncing techniques
- Experiment with different hold time thresholds
- Learn about interrupt-based button handling
- Explore combining hold detection with other sensors
- Try creating a button gesture recognition system
- Learn about state machines for complex button interactions
## Safety Notes
- Always disconnect power before connecting or disconnecting modules
- Handle the TinkerBlock shield and modules carefully to avoid bending pins
- Ensure proper alignment when connecting modules to prevent damage
- The built-in resistor in the TK04 module prevents component damage
- Keep the Lonely Binary UNO R3 and shield in a stable position during operation
- Be patient when testing hold times - avoid rapid button pressing that might damage the switch
                                
                            
                            

 
	   
	 
	   
	 
	   
	 
	   
	 
	   
	 
	   
	 
	   
	