slim joystick/Reading it/08. The first read
Reading it · 08 of 11

The first read

Six wires, no library, and a sketch that prints the stick, the click and the button five times a second. X and Y come out as raw counts so you can see which way each one rises; BTNS comes out in millivolts and as a button's name, from the six lines in the last chapter.

Six wires

Six wires
Your board
X, Y, BTNS
GPIO 4, GPIO 5, GPIO 6
KEY
GPIO 7
3V3 to
3V3
X, Y and BTNS to GPIO 4, GPIO 5 and GPIO 6, all on ADC1, which keeps working with Wi-Fi on. KEY to GPIO 7, which is not one the chip reads at boot. 3V3 to 3V3.

GND to GND, and 3V3 to 3V3 on every board, the Uno included. X, Y and BTNS to three analog pins and KEY to a digital one:

BoardXYBTNSKEY
Arduino UnoA0A1A2D2
ESP32GPIO 34GPIO 35GPIO 32GPIO 25
ESP32-S3GPIO 4GPIO 5GPIO 6GPIO 7
Raspberry Pi PicoGP26GP27GP28GP15

The pins are the same in every sketch in this book. On the ESP32s, X, Y and BTNS are all on ADC1, the converter that keeps working with Wi-Fi on, and none of the four is a pin the chip reads at boot. On a Pico they are its three analog inputs, all of them.

The sketch

readMv() reads millivolts: analogReadMilliVolts on an ESP32 or ESP32-S3, and the count scaled by the ADC's full scale on an Uno or a Pico. whichButton() walks the six lines from telling them apart, highest first, and returns the first button whose line the reading is above.

X and Y print as plain counts, on purpose. The next article turns them into something tidier; this one is for finding out what your stick does.

What you should see

The serial monitor at 115200 prints five lines a second. On an Uno, with the stick let go and U5 pressed, something like:

X 331  Y 344  KEY 0  BTNS 0 mV  none
X 330  Y 344  KEY 0  BTNS 1100 mV  U5
X 612  Y 343  KEY 0  BTNS 0 mV  none
X 331  Y 344  KEY 1  BTNS 0 mV  none

Let go, X and Y sit near the middle of what this board can reach: near 338 on an Uno, 512 on a Pico, 2048 on an ESP32, and never exactly. Now push the stick towards the header, then away, then left and right, and write down which number moves and which way. That is your stick's orientation, and the steering sketch has a switch for each axis in case it is not the way you want.

KEY prints 1 only while the stick is pushed straight down. The buttons print their names one at a time; press two and only one appears, which is one button at a time.

The code

No library. X and Y print as analogRead counts, KEY as 0 or 1, and BTNS in millivolts with the button it names. Change the four _PIN numbers to the pins you wired; the comment above them lists all four boards.

joystick_first_read.ino
/*
  Slim Joystick - first read                             TK21 / /p/tk21

  Wiring. Parts up, header along the top. Count from the square pad,
  which is GND at the right-hand end, leftwards:

    GND  -> GND
    3V3  -> 3V3 on every board, the Uno included (it is printed 3V3)
    BTNS -> A2 on an Uno, GPIO 32 on an ESP32, GPIO 6 on an
            ESP32-S3, GP28 on a Raspberry Pi Pico     (analog)
    X    -> A0, GPIO 34, GPIO 4, GP26      (same order, analog)
    Y    -> A1, GPIO 35, GPIO 5, GP27      (analog)
    KEY  -> D2, GPIO 25, GPIO 7, GP15      (digital)

  Arduino IDE
    Tools > Board                 your board, e.g. ESP32S3 Dev Module
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    No library needed.
*/

// The pins X, Y, BTNS and KEY are wired to.
// Uno: A0 A1 A2 2. ESP32: 34 35 32 25. ESP32-S3: 4 5 6 7. Pico: 26 27 28 15.
const int X_PIN = 4;
const int Y_PIN = 5;
const int BTNS_PIN = 6;
const int KEY_PIN = 7;

// Uno and Pico only: the ADC's full scale, in mV.
// Uno: 5000. Pico: 3300.
const float FULL_SCALE_MV = 5000.0;

// The buttons in ladder order, and the line under each one's level,
// in mV with 3V3 on the header: halfway to the next level down.
const char* BUTTON_NAME[] = {"U11", "U10", "U5", "U7", "U8", "U6"};
const int LIMIT_MV[] = {2475, 1375, 963, 743, 605, 275};

// Millivolts on an analog pin, on any of the four boards.
float readMv(int pin) {
#if defined(ARDUINO_ARCH_ESP32)
  return analogReadMilliVolts(pin);     // calibrated in the chip
#else
  return analogRead(pin) * FULL_SCALE_MV / 1023.0;
#endif
}

// Which button BTNS shows: 0 to 5 in ladder order, or -1 for none.
int whichButton(float mv) {
  for (int i = 0; i < 6; i++) {
    if (mv > LIMIT_MV[i]) return i;
  }
  return -1;
}

void setup() {
  Serial.begin(115200);
  pinMode(KEY_PIN, INPUT);        // R1 on the board pulls it down
}

void loop() {
  int x = analogRead(X_PIN);
  int y = analogRead(Y_PIN);
  int key = digitalRead(KEY_PIN); // HIGH while the stick is pushed down
  float btns = readMv(BTNS_PIN);
  int b = whichButton(btns);

  Serial.print("X ");
  Serial.print(x);
  Serial.print("  Y ");
  Serial.print(y);
  Serial.print("  KEY ");
  Serial.print(key);
  Serial.print("  BTNS ");
  Serial.print(btns, 0);
  Serial.print(" mV  ");
  Serial.println(b < 0 ? "none" : BUTTON_NAME[b]);
  delay(200);                     // five lines a second
}

readMv() uses analogReadMilliVolts on an ESP32 or ESP32-S3 and scales the count everywhere else, so the one list of lines works on every board. On an Uno set FULL_SCALE_MV to 5000; on a Pico, 3300.

When it does not work

X and Y read 0, or both read the top.

The tracks have no supply or no ground. Check the 3V3 and GND wires first: count from the square pad, which is GND at the right-hand end, parts up. Then check that X and Y are on analog pins and that the sketch's pin numbers match them.

BTNS says none for every button.

Press U11, the left red button. If it still says none, BTNS is not on the pin the sketch reads, or 3V3 is missing. If U11 works and the others do not, BTNS is on a digital-only pin or the lines in the sketch have been changed.

KEY prints 1 all the time.

The sketch sets KEY to INPUT because R1 on the board pulls it down. If you changed it to INPUT_PULLUP, change it back. If KEY is not wired, the pin floats and prints anything.

The serial monitor stays empty on my ESP32-S3.

Set Tools > USB CDC On Boot to Enabled and upload again. Without it the S3's USB port does not bring up a serial port at boot, so the sketch runs with nowhere to print.

Where this goes next

Turning the stick's raw numbers into −100 to 100, with 0 when it is let go.

A centre and a dead zone

Edit this page — content/books/slim-joystick/the-first-read.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

Slim Joystick

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum