Skip to main content

Digital Input Reading (Push Button) Tutorial

· 7 min read
Jon Otero Fernández
Author of JARU
BeginnerGPIOWindows VMESP32

After blinking an LED, the next natural step is reading the outside world. In this tutorial you will learn how to connect a push button, read its state with GPIO.read, and finally react to presses using interrupts — all tested first in the Windows simulator and then on your physical ESP32.

What you need

  • JARU IDE installed on your PC — you can complete the entire tutorial with just this.
  • (Optional) An ESP32 board, a push button, an LED, resistors, and a USB cable.

Step 1: The code — Polling

The most straightforward way to read a push button is to constantly check its state inside the main loop. Open JARU IDE, create a new file called button.aru, and type the following code:

button.aru
// Import the GPIO module to control pins
use GPIO

println("Starting button reading...");

// 1. Pin configuration
// Pin 4: push button with internal pull-up resistor (reads HIGH when not pressed)
GPIO.pinmode(4, GPIO.PULLUP);

// Pin 2: built-in LED as output
GPIO.pinmode(2, GPIO.OUTPUT);

println("Hardware configured. Waiting for presses...");

// 2. Main loop — polling
while (true)
var state = GPIO.read(4);

if (state == LOW) then
// The button is pressed (connects to GND → reads LOW)
GPIO.write(2, HIGH);
println("Button pressed → LED on");
else
GPIO.write(2, LOW);
end

pause(50); // Small debounce delay
end
Why GPIO.PULLUP?

When you configure a pin with GPIO.PULLUP, the ESP32 enables an internal resistor that keeps the pin at HIGH when nothing is connected. When the button is pressed and connects the pin to GND, the level drops to LOW. This way you don't need an external resistor.

What each part does

GPIO.pinmode(4, GPIO.PULLUP) configures pin 4 as a digital input with an internal pull-up resistor. The pin reads HIGH at rest and LOW when the button connects to GND.

GPIO.read(4) returns the current digital state of the pin: HIGH (1) or LOW (0).

state == LOW detects that the button is pressed. With pull-up, the logic is inverted: pressed = LOW.

pause(50) introduces a 50 ms delay that acts as a basic debounce filter, preventing erratic readings caused by the mechanical bounce of the button.


Step 2: Simulation on Windows

  1. Open the GPIO Simulator from the IDE menu Build → GPIO Sim.
  2. Add pin 4 manually with the New GPIO button and attach a PushButton card.
  3. Add pin 2 and attach an LED card.
  4. Click Run to execute the program on the VM.
  5. You will see the startup messages in the output console.
  6. Press the button on the PushButton card in the simulator and watch the LED card turn on while you hold it down. When you release it, the LED turns off.

GPIO Simulator Example

Starting button reading...
Hardware configured. Waiting for presses...
Button pressed → LED on
Button pressed → LED on

Step 3: Improvement — Using interrupts

Polling works, but it forces the processor to keep checking constantly. Interrupts are more efficient: the hardware automatically notifies when the pin changes state. Create a new file button_int.aru:

button_int.aru
// Import the GPIO module
use GPIO

println("Starting interrupt-based reading...");

// 1. Pin configuration
GPIO.pinmode(4, GPIO.PULLUP);
GPIO.pinmode(2, GPIO.OUTPUT);

// 2. State variable
var ledOn = false;

// 3. Callback function — runs when the pin changes
func onButtonPress(pin, val)
ledOn = !ledOn; // Toggle state

if (ledOn) then
GPIO.write(2, HIGH);
println("LED on (toggle)");
else
GPIO.write(2, LOW);
println("LED off (toggle)");
end
end

// 4. Attach interrupt on falling edge (HIGH → LOW = press)
GPIO.onInterrupt(4, GPIO.FALLING, onButtonPress);

println("Interrupt registered. Press the button...");

// 5. Main loop free for other tasks
while (true)
pause(100);
end
Toggle vs. Hold

Notice the difference: the first example turns the LED on while you hold the button. This second example toggles the state with each press — press once to turn on, press again to turn off.

What each new part does

func onButtonPress() defines the callback function that will be automatically executed every time an interrupt is detected on the pin.

GPIO.onInterrupt(4, GPIO.FALLING, onButtonPress) attaches the onButtonPress function to pin 4. The GPIO.FALLING mode triggers the interrupt on the falling edge (when the pin goes from HIGH to LOW), that is, right when you press the button.

while (true) pause(100); end keeps the program alive. The main loop stays free because all the button logic is handled by the interrupt.

Available interrupt modes

ConstantTriggers when...
GPIO.RISINGThe pin goes from LOW to HIGH (rising edge)
GPIO.FALLINGThe pin goes from HIGH to LOW (falling edge)
GPIO.CHANGEThe pin changes state in either direction
GPIO.ONLOWThe pin stays at LOW level
GPIO.ONHIGHThe pin stays at HIGH level

Step 4: Simulating the interrupt version

  1. Repeat the simulator setup: pin 4 with PushButton and pin 2 with LED.
  2. Run button_int.aru with Run.
  3. Click the button in the simulator. Each click will toggle the LED between on and off. GPIO Simulator Example
  4. Check the console: each press prints the new state.
Starting interrupt-based reading...
Interrupt registered. Press the button...
LED on (toggle)
LED off (toggle)
LED on (toggle)

Step 5: Deploying to the ESP32

Once the logic is verified in the simulator, deploying to hardware is identical to the previous tutorial. You don't need to change a single line of code.

  1. Connect your ESP32 to the PC's USB port.
  2. Wire the push button between GPIO 4 and GND. No external resistor needed thanks to GPIO.PULLUP.
  3. In JARU IDE, select your board's COM port from the toolbar dropdown.
  4. Click the Upload Program button.
  5. Wait for the flashing process to finish, then press the physical button. The ESP32's LED will respond exactly as it did in the simulator.
Same code, two environments

The JARU philosophy continues to work: the very same button_int.aru you tested on Windows runs unchanged on the real ESP32.


Extra challenge

Combine what you have learned in this tutorial and the previous one. Try to create a program that does the following:

  • When the button is pressed, the LED starts blinking automatically.
  • When pressed again, the LED stops and turns off.

Hint: use a boolean variable that toggles in the interrupt and check it inside the main loop to decide whether to run the blink sequence.

Want a bigger challenge? Add a second push button on another pin to control the blink speed: each press halves the interval (500 → 250 → 125 ms) and then wraps around.


Summary

In this tutorial you have learned to configure a pin as a digital input with GPIO.pinmode and the GPIO.PULLUP mode, read the state of a push button with GPIO.read, react to presses with GPIO.onInterrupt and the GPIO.FALLING mode, distinguish between polling and interrupt-driven reading, and test both approaches on the Windows VM before deploying to the ESP32 without modifying the code.

The next tutorial introduces analog reading and writing with PWM and sensors.

Hello World (Blink LED) Tutorial

· 4 min read
Jon Otero Fernández
Author of JARU
BeginnerGPIOWindows VMESP32

The first step in the hardware world is always to blink an LED. In this tutorial you will learn the basic syntax of JARU and discover one of its best features: write the code once and test it both in the Windows simulator and on your physical ESP32 board.

What you need

  • JARU IDE installed on your PC — you can complete the entire tutorial with just this.
  • (Optional) An ESP32 board and a USB cable for the final deployment.

Step 1: The code

In JARU we interact with hardware by importing modules. Open JARU IDE, create a new file called blink.aru and write the following code:

blink.aru
// Import the GPIO module to control the pins
use GPIO

println("Starting Hello World...");

// 1. Pin setup
// Configure pin 2 (where the built-in LED usually is) as output
GPIO.pinmode(2, GPIO.OUTPUT);

println("Hardware configured. Starting loop...");

// 2. Main loop
while (true)
// Turn LED on
GPIO.write(2, HIGH);
pause(500); // Wait 500 milliseconds

// Turn LED off
GPIO.write(2, LOW);
pause(500); // Wait another 500 milliseconds
end
Why pin 2?

Most ESP32 boards have a built-in LED connected to GPIO 2. If your board uses a different pin, change it in the GPIO.pinmode call.

What each part does

use GPIO imports the general-purpose input/output module. Without this line, the GPIO.* functions will not be available.

GPIO.pinmode(2, GPIO.OUTPUT) configures pin 2 as a digital output. This function must always be called before writing to a pin.

GPIO.write(2, GPIO.HIGH) / GPIO.write(2, GPIO.LOW) turn the LED on and off by writing a high or low level to the pin.

pause(500) halts execution for 500 ms, creating the blinking effect.


Step 2: Simulation on Windows

One of the great advantages of JARU is its built-in Virtual Machine. You can run this code directly on your computer without any hardware connected.

  1. Open the GPIO Simulator from the IDE's Build → GPIO Sim menu.
  2. Add pin 2 manually using the New GPIO button.
  3. Attach an LED device card to pin 2 from the device panel.
  4. Click Run to execute the program in the VM.
  5. Watch the output console: you will see the println messages confirming the system has started correctly.
  6. Look at the LED card in the simulator: the indicator will turn on and off every 500 ms. You are simulating hardware directly on Windows!

GPIO Simulator Example

Starting Hello World...
Hardware configured. Starting loop...

Step 3: Deploying to the ESP32

Once you have verified that the logic works in the simulator, moving it to real hardware is a single click away. You do not need to change a single line of code.

  1. Connect your ESP32 to the PC's USB port.
  2. In JARU IDE, select your board's COM port from the toolbar dropdown.
  3. Click the Upload Program button.
  4. Wait for the flashing process to finish — the console will show the progress.
  5. The physical LED on your ESP32 will start blinking exactly as it did in the simulator.
Same code, two environments

This is the core philosophy of JARU: develop and debug on the Windows VM, then deploy to hardware with full confidence once the logic is verified.


Extra challenge

Change the pause(500) values to pause(100) and run the code first in the Windows simulator. Notice how much faster the pin 2 indicator blinks on screen. Now flash it to the ESP32 and check the result in the real world.

Feeling adventurous? Try making the LED blink three times quickly and then pause for a long time — like the Morse code for the letter S (· · ·).


Summary

In this tutorial you learned how to import the GPIO module, configure a pin as output with GPIO.pinmode, write digital values with GPIO.write, use pause to control timing, and test the same code on the Windows VM and a real ESP32 without any modifications.

The next tutorial introduces reading digital inputs with buttons and interrupts.