Source: https://mokxi.com/learn/arduino-joystick
Updated: 2026-09-27

Learn

# An Arduino joystick, read and drawn on eight LEDs

Written by the Mokxi team, updated September 27, 2026

Try it now, no account Sign up free or see every lesson

- 192 parts on the bench
- 25 boards running now
- 1.00x real time, on every board

Drag the stick, or press it to swap axes

The bar graph example on a simulated ATmega328P. Drag the stick to move the bar, and press it to read the other axis.

The thumb stick module on every starter kit, the KY-023 and its clones, looks like a game controller part and turns out to be two potentiometers and a pushbutton under one cap. That makes it one of the best parts to learn analog input on, because you can feel the number change as you move it. The circuit above is an Arduino Uno reading one axis of a stick and drawing it as a bar on eight LEDs, running right now in your browser on the same sketch you can read below.

Drag the black cap on the canvas and the bar follows it. Let go and it springs back to the middle, with four lamps lit. Press the stick straight down and the bar switches to the other axis, and the serial monitor says which one you are looking at.

## What you need

- An Arduino Uno
- A two-axis joystick module (KY-023 or similar)
- Eight LEDs: three green, three yellow and two red
- Eight 220 ohm resistors, one per LED
- A breadboard and jumper wires

## Wiring

Part and pin

Goes to

Note

Joystick VCC

5 V

Powers both potentiometer tracks

Joystick GND

GND

The other end of both tracks

Joystick VRX

A0

The X axis wiper

Joystick VRY

A1

The Y axis wiper

Joystick SW

Pin 12

Shorts to GND when pressed; the internal pull-up holds it high

Eight LEDs, each through 220 ohm

Pins 2 to 9

Left to right, cathodes to GND

## What is inside a joystick module

Each axis is a 10 k potentiometer with one end on VCC, the other on GND and its wiper on VRX or VRY. Tilting the stick moves the wiper, so the pin sees a voltage somewhere between 0 and 5 volts: about 2.5 volts at rest, near 0 at one end of travel and near 5 at the other. It is exactly the voltage divider you would build with a knob, just with a spring that pulls it back to the middle.

The button is simpler still. Pressing the cap down closes a switch from SW to ground, and nothing else. There is no resistor on most modules, so the pin needs a pull-up to read HIGH when the button is not pressed, and the Uno has one built in that the sketch turns on with INPUT_PULLUP. Pressed reads LOW.

Because the axes are just voltages, the module works on a 3.3 volt board too. Power it from 3.3 V and the same stick reads 0 to 3.3 volts. On an ESP32 the converter is twelve bits, so the full scale is 0 to 4095 rather than 0 to 1023.

## Reading it: analogRead and map

analogRead(A0) turns the voltage on the pin into a number from 0 to 1023, where 0 is 0 volts and 1023 is the 5 volt reference. A centered stick reads somewhere near 512. The sketch then uses map() to turn that 0 to 1023 range into a number of lamps from 0 to 8, and lights that many LEDs from the left. That really is the whole bar graph: the meter is one line of arithmetic, and the LEDs are only where the answer is written down.

map() can return 8 for a reading of exactly 1023, which is one past the last array index, so the sketch clamps it to 8 lamps. It also only prints to the serial monitor when the number of lamps changes, which keeps the monitor readable instead of scrolling hundreds of identical lines a second.

The loop, from the bar graph example

## The helper, and the plain Arduino version

The example uses a small header that ships with Mokxi, mokxi_joystick.h. It is nothing magic: x() and y() are analogRead on the two axis pins, pressed() is digitalRead on SW compared with LOW, and clicked() is true once per press, on the edge, so holding the stick down does not flip the axis over and over.

On a real Uno without that header, write the same three things yourself: pinMode(12, INPUT_PULLUP) in setup(), analogRead(A0) and analogRead(A1) for the axes, and remember the last button state so you only act when it goes from HIGH to LOW. The rest of the sketch is standard Arduino code and runs unchanged.

The header also has dx() and dy(), which measure from wherever the stick was resting when begin() ran and ignore a small dead zone around it. Use those for steering a game or a robot, where a stick that rests at 519 instead of 512 should still count as still. The bar graph uses the raw reading on purpose, because it should be half lit when the stick is centered.

## Try it in the editor

Open the circuit and change LEDS and the pin list to use only four lamps. The bar now moves in bigger steps, because map() is dividing the same range into fewer pieces.

Then make a direction indicator instead of a bar: light only the lamp at position lit rather than every lamp below it. It is a one-character change in the bar() function, from i < lit to i == lit.

Finally, add a servo on pin 10 and send it map(raw, 0, 1023, 0, 180). The stick now steers a servo, which is the start of a pan and tilt head or a robot arm.

## Common mistakes

Forgetting the pull-up on SW. Without INPUT_PULLUP the button pin floats and reads random presses, often just from touching the wires.

Expecting exactly 512 at rest. Real sticks settle a few counts either side of center, and different axes settle differently. Measure the rest position at startup, or use a dead zone.

Swapping VRX and VRY, or finding the axis runs backwards. Both are normal: modules are mounted in different orientations. Swap the pins in code or flip the reading with 1023 - raw.

No resistors on the LEDs. Each LED needs its own 220 ohm resistor to keep the current to a safe level for the pin.

## Questions

How do I connect a joystick to an Arduino?

VCC to 5 V, GND to GND, VRX and VRY to two analog pins such as A0 and A1, and SW to any digital pin with the internal pull-up turned on. Read the axes with analogRead and the button with digitalRead.

What values does an Arduino joystick give?

On an Uno each axis reads 0 to 1023, with the center near 512. On a 12-bit board such as an ESP32 it reads 0 to 4095. The button reads LOW when pressed and HIGH when released.

Can I use a joystick with a Raspberry Pi Pico?

On real hardware, yes, on its ADC pins. In Mokxi the Pico has no analogRead yet, so the joystick header refuses to compile for it; use an Uno, a Nano or an ESP32-C3 instead.

Related

## Keep going

Arduino Potentiometer: analogRead and a Dimmer Analog vs Digital Pins, and ADC Resolution Arduino Servo Motor with a Potentiometer Voltage Dividers and Why They Are Bad Power Supplies How the joystick is modeled The Arduino Uno simulator The project page, with the full sketch

## Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.

Start building Open the editor
