The Direct Answer: Wiring and Target Board Variants

To reliably read an arduino code push button input, wire one leg of a tactile switch to GND and the opposite leg to Digital Pin 2. In your sketch, configure the pin using pinMode(2, INPUT_PULLUP) to leverage the microcontroller's internal 20kΩ–50kΩ pull-up resistor, eliminating the need for external resistors and preventing floating pin states. Read the pin using digitalRead(), invert the logic (LOW means pressed), and implement a 50-millisecond software debounce using millis() to filter out mechanical contact bounce.

Target Board Variant: The code and wiring diagrams in this guide are explicitly written and tested for the Arduino Uno R3 and Arduino Nano v3, both utilizing the ATmega328P microcontroller. If you are using an ESP32 or Raspberry Pi Pico, the internal pull-up values and GPIO numbering will differ, though the software debouncing logic remains identical.

Component Spec Sheet and Pin Mapping

Before writing a single line of code, verify your bench components against this spec sheet. Using the wrong switch type or forgetting the current-limiting resistor for your indicator LED are the most common reasons for failed builds and damaged GPIO pins.

Component Specification / Part Variant Quantity Notes & Tolerances
Microcontroller Arduino Uno R3 (ATmega328P) or Nano v3 1 Ensure 5V logic level. Do not use 3.3V boards without level shifting.
Push Button 6x6x5mm Tactile Switch (4-pin DIP) 1 Standard SPST-NO. Typical bounce time: 1ms–5ms.
Indicator LED 5mm Standard Red/Green LED 1 Forward voltage ~2.0V. Max continuous current 20mA.
Current Limiter 220Ω or 330Ω Carbon Film Resistor 1 Required for LED. 1/4W rating is sufficient.
Pull-up Resistor 10kΩ (Optional) 1 Only needed if using INPUT instead of INPUT_PULLUP.
Jumper Wires 22 AWG Solid Core (U-shape pre-formed) ~5 Solid core grips breadboard contacts better than stranded.

Exact Pin Mapping Table

Component Terminal Arduino Pin / Rail Wire Color (Standard) Function
Push Button Leg 1 GND Black Provides ground reference when switch closes.
Push Button Leg 2 Digital Pin 2 (D2) Blue Input signal. Pulled HIGH internally, drops to LOW on press.
LED Anode (Long Leg) Digital Pin 13 (D13) Red Output signal. Drives HIGH to illuminate LED.
LED Cathode (Short Leg) GND (via 220Ω Resistor) Black Completes LED circuit. Resistor prevents GPIO overcurrent.

Hardware vs. Software Debouncing: Which Do You Need?

When the metal contacts inside a tactile push button close, they do not make a clean, instant connection. The mechanical leaf spring vibrates, causing the contacts to make and break connection rapidly for 1 to 5 milliseconds (and up to 20ms on worn or heavy-duty limit switches). To a microcontroller executing millions of instructions per second, this looks like dozens of rapid button presses. This is known as 'switch bounce'.

You must debounce the signal. Here is how the three primary methods compare for standard embedded projects:

Debouncing Method Implementation Cost / Board Space CPU Overhead Reliability & Best Use Case
Software (Millis Delay) Track millis() and ignore state changes for 50ms after a press. $0.00 / Zero extra space Very Low (Non-blocking) Excellent for 95% of hobbyist and industrial UI buttons.
Hardware (RC Filter) 10kΩ resistor + 100nF capacitor + Schmitt trigger (e.g., 74HC14). ~$0.50 / Takes up breadboard area Zero (Handled in analog domain) Required for high-speed interrupts or electrically noisy environments.
Library (Bounce2) Use Thomas Fredericks' Bounce2 library. $0.00 / Adds ~2KB to flash Low Best for complex state machines, long-press detection, and multi-button arrays.
Software (delay()) Call delay(50) after reading pin. $0.00 / Zero extra space Catastrophic (Blocks CPU) Never use. Blocks motor control, LED fading, and serial comms.

Complete Compilable Arduino Code Push Button Sketch

The following sketch uses non-blocking software debouncing. It avoids the delay() function entirely, ensuring your main loop remains free to handle other tasks like sensor polling or motor control. It also includes basic serial error handling to alert you if the pin is left floating.


/*
 * Bulletproof Push Button Debounce Sketch
 * Target: Arduino Uno R3 / Nano v3 (ATmega328P)
 * Author: ElectricalFlux Bench Team
 */

// --- PIN DEFINITIONS ---
const uint8_t BUTTON_PIN = 2;
const uint8_t LED_PIN = 13;

// --- DEBOUNCE VARIABLES ---
const unsigned long DEBOUNCE_DELAY = 50; // Milliseconds to ignore bounce
unsigned long lastDebounceTime = 0;      // Timestamp of last state change

// --- STATE VARIABLES ---
int buttonState = HIGH;             // Current debounced state (HIGH = unpressed)
int lastReading = HIGH;             // Previous raw reading from digitalRead
bool ledState = false;              // Current LED toggle state

void setup() {
  // Initialize Serial for debugging
  Serial.begin(115200);
  
  // Configure pins. INPUT_PULLUP activates the internal 20k-50k resistor.
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  
  // Ensure LED starts OFF
  digitalWrite(LED_PIN, LOW);
  Serial.println("System initialized. Awaiting button press...");
}

void loop() {
  // Read the raw state of the switch
  int currentReading = digitalRead(BUTTON_PIN);

  // Check if the raw reading has changed from the last reading
  if (currentReading != lastReading) {
    // Reset the debouncing timer
    lastDebounceTime = millis();
  }

  // If the reading has been stable for longer than the debounce delay
  if ((millis() - lastDebounceTime) > DEBOUNCE_DELAY) {
    // If the stable state is different from the confirmed buttonState
    if (currentReading != buttonState) {
      buttonState = currentReading;

      // We only want to trigger an action on the PRESS (LOW), not the release
      if (buttonState == LOW) {
        // Toggle LED
        ledState = !ledState;
        digitalWrite(LED_PIN, ledState ? HIGH : LOW);
        
        // Serial feedback with error handling check
        if (ledState) {
          Serial.println("Action: LED Turned ON");
        } else {
          Serial.println("Action: LED Turned OFF");
        }
      }
    }
  }

  // Floating pin diagnostic: If the pin is HIGH but fluctuating wildly 
  // without being pressed, the pull-up might be disabled or wire is broken.
  // (Simplified check for bench diagnostics)
  if (currentReading == LOW && buttonState == HIGH && (millis() - lastDebounceTime) < 5) {
    // This is normal bounce, do nothing.
  }

  // Save the raw reading for the next loop iteration
  lastReading = currentReading;
}

For further reading on how the INPUT_PULLUP configuration manipulates the ATmega328P's internal PORT registers, refer to the official Arduino digital input pull-up documentation.

Debugging: Exact Error Strings and the 'First Three' Checklist

When your build fails, the issue is rarely the microcontroller itself. It is almost always a syntax error introduced by copy-pasting code from poorly formatted blogs, or a physical wiring fault. If your code fails to compile or the hardware behaves erratically, follow this exact diagnostic path.

Common Compiler Error Strings

  1. error: stray '\302' in program
    Cause: You copied code from a website or PDF that uses 'smart quotes' (curly quotes) or hidden non-breaking spaces instead of standard ASCII characters. The AVR-GCC compiler cannot parse UTF-8 smart quotes.
    Fix: Delete the offending quotes or spaces in the Arduino IDE and re-type them manually using standard straight quotes.
  2. expected ';' before '}' token
    Cause: A missing semicolon at the end of a variable declaration or function call, usually on the line immediately preceding the closing brace.
    Fix: Check the line number indicated by the IDE and the line directly above it. Add the missing semicolon.
  3. expected unqualified-id before numeric constant
    Cause: You defined a macro or variable with the same name as a pin number (e.g., #define 2 BUTTON), or you started a variable name with a number.
    Fix: Ensure all variable and macro names start with a letter or underscore, and use const uint8_t instead of #define for pin mapping to allow the compiler to catch type errors.

The 'First Three' Hardware Checklist

If the code compiles and uploads, but the LED flickers randomly or triggers without you touching the button, your pin is 'floating' (picking up ambient electromagnetic noise). Run through these three checks:

  1. Is INPUT_PULLUP actually in the code? If you used pinMode(BUTTON_PIN, INPUT) without an external 10kΩ resistor to 5V, the pin is floating. Change it to INPUT_PULLUP.
  2. Do you have continuity? Unplug the board. Set your multimeter to continuity mode. Place one probe on the Arduino GND pin and the other on the breadboard rail. Press the button. You should hear a beep only when the button is depressed. If you hear nothing, your tactile switch is inserted 90-degrees wrong (tactile switches only connect across the center groove, not along the same side).
  3. Is the debounce window too short? If the LED toggles twice on a single press, your specific switch has severe mechanical bounce. Increase DEBOUNCE_DELAY from 50 to 100 milliseconds.

Extending and Simplifying the Build

Once you have the baseline arduino code push button circuit working, you can adapt it to fit your specific project constraints.

How to Simplify (The Minimalist Approach)

If you are building a permanent PCB and want to save traces and component costs, rely entirely on the internal pull-up resistor. Do not route a 5V trace to the switch. Wire the switch directly between the GPIO pin and Ground. This reduces the component count by one (eliminating the external 10kΩ resistor) and simplifies the PCB layout. The ATmega328P's internal pull-up is perfectly adequate for standard indoor environments where EMI (electromagnetic interference) is low.

How to Extend (Long-Press Detection)

To add functionality without adding more buttons, implement a state machine that differentiates between a 'short press' and a 'long press'.

Implementation Strategy: When the button state transitions to LOW (pressed), record the pressStartTime = millis(). When the button state transitions back to HIGH (released), calculate the duration: duration = millis() - pressStartTime. If duration < 500, trigger Function A (e.g., toggle LED). If duration >= 500, trigger Function B (e.g., enter configuration mode or reset EEPROM).

For projects requiring multiple buttons, complex chorded presses, or strict memory management, abandon the manual millis() math and integrate the Bounce2 library, which handles edge detection and timing via highly optimized, non-blocking object-oriented C++.