GPIOUtils is a lightweight, composable toolkit for writing clean, non-blocking Arduino code.
It solves the small but persistent problems that make embedded code messy:
- switch bounce
- noisy analog signals
- timing logic scattered everywhere
- awkward state machines
- one-off hacks that don’t scale
Instead of monolithic frameworks, GPIOUtils gives you small building blocks that snap together cleanly.
With a few simple components, you can build behaviour like:
- A button with debounce + long-press + auto-repeat
- An analog input with noise suppression + hysteresis
- A clean event pipeline like:
button → debounce → edge → long-press → one-shot → timed output
- Non-blocking timing like:
- periodic tasks
- pulse generation
- delayed triggers
- rate-limited signals
All without delay() and without tangled logic.
GPIOUtils follows a few strict rules:
1. No hidden side effects
Constructors never touch hardware.
All setup happens explicitly in:
begin();- If a class owns a pin → it configures it
- If it doesn’t → it never touches hardware
Instead of giant helper classes, everything is designed to chain:
raw input → conditioning → event → timing → output
You build exactly what you need—nothing more.
-
AnalogCalibrator
Fix real-world ADC range issues (inputs that don’t hit full scale) -
Dejitter
Removes small analog noise (deadband filtering) -
Schmitt
Converts noisy analog signals into stable digital states (hysteresis)
-
Debounce
Clean up mechanical switches -
EdgeDetector
Detect rising/falling edges cleanly -
GlitchFilter
Reject short spikes and false triggers
-
OneShotEvent
Fire a fixed-duration event (optionally delayed) -
PulseGenerator
Generate pulse trains (finite or continuous) -
AutoRepeat
Keyboard-style repeating input -
MultiPress
Detect double/triple clicks -
LongPressDetector
Detect press-and-hold actions -
Toggle
Convert events into persistent state -
RateLimiter
Smooth or constrain value changes -
PeriodicTimer
Generate regular ticks without blocking
- TimedOutput (owns a pin)
Drive outputs with:- timed pulses
- scheduled transitions
- non-blocking control
adcToU8()→ ADC → 8-bitadcToFloat()→ normalizedadcToFloat(min, max)→ scaled range
Instead of tangled code:
if (buttonPressed && !lastState && millis() - lastTime > 50) { ... }You get:
Debounce button(2);
EdgeDetector edge;
OneShotEvent pulse(1000);
void loop() {
bool clean = button.update();
if (edge.rising(clean)) {
pulse.trigger();
}
if (pulse.update()) {
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(LED_PIN, LOW);
}
// Do something else (nonblocking) ...
}Readable. Testable. Composable.
GPIOUtils/
src/
GPIOUtils.h
impl/
examples/
Only include:
#include <GPIOUtils.h>Start here:
👉 examples/README.md
- No blocking (
delay()-free) - No frameworks or magic
- Small, focused components
- Easy to reason about
- Works on any Arduino-compatible board
“Do one thing well, and compose everything else.”