Video
# Lab: Button Press Counter
## **Objective**
Learn to count and track the number of button presses using the TinkerBlock TK04 Push Button module. This lab builds upon the basic button reading skills from Lab 3 to implement a counter system.
## **Learning Outcomes**
- Understand button press detection and edge triggering
- Learn about state tracking and counter implementation
- Master button debouncing techniques
- Use Serial communication to display counter values
## **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 Press Detection**
- **Edge Detection**: Detecting the moment when button state changes from LOW to HIGH
- **State Tracking**: Remembering the previous button state to detect transitions
- **Counter Logic**: Incrementing a variable each time a button press is detected
### **Button Debouncing**
- **Mechanical Bounce**: Physical switches can create multiple rapid on/off signals
- **Debounce Delay**: Small delay to wait for switch to stabilize
- **State Comparison**: Only count when button transitions from LOW to HIGH
### **Counter Variables**
- **Press Counter**: Integer variable to store total number of presses
- **Last State**: Variable to remember previous button state
- **Current State**: Current reading from the button
### **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)
- **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**
**Same as Lab 3: Push Button Control**
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 4: Button Press Counter
// Count and display the number of button presses
// Define the button pin
const int buttonPin = 5; // Button input pin
// Counter variables
int buttonPressCount = 0; // Total number of button presses
int lastButtonState = LOW; // Previous button state for edge detection
void setup() {
// Configure button pin as input
pinMode(buttonPin, INPUT);
// Initialize serial communication for debugging
Serial.begin(9600);
Serial.println("Button Press Counter Lab Started");
Serial.println("Press the button to increment the counter");
Serial.print("Initial count: ");
Serial.println(buttonPressCount);
}
void loop() {
// Read the current button state
int buttonState = digitalRead(buttonPin);
// Detect button press (transition from LOW to HIGH)
if (buttonState == HIGH && lastButtonState == LOW) {
buttonPressCount++;
Serial.print("Button pressed! Total presses: ");
Serial.println(buttonPressCount);
}
// Update the last button state for next comparison
lastButtonState = buttonState;
// Debounce delay to prevent multiple counts from single press
delay(50);
}
```
## **Code Explanation**
### **Setup Function**
```cpp
void setup() {
pinMode(buttonPin, INPUT);
Serial.begin(9600);
Serial.println("Button Press Counter Lab Started");
Serial.print("Initial count: ");
Serial.println(buttonPressCount);
}
```
- Configures pin D5 as input for button reading
- Initializes serial communication for debugging
- Prints startup messages and initial counter value
### **Loop Function**
```cpp
void loop() {
int buttonState = digitalRead(buttonPin);
if (buttonState == HIGH && lastButtonState == LOW) {
buttonPressCount++;
Serial.print("Button pressed! Total presses: ");
Serial.println(buttonPressCount);
}
lastButtonState = buttonState;
delay(50);
}
```
### **Button State Reading:**
- **digitalRead(buttonPin)**: Reads current state of pin D5
- Returns **HIGH** (1) when button is pressed, **LOW** (0) when not pressed
### **Edge Detection:**
- **if (buttonState == HIGH && lastButtonState == LOW)**: Detects rising edge
- Only triggers when button transitions from LOW to HIGH
- Prevents multiple counts from button bounce
### **Counter Logic:**
- **buttonPressCount++**: Increments counter by 1
- **lastButtonState = buttonState**: Updates previous state for next comparison
### **Debouncing:**
- **delay(50)**: 50ms delay to allow switch to stabilize
- Prevents multiple rapid readings from mechanical bounce
### **Serial Communication**
- Displays current counter value after each button press
- Provides clear feedback about button press events
- Shows total count for user reference
## **Testing and Verification**
1. **Upload the code to Lonely Binary UNO R3**
2. **Open Serial Monitor** in Arduino IDE (Tools → Serial Monitor)
3. **Observe the behavior:**
- Initial count should display as 0
- Each button press should increment the counter
- Serial Monitor should show "Button pressed! Total presses: X"
- The button's built-in LED should light when pressed
4. **Verify counter accuracy:**
- Press button multiple times and verify count increases correctly
- Check that rapid pressing doesn't cause missed counts
- Confirm counter doesn't increment when button is held down
## **Troubleshooting**
### **Counter doesn't increment:**
- 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 Serial Monitor for button state readings
- Verify code uploaded successfully
### **Counter increments multiple times per press:**
- Increase the debounce delay (e.g., change **delay(50)** to **delay(100)**)
- Check for loose connections causing intermittent signals
- Verify button module is properly seated
### **Counter increments when button is held:**
- Check the edge detection logic in the if statement
- Verify **lastButtonState** is being updated correctly
- Ensure the condition **buttonState == HIGH && lastButtonState == LOW** is working
### **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
## **Experiment Variations**
### **1. Reset Counter with Long Press**
Reset counter when button is held for more than 3 seconds:
```cpp
unsigned long pressStartTime = 0;
bool buttonWasPressed = false;
void loop() {
int buttonState = digitalRead(buttonPin);
if (buttonState == HIGH && lastButtonState == LOW) {
// Button just pressed
buttonPressCount++;
pressStartTime = millis();
buttonWasPressed = true;
Serial.print("Button pressed! Total presses: ");
Serial.println(buttonPressCount);
} else if (buttonState == LOW && buttonWasPressed) {
// Button released
buttonWasPressed = false;
}
// Check for long press (3 seconds)
if (buttonWasPressed && (millis() - pressStartTime) > 3000) {
buttonPressCount = 0;
Serial.println("Counter reset!");
buttonWasPressed = false;
}
lastButtonState = buttonState;
delay(50);
}
```
### **2. Press Counter with LED Feedback**
Use built-in LED to show counter status:
```cpp
const int ledPin = 13; // Built-in LED
void loop() {
int buttonState = digitalRead(buttonPin);
if (buttonState == HIGH && lastButtonState == LOW) {
buttonPressCount++;
Serial.print("Button pressed! Total presses: ");
Serial.println(buttonPressCount);
// Flash LED based on counter value
for (int i = 0; i < buttonPressCount; i++) {
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
}
}
lastButtonState = buttonState;
delay(50);
}
```
### **3. Press Counter with Timestamp**
Add timestamps to each button press:
```cpp
void loop() {
int buttonState = digitalRead(buttonPin);
if (buttonState == HIGH && lastButtonState == LOW) {
buttonPressCount++;
unsigned long currentTime = millis();
Serial.print("Press #");
Serial.print(buttonPressCount);
Serial.print(" at ");
Serial.print(currentTime);
Serial.println(" ms");
}
lastButtonState = buttonState;
delay(50);
}
```
## **Questions for Understanding**
1. What is the difference between edge detection and level detection?
2. Why do we need to track the previous button state?
3. What is button debouncing and why is it important?
4. How does the counter prevent multiple increments from a single press?
5. What would happen if we removed the **delay(50)** from the code?
6. How can you modify the code to count button releases instead of presses?
7. What is the purpose of the **lastButtonState** variable?
8. How could you implement a counter that resets after reaching a certain value?
## **Next Steps**
- Try implementing a button press counter with reset functionality
- Experiment with different debounce delay values
- Learn about interrupt-based button handling for more responsive counting
- Explore combining button counter with LED displays
- Try creating a multi-button counter system
- Learn about EEPROM to make the counter persistent across power cycles
## **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