OneButton is an Arduino library for detecting button press patterns on a single digital input pin, supporting:
- Single clicks
- Double clicks
- Long presses with start/stop events
- Multi-click detection
- Press events
- Debouncing with configurable timing
The library comes in two versions:
- OneButton: Full-featured implementation for boards with ample memory
- OneButtonTiny: Lightweight variant for memory-constrained devices (attiny84, etc.)
License: BSD-3-Clause Repository: https://github.com/mathertel/OneButton
Prefer declaring buttons without initialization and using setup() in Arduino's setup() function:
// Declaration
OneButton btn;
// In setup()
btn.setup(BUTTON_PIN, INPUT_PULLUP, true); // pin, mode, activeLowThis ensures proper hardware initialization order and maximum compatibility.
OneButton uses callbacks (function pointers) for events. Two callback types are supported:
- Simple callbacks:
void callback(void) - Parameterized callbacks:
void callback(void *param)
OneButton implements a simple FSM internally for state tracking. When generating code, ensure:
tick()is called regularly in the main loop- Button logic is non-blocking
- Only one event fires per button state transition
// Configuration in setup()
btn.setDebounceMs(50); // Debouncing delay (default: 20ms)
btn.setClickMs(400); // Time to recognize single click (default: 400ms)
btn.setPressMs(800); // Time to trigger press event (default: 800ms)
btn.setLongPressIntervalMs(100); // Interval for repeated long-press callbacks (default: 0)
btn.setIdleMs(3000); // Auto-idle timeout (optional)When generating code that attaches events:
// Single click
btn.attachClick(handleClick);
btn.attachClick(handleClickWithParam, (void*)myData);
// Double click
btn.attachDoubleClick(handleDoubleClick);
// Press events
btn.attachPress(handlePress);
// Long press
btn.attachLongPressStart(handleLongPressStart);
btn.attachLongPressStop(handleLongPressStop);
// Multi-click (requires specific configuration)
btn.attachMultiClick(handleMultiClick);The tick() method must be called regularly:
void loop() {
btn.tick(); // Usually called on every iteration
// Other code...
}// Active state (requires getPressedMs() or related methods)
if (btn.isPressed()) { } // Button currently held down
if (btn.isLongPressed()) { } // Long press is active- Buttons/pins:
btn1,btn2,myButton,BUTTON_PIN_1(constants) - Callbacks:
handleClick(),onButtonPress(),button1_click() - Configuration variables: Use meaningful names with
Mssuffix for time values
- Global OneButton instances are acceptable for simplicity
- Prefer static arrays for multiple buttons in memory-constrained scenarios
- Use parameterized callbacks for passing context to handlers
// Simple callback (preferred for single-purpose buttons)
void handleClick() {
// Handle event
}
// Parameterized callback (better for multiple buttons with shared handler)
void handleClick(void *param) {
int buttonId = (int)param;
// Handle event based on buttonId
}OneButton btn;
void setup() {
btn.setup(BUTTON_PIN, INPUT_PULLUP, true);
btn.attachClick(handleClick);
btn.attachDoubleClick(handleDoubleClick);
btn.attachLongPressStart(handleLongStart);
btn.attachLongPressStop(handleLongStop);
}
void loop() {
btn.tick();
}
void handleClick() { /* single click logic */ }
void handleDoubleClick() { /* double click logic */ }
void handleLongStart() { /* long press started */ }
void handleLongStop() { /* long press ended */ }#define NUM_BUTTONS 3
OneButton buttons[NUM_BUTTONS];
int btn_pins[NUM_BUTTONS] = {2, 3, 4};
void setup() {
for (int i = 0; i < NUM_BUTTONS; i++) {
buttons[i].setup(btn_pins[i], INPUT_PULLUP, true);
buttons[i].attachClick(handleButtonClick, (void*)i);
}
}
void loop() {
for (int i = 0; i < NUM_BUTTONS; i++) {
buttons[i].tick();
}
}
void handleButtonClick(void *param) {
int buttonId = (int)param;
// Handle click for specific button
}#include <OneButtonTiny.h>
OneButtonTiny btn;
void setup() {
btn.setup(BUTTON_PIN, INPUT_PULLUP, true);
btn.attachClick(handleClick); // ✓ Available
btn.attachDoubleClick(handleDblClick); // ✓ Available
btn.attachLongPressStart(handleLong); // ✓ Available
// Note: MultiClick, LongPressStop NOT available in Tiny version
}- Default debounce is 20ms, usually sufficient
- Increase
setDebounceMs()if experiencing phantom clicks or noise
debounce < click < press < longPress
Example: 20ms < 400ms < 800ms < varies
- Multiple event triggers: Ensure
tick()is called once per loop iteration - Slow response: Call
tick()more frequently (no delays in loop) - Button state changes not detected: Verify PIN configuration and
activeLowsetting - Long press interferes with click: Adjust
setClickMs()andsetPressMs()values
When generating test code:
// Simulate button press duration (in mock/test environment)
void testSingleClick(OneButton &btn) {
// Simulate 100ms press
pressButton(btn);
delay(100);
releaseButton(btn);
delay(500); // Wait for single-click detection
}
void testDoubleClick(OneButton &btn) {
pressButton(btn);
delay(50);
releaseButton(btn);
delay(100); // Brief interval between clicks
pressButton(btn);
delay(50);
releaseButton(btn);
}When using Copilot to generate OneButton code, be specific about:
- Button behavior: "Generate code for detecting single and double clicks"
- Timing requirements: "Set debounce to 50ms and click detection to 500ms"
- Callback style: Request either simple or parameterized callbacks
- Multi-button scenarios: Specify number of buttons and how to differentiate them
- Memory constraints: Mention if OneButtonTiny should be used instead of OneButton
- "Add a long-press handler to toggle an LED when held for 1 second"
- "Create a multi-button setup with 3 buttons, each calling a different function"
- "Generate a debounced button click counter that prints to Serial"
The library includes comprehensive examples:
examples/SimpleOneButton- Basic single button usageexamples/FunctionalButton- Using C++ lambda callbacksexamples/TwoButtons- Multiple button managementexamples/LongPressEvents- Long press detectionexamples/SpecialInput- Custom input sourcesexamples/InterruptOneButton- Interrupt-based detectionexamples/BlinkMachine- State machine example
When generating code, avoid these legacy method names:
setDebounceTicks()→ UsesetDebounceMs()insteadsetClickTicks()→ UsesetClickMs()insteadsetPressTicks()→ UsesetPressMs()instead
Current version: 2.6.2
- Homepage: http://www.mathertel.de/Arduino/OneButtonLibrary.aspx
- Repository: https://github.com/mathertel/OneButton
- License: BSD-3-Clause (see LICENSE file)
- Author: Matthias Hertel (mathertel@hotmail.com)