Overview
Push buttons are the most fundamental way to add interactivity to your projects. They allow users to control devices, trigger actions, and make selections. On the Vumbua Synapse Kit, the push button is pre-connected to Digital Pin D7 of the ATmega328P microcontroller.
In this lesson, you'll learn not only how to read button states, but also crucial concepts like pull-up resistors and debouncing that ensure reliable input in real-world applications.
Push buttons are used in countless applications:
- Power switches on electronic devices
- Game controller buttons
- Elevator floor selection
- Microwave oven controls
- Industrial machine controls
- Emergency stop buttons
- Keyboard keys
Prerequisites
Before starting Lesson 2, make sure you have completed:
Completed Lessons
- Lesson 1: Blinking LED
- Understanding of
setup()andloop() - Using
pinMode()anddigitalWrite() - Basic Serial Monitor usage
Hardware Requirements
- Vumbua Synapse Kit with push button
- USB Type-C cable
- Computer with Arduino IDE installed
The push button is pre-connected to the Vumbua board on Digital Pin D7. It includes an internal pull-up resistor - you can start programming immediately without any wiring!
The button is located near the top-right corner of the board, labeled "BUTTON" or with a tactile switch icon.
Learning Objectives
By the end of this lesson, you will be able to:
- Understand how push buttons work electrically
- Configure digital pins as inputs with
pinMode() - Read button states using
digitalRead() - Understand and use internal pull-up resistors
- Implement button debouncing techniques
- Create interactive button-controlled LED projects
- Use buttons to toggle between different states
- Display button status on Serial Monitor
- Understand the ATmega328P's digital I/O system
What is a Push Button?
Mechanical Operation
A push button is a simple switch that makes or breaks an electrical connection when pressed. Most buttons have four pins internally connected in pairs:
- Two pins are always connected (common connection)
- The other two pins connect when button is pressed
- This is called a "push-to-make" or "normally open" switch
- When released, the connection opens again
Electrical Characteristics
Buttons are characterized by:
- Contact Resistance: Very low when closed (< 0.1Ω)
- Bounce Time: Mechanical vibration when pressed (1-50ms)
- Actuation Force: Pressure needed to press (varies by type)
- Lifecycle: Number of presses before failure (50K-1M+)
Types of Buttons
Common types in electronics:
- Tactile Switches: Small, clicky buttons (like on Vumbua)
- Momentary Switches: Return to original state when released
- Toggle Switches: Stay in position until switched again
- Pushbutton Switches: Larger industrial buttons
- Membrane Switches: Flat, flexible buttons
Button Internal Connections
Pins 1-2 are always connected internally
Pins 3-4 are always connected internally
When pressed, all four pins connect together
Button Connections on Vumbua
The push button on the Vumbua Synapse Kit is connected as follows:
Circuit Diagram - Vumbua Button Connection
Normal State (Button NOT pressed): D7 reads HIGH (5V) through pull-up resistor
Pressed State (Button pressed): D7 reads LOW (0V) connected to GND
Understanding Pull-up Resistors
Pull-up resistors are essential for reliable button reading:
The Floating Pin Problem
Without a pull-up resistor, when a button is not pressed, the microcontroller pin is "floating" - not connected to anything. This can cause:
- Random HIGH/LOW readings due to electrical noise
- Unreliable button detection
- False triggers from static electricity
Pull-up Solution
A pull-up resistor connects the pin to 5V through a high resistance (10KΩ typical). This ensures:
- Pin reads HIGH when button is NOT pressed
- Pin reads LOW when button IS pressed (connects to GND)
- Clear, unambiguous signal levels
- Protection against electrical noise
Internal vs External Pull-ups
The ATmega328P has built-in pull-up resistors that can be enabled in software:
- Internal Pull-up: ~20KΩ resistor inside microcontroller
- External Pull-up: Physical resistor on circuit board
- Vumbua Kit: Uses external 10KΩ pull-up for reliability
- Enabling:
pinMode(pin, INPUT_PULLUP);
| Button State | Electrical Connection | Pin D7 Voltage | digitalRead() |
Internal Logic |
|---|---|---|---|---|
| NOT Pressed | Open circuit | 5V (through pull-up) | HIGH (1) | Logic 1 |
| PRESSED | Connected to GND | 0V | LOW (0) | Logic 0 |
With pull-up resistors, buttons use active-LOW logic:
- HIGH (1): Button NOT pressed (default state)
- LOW (0): Button IS pressed (active state)
This is opposite to what beginners might expect, but it's the standard for reliable
digital input. Always check for LOW to detect button presses!
Using digitalRead() Function
The digitalRead() function reads the state of a digital pin:
Function Syntax
int buttonState = digitalRead(pin);
Where pin is the digital pin number (D7 for Vumbua button).
Return Values
digitalRead() returns either:
- HIGH: Voltage ≥ 3V (logic 1)
- LOW: Voltage ≤ 2V (logic 0)
For buttons with pull-up resistors:
HIGH= Button NOT pressedLOW= Button IS pressed
Setup Requirements
Before using digitalRead(), you must configure the pin:
// For external pull-up (like Vumbua) pinMode(pin, INPUT); // For internal pull-up (if no external resistor) pinMode(pin, INPUT_PULLUP);
The Vumbua Synapse Kit uses an external 10KΩ pull-up,
so use INPUT mode.
Basic Button Reading
Let's start with a simple program to read and display button states:
button_basic.ino
/* Vumbua Synapse Kit - Lesson 2: Basic Button Reading Read digital input from push button on pin D7 Display button state on Serial Monitor */ const int buttonPin = 7; // Push button connected to digital pin 7 int buttonState = 0; // Variable to store button state void setup() { // Initialize Serial communication at 9600 bps Serial.begin(9600); // Initialize button pin as input // Vumbua uses external pull-up resistor, so use INPUT mode pinMode(buttonPin, INPUT); Serial.println("Vumbua Synapse Kit - Button Reading Program"); Serial.println("==========================================="); Serial.println("Press the button to see state change from HIGH to LOW"); Serial.println("Remember: LOW means button is PRESSED (active-low logic)"); Serial.println(); } void loop() { // Read the state of the button buttonState = digitalRead(buttonPin); // Display button state Serial.print("Button State: "); if (buttonState == HIGH) { Serial.print("HIGH"); Serial.println(" (NOT pressed)"); } else { Serial.print("LOW"); Serial.println(" (PRESSED!)"); } // Wait for 100 milliseconds before next reading // This prevents Serial Monitor from flooding too fast delay(100); }
Testing the Program
1. Upload the Code
Upload to your Vumbua Synapse Kit. The button is already connected to pin D7 on the board.
2. Open Serial Monitor
Go to Tools → Serial Monitor or press Ctrl+Shift+M.
Set the baud rate to 9600.
3. Press and Release the Button
Watch the Serial Monitor output:
- When button is NOT pressed: Should show "HIGH (NOT pressed)"
- When button is PRESSED: Should show "LOW (PRESSED!)"
Try pressing and holding for a few seconds to see the continuous readings.
Click the button above to simulate the physical button press on your Vumbua Kit.
Button Controlled LED
Now let's combine button input with LED output to create an interactive project:
button_led_control.ino
/* Vumbua Synapse Kit - Lesson 2: Button Controlled LED Control LED on pin 9 using push button on pin 7 LED turns ON only when button is pressed */ const int buttonPin = 7; // Button on digital pin 7 const int ledPin = 9; // LED on digital pin 9 int buttonState = 0; // Variable for button state void setup() { // Initialize serial communication Serial.begin(9600); // Initialize button pin as input pinMode(buttonPin, INPUT); // Initialize LED pin as output pinMode(ledPin, OUTPUT); Serial.println("Button Controlled LED System"); Serial.println("LED will turn ON when button is pressed"); } void loop() { // Read the button state buttonState = digitalRead(buttonPin); // Check if button is pressed (active-low logic) if (buttonState == LOW) { // Button is pressed - turn LED ON digitalWrite(ledPin, HIGH); Serial.println("Button PRESSED - LED ON"); } else { // Button is not pressed - turn LED OFF digitalWrite(ledPin, LOW); Serial.println("Button RELEASED - LED OFF"); } // Small delay to make Serial Monitor readable delay(50); }
Challenge: Toggle LED with Button Press
Modify the program so the LED toggles (changes state) each time you press the button:
button_led_toggle.ino
/* Vumbua Synapse Kit - Lesson 2: LED Toggle with Button Toggle LED state each time button is pressed Includes debouncing for reliable toggling */ const int buttonPin = 7; // Button on pin 7 const int ledPin = 9; // LED on pin 9 int buttonState; // Current button reading int lastButtonState = HIGH; // Previous button reading int ledState = LOW; // Current LED state // Variables for debouncing unsigned long lastDebounceTime = 0; unsigned long debounceDelay = 50; void setup() { Serial.begin(9600); pinMode(buttonPin, INPUT); pinMode(ledPin, OUTPUT); // Set initial LED state digitalWrite(ledPin, ledState); Serial.println("LED Toggle System Ready"); Serial.println("Press button to toggle LED"); } void loop() { // Read the button state int reading = digitalRead(buttonPin); // Check if button state changed (due to noise or pressing) if (reading != lastButtonState) { // Reset the debouncing timer lastDebounceTime = millis(); } // Check if enough time has passed since last change if ((millis() - lastDebounceTime) > debounceDelay) { // If the button state has changed: if (reading != buttonState) { buttonState = reading; // Only toggle the LED if the new button state is LOW (pressed) if (buttonState == LOW) { ledState = !ledState; // Toggle LED state digitalWrite(ledPin, ledState); // Print status to Serial Monitor if (ledState == HIGH) { Serial.println("LED turned ON"); } else { Serial.println("LED turned OFF"); } } } } // Save the current reading as last state for next loop lastButtonState = reading; }
The toggle program introduces the concept of a state machine - the LED has two states (ON/OFF) and the button causes transitions between them.
This pattern is fundamental to more complex programs where devices have multiple modes or states (like a traffic light controller).
Button Debouncing
Mechanical buttons have a physical phenomenon called "bouncing" that must be handled:
What is Button Bounce?
When a button is pressed or released, the metal contacts don't make perfect contact immediately. They physically vibrate (bounce) for a few milliseconds, causing multiple rapid ON-OFF transitions.
Without debouncing, a single button press might be detected as multiple presses!
Bounce Characteristics
- Duration: Typically 1-50 milliseconds
- Cause: Mechanical vibration of contacts
- Effect: Multiple rapid state changes
- Solution: Software or hardware debouncing
Debouncing Methods
- Software Debouncing: Ignore changes for a few ms after detection
- Hardware Debouncing: RC circuit (resistor + capacitor)
- Debounce Library: Pre-written code for easy implementation
- Vumbua Approach: Software debouncing (shown in toggle example)
Button Bounce Visualization
Simple Debouncing Code
// Simple debouncing function
bool isButtonPressed() {
static unsigned long lastPressTime = 0;
const unsigned long debounceTime = 50; // milliseconds
// Read current button state
int currentState = digitalRead(buttonPin);
// If button is pressed (LOW) and enough time has passed
if (currentState == LOW && (millis() - lastPressTime) > debounceTime) {
lastPressTime = millis();
return true;
}
return false;
}
The Vumbua Synapse Kit includes both hardware and software considerations for reliable button input:
- Hardware: 10KΩ pull-up resistor for stable signal
- Hardware: Quality tactile switch with minimal bounce
- Software: Debouncing code examples provided
- Education: Understanding both approaches taught
ATmega328P Digital I/O System
Understanding how the microcontroller handles digital I/O helps you write better code:
Port Registers
The ATmega328P organizes digital pins into three 8-bit ports:
- PORTB: Digital pins 8-13
- PORTC: Analog pins A0-A5
- PORTD: Digital pins 0-7 (D7 is here!)
Pin D7 is bit 7 of PORTD. Each port has three registers:
- DDRx: Data Direction Register (input/output)
- PORTx: Data Register (write outputs)
- PINx: Pin Input Register (read inputs)
How digitalRead() Works Internally
When you call digitalRead(7):
- Arduino translates pin 7 to PORTD, bit 7
- Reads the PIN register for that port
- Extracts the specific bit (bit 7)
- Returns HIGH (1) or LOW (0) based on bit value
- This happens in about 50 nanoseconds!
Direct Port Manipulation (Advanced)
For maximum speed, you can manipulate ports directly:
// Set pin 7 as input (equivalent to pinMode(7, INPUT)) DDRD &= ~(1 << 7); // Enable internal pull-up on pin 7 PORTD |= (1 << 7); // Read pin 7 state (equivalent to digitalRead(7)) bool state = (PIND & (1 << 7)) != 0;
This is faster but less readable - use only when speed is critical!
| Arduino Function | Equivalent Register Operation | For Pin D7 | Speed |
|---|---|---|---|
pinMode(7, INPUT) |
DDRD &= ~(1 << 7) |
Clear bit 7 of DDRD | ~3.5μs |
pinMode(7, OUTPUT) |
DDRD |= (1 << 7) |
Set bit 7 of DDRD | ~3.5μs |
digitalRead(7) |
(PIND & (1 << 7)) |
Read bit 7 of PIND | ~4.5μs |
digitalWrite(7, HIGH) |
PORTD |= (1 << 7) |
Set bit 7 of PORTD | ~4.5μs |
Advanced Applications
Project 1: Multi-Click Detector
Detect single, double, and triple clicks on the same button:
multi_click_detector.ino
/* Vumbua Synapse Kit - Multi-Click Detector Detect single, double, and triple button clicks */ const int buttonPin = 7; const int ledPin = 9; int clickCount = 0; unsigned long lastClickTime = 0; const unsigned long clickTimeout = 400; // Time between clicks in ms void setup() { Serial.begin(9600); pinMode(buttonPin, INPUT); pinMode(ledPin, OUTPUT); Serial.println("Multi-Click Detector Ready"); Serial.println("Try single, double, or triple clicks"); } void loop() { int buttonState = digitalRead(buttonPin); if (buttonState == LOW) { // Button is pressed unsigned long currentTime = millis(); // Check if this is a new click (not holding) if (currentTime - lastClickTime > 200) { clickCount++; lastClickTime = currentTime; // Visual feedback - blink LED digitalWrite(ledPin, HIGH); delay(50); digitalWrite(ledPin, LOW); } // Wait for button release while (digitalRead(buttonPin) == LOW) { // Wait for release } delay(10); // Debounce } // Check for click sequence timeout if (millis() - lastClickTime > clickTimeout && clickCount > 0) { // Timeout reached - process the clicks switch (clickCount) { case 1: Serial.println("Single click detected"); blinkLED(1); break; case 2: Serial.println("Double click detected"); blinkLED(2); break; case 3: Serial.println("Triple click detected"); blinkLED(3); break; default: Serial.print("Multiple clicks detected: "); Serial.println(clickCount); blinkLED(clickCount); } clickCount = 0; // Reset counter } } void blinkLED(int times) { for (int i = 0; i < times; i++) { digitalWrite(ledPin, HIGH); delay(200); digitalWrite(ledPin, LOW); delay(200); } }
Project 2: Button Controlled LED Modes
Use button to cycle through different LED patterns:
led_mode_controller.ino
/* Vumbua Synapse Kit - LED Mode Controller Cycle through LED modes with button presses */ const int buttonPin = 7; const int ledPin = 9; int mode = 0; // Current mode (0-3) int lastButtonState = HIGH; unsigned long lastModeChange = 0; void setup() { Serial.begin(9600); pinMode(buttonPin, INPUT); pinMode(ledPin, OUTPUT); Serial.println("LED Mode Controller"); Serial.println("Press button to cycle through modes"); Serial.println("Mode 0: LED Off"); Serial.println("Mode 1: LED On"); Serial.println("Mode 2: Blinking"); Serial.println("Mode 3: Breathing (PWM)"); } void loop() { // Check for button press to change mode int currentButtonState = digitalRead(buttonPin); if (currentButtonState == LOW && lastButtonState == HIGH) { // Button just pressed - debounce check if (millis() - lastModeChange > 300) { mode = (mode + 1) % 4; // Cycle through 0-3 lastModeChange = millis(); Serial.print("Mode changed to: "); Serial.println(mode); } } lastButtonState = currentButtonState; // Execute current mode switch (mode) { case 0: // LED Off digitalWrite(ledPin, LOW); break; case 1: // LED On digitalWrite(ledPin, HIGH); break; case 2: // Blinking digitalWrite(ledPin, HIGH); delay(250); digitalWrite(ledPin, LOW); delay(250); break; case 3: // Breathing (PWM) // Fade in for (int brightness = 0; brightness <= 255; brightness++) { analogWrite(ledPin, brightness); delay(5); if (checkButton()) return; // Check for mode change } // Fade out for (int brightness = 255; brightness >= 0; brightness--) { analogWrite(ledPin, brightness); delay(5); if (checkButton()) return; // Check for mode change } break; } } bool checkButton() { if (digitalRead(buttonPin) == LOW) { delay(50); // Debounce return true; } return false; }
Troubleshooting Common Issues
- Check: Button is properly connected to D7 on Vumbua
- Verify: Using
pinMode(7, INPUT)not OUTPUT - Test: Measure voltage at D7 pin with multimeter
- Try: Different button if available (could be stuck)
- Remember: Vumbua uses active-LOW logic (LOW = pressed)
- Symptom: One button press triggers multiple actions
- Cause: Button bouncing (mechanical vibration)
- Solution: Implement debouncing (see examples above)
- Debounce Time: Start with 50ms, adjust as needed
- Alternative: Use hardware debouncing with capacitor
- Check: LED is connected to correct pin (pin 9 in examples)
- Verify: LED polarity (long leg to +, short to -)
- Test: LED with simple blink program first
- Confirm: Using
digitalWrite(ledPin, HIGH/LOW)correctly - Remember: Check Serial Monitor for button state feedback
- Cause: Floating input pin (no pull-up resistor)
- Solution: Vumbua has external pull-up, ensure proper connection
- Alternative: Enable internal pull-up:
pinMode(7, INPUT_PULLUP) - Check: For loose connections or damaged button
- Test: With different delay values in loop
Debugging Tips
1. Serial Monitor is Your Friend
Always print button states to Serial Monitor for debugging. This helps you see exactly what the microcontroller is reading.
void loop() {
int state = digitalRead(7);
Serial.print("Button state: ");
Serial.println(state);
delay(100);
}
2. Test with Known Good Code
Start with the simplest button reading program. If that works, gradually add complexity (debouncing, toggling, etc.).
3. Check Hardware First
80% of button issues are hardware-related:
- Loose connections
- Damaged button
- Incorrect wiring
- Power supply issues
Video Demonstration
Video Tutorial Coming Soon!
We're preparing a detailed video walkthrough for this lesson.
Subscribe to our YouTube channel to be notified when it's available.
Subscribe to OLSPACEWhat's Next?
Congratulations! You've successfully mastered digital input with push buttons. Here's what you've accomplished:
- ✓ Learned how push buttons work electrically and mechanically
- ✓ Used
digitalRead()to read button states from D7 - ✓ Understood pull-up resistors and active-LOW logic
- ✓ Implemented button debouncing techniques
- ✓ Created button-controlled LED projects
- ✓ Built toggle switches and mode selectors
- ✓ Understood the ATmega328P's digital I/O system
- ✓ Learned troubleshooting techniques for button issues
In the next lesson, you'll explore sound generation:
Lesson 3: Buzzer - Sound Generation
Learn to generate tones and melodies using the piezo buzzer on your Vumbua Synapse Kit. Create audible alerts, simple music, and sound effects that respond to button presses and other inputs.
Resources & Downloads
Download Complete Code
Get all the code files for this lesson: