Using it · 08 of 10

The first read

Three wires and a sketch with no library that prints SIGNAL five times a second, in thousandths of VCC, with the push it names. SIGNAL goes to A0 on an Uno, GPIO 34 on an ESP32, GPIO 4 on an ESP32-S3 and GP26 on a Pico; VCC to 5V on the Uno and 3V3 on the rest.

Three wires

Three wires
Your board
VCC to
5V
SIGNAL to
A0
NC to
nothing
GND to GND, VCC to 5V, SIGNAL to A0, NC to nothing. The Uno measures against its own 5 V, so with VCC on the same 5 V a reading is a fraction of VCC and the sketch's lines hold whatever USB actually gives.

GND to GND. VCC to your board's logic voltage: 5V on an Uno, 3V3 on an ESP32, an ESP32-S3 or a Pico. SIGNAL to the analog pin. NC to nothing.

The sketch

readPermille() is the only part that differs between boards. On an ESP32 or an ESP32-S3 it asks analogReadMilliVolts for calibrated millivolts and divides by 3300, the VCC it assumes. On an Uno or a Pico it divides the count by 1023, because those two measure against their own supply, which is VCC.

whichPush() then walks the five lines from telling them apart, highest first, and returns the first one the reading is above. Below all five is nothing pressed.

What you should see

Hold the block with the header on the left and push each way. The serial monitor at 115200 prints, on an Uno:

SIGNAL 0/1000  none
SIGNAL 111/1000  up
SIGNAL 181/1000  press
SIGNAL 272/1000  left
SIGNAL 444/1000  down
SIGNAL 1000/1000  right

A few thousandths either way is normal: 1 % resistors and a little noise. On an ESP32 right prints a little under 1000, often about 940: the top of its ADC, which is still far over the line. Printed five times a second, a push you let go of can sometimes show one line of a lower push on the way down; the next article is about that.

The code

readPermille() turns a reading into thousandths of VCC on any of the four boards: millivolts over 3300 on an ESP32, the count over 1023 on an Uno or a Pico. whichPush() checks the five lines, highest first. loop() prints both five times a second. Change SIGNAL_PIN to the pin you wired.

joystick_first_read.ino
/*
  Five-Direction Joystick - first read                 TK94 / /p/tk94

  Wiring. Parts up, header at the bottom. Count from the square pad,
  which is GND at the left-hand end:

    GND    -> GND
    VCC    -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
    NC     -> nothing: it is connected to nothing on the board
    SIGNAL -> A0 on an Uno, GPIO 34 on an ESP32, GPIO 4 on an
              ESP32-S3, GP26 on a Raspberry Pi Pico       (analog)

  The names are for the block held with the header on the left,
  the way the words on its front read.

  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 analog pin SIGNAL is wired to.
// Uno: A0. ESP32: 34. ESP32-S3: 4. Pico: 26.
const int SIGNAL_PIN = 4;

// The pushes, highest level first, and the line under each one:
// halfway to the next level down, in thousandths of VCC.
const char* NAME[] = {"right", "down", "left", "press", "up"};
const int LIMIT[] = {722, 359, 227, 146, 56};

// SIGNAL in thousandths of VCC, on any of the four boards.
int readPermille() {
#if defined(ARDUINO_ARCH_ESP32)
  // Measured against a reference in the chip: calibrated
  // millivolts, over VCC's 3300.
  return analogReadMilliVolts(SIGNAL_PIN) * 1000L / 3300;
#else
  // The Uno and Pico measure against their supply, which is VCC.
  return analogRead(SIGNAL_PIN) * 1000L / 1023;
#endif
}

// Which push a reading is: 0 to 4 as in NAME, or -1 for none.
int whichPush(int permille) {
  for (int i = 0; i < 5; i++) {
    if (permille > LIMIT[i]) return i;
  }
  return -1;
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  int p = readPermille();
  int d = whichPush(p);
  Serial.print("SIGNAL ");
  Serial.print(p);
  Serial.print("/1000  ");
  Serial.println(d < 0 ? "none" : NAME[d]);
  delay(200);                     // five lines a second
}

No library and no pinMode: analogRead sets the pin up itself. The lines are halfway between the levels the ladder makes, so they need no calibration. The sketch compiles for an Uno, an ESP32 and an ESP32-S3.

View on GitHub · blocks/tk94-five-direction-joystick/arduino/joystick_first_read/joystick_first_read.ino @ v1.11

When it does not work

It prints 0 whatever I push.

Check VCC first: with VCC unconnected the ladder has no top and R14 holds SIGNAL at 0. Then check SIGNAL is on the pin SIGNAL_PIN names, and not on NC, the third hole from the square pad, which goes nowhere.

The numbers jump about with nothing pressed.

SIGNAL is not reaching the pin you are reading, which then floats. Check the wire and the number in SIGNAL_PIN: on an ESP32 it is the GPIO number, 34, not the position on the board's header.

Right prints under 1000 on my ESP32.

The ESP32's ADC tops out a little under 3.3 V, so 3.3 V reads as its ceiling, roughly 3.1 V. It is still far over the line at 722, so the name is right. The other four levels are well inside its range.

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

A menu that moves once for each push, however long it is held.

One step per push →

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

Community

Questions about this product

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

Ask a question ↗

Five-Direction 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 →