Built-in project · SparkFun Pro Micro

Dance pad on a Pro Micro

Four FSR panels on A0 to A3 with a press and a release threshold each, lighting a panel lamp and sent as four gamepad buttons through Joystick.h. The whole build, a SparkFun Pro Micro and 12 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Intermediate Runs in your browser. Free, and no account needed.

Dance pad on a Pro Micro · SparkFun Pro Microlive0.000 s 0.00x
Click to open it in the editor
The circuit itself, running here on the simulator. Press what can be pressed; click anything else to open it in the editor.

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · SparkFun Pro Micro
// Dance pad on a Pro Micro: four FSR panels, a lamp for each, and a USB
// gamepad report through the Arduino Joystick library's API (Joystick.h).
//
// The panels. Each arrow has a force sensing resistor (FSR) under it: thin,
// cheap and with no moving parts, which is why so many DIY pads and the open
// firmware written for them use FSRs. Here each FSR runs from its analog pin
// to ground, with the chip's internal pull-up as the top half of the
// divider. Standing on the panel drops the FSR's resistance and pulls the pin
// down, so the sketch turns the reading over: pressure = 1023 - reading.
//
//   left A3   down A2   up A1   right A0      lamps on pins 2, 3, 4 and 5
//
// The internal pull-up is somewhere between 20k and 50k and differs from chip
// to chip, so thresholds tuned on one board can be off on another. Many pad
// builds use a fixed resistor instead (a 10k from each pin to 5 V does the
// same job); set USE_INTERNAL_PULLUP to false when you add them.
//
// In Mokxi: drag a pressure pad's force up to stand on that panel. The Serial
// Monitor shows each step and the pressure that set it off.
//
// Two thresholds per panel. A panel turns on when its pressure rises past
// PRESS and off only when it falls below PRESS minus RELEASE_GAP. With one
// threshold, a foot resting near the line would flicker the arrow on and off
// many times a second (in the game, a burst of steps). The gap is the cure.
//
// Not simulated: the USB connection to a PC. Mokxi models this chip's USB as
// a serial pipe, so each report Joystick.h would send prints as a [Joystick]
// line instead. Flash it to a real Pro Micro and the pad is a gamepad with
// four buttons, which a rhythm game such as StepMania can map to the arrows.

#include <Joystick.h>

// ---------------------------------------------------------------------------
// Make it yours
// ---------------------------------------------------------------------------

const uint8_t PANEL_PINS[4] = {A3, A2, A1, A0};
const uint8_t LAMP_PINS[4] = {2, 3, 4, 5};
const char *const PANEL_NAMES[4] = {"LEFT", "DOWN", "UP", "RIGHT"};

// The pressure (0 to 1023) at which each panel counts as stepped on. Lower is
// more sensitive. Tune each panel by itself: the FSRs, the panel's weight and
// how it sits all differ, which is why pads keep one number per arrow.
int PRESS[4] = {600, 600, 600, 600};
// How far below PRESS a panel has to fall to let go.
const int RELEASE_GAP = 80;

// False when each panel has its own pull-up resistor to 5 V.
const bool USE_INTERNAL_PULLUP = true;

// Readings averaged per panel per pass, to steady a noisy sensor.
const uint8_t SAMPLES = 4;

// Lamps: true lights a panel while it is stepped on, false leaves them off.
const bool LAMPS_FOLLOW_STEPS = true;

// Print every panel's pressure twice a second, to find PRESS values.
const bool SHOW_PRESSURE = false;

// ---------------------------------------------------------------------------

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 4, 0,
                   false, false, false, false, false, false,
                   false, false, false, false, false);

bool down[4];
unsigned long lastShown = 0;

int pressure(uint8_t p) {
  long sum = 0;
  for (uint8_t s = 0; s < SAMPLES; s++) {
    sum += analogRead(PANEL_PINS[p]);
  }
  return 1023 - (int)(sum / SAMPLES);
}

void setup() {
  for (uint8_t p = 0; p < 4; p++) {
    pinMode(PANEL_PINS[p], USE_INTERNAL_PULLUP ? INPUT_PULLUP : INPUT);
    pinMode(LAMP_PINS[p], OUTPUT);
    digitalWrite(LAMP_PINS[p], LOW);
  }
  Serial.begin(115200);
  Joystick.begin(false);
  Serial.println("Dance pad ready: step on a panel.");
  Joystick.sendState();
}

void loop() {
  bool changed = false;
  int force[4];
  for (uint8_t p = 0; p < 4; p++) {
    force[p] = pressure(p);
    bool now = down[p] ? force[p] >= PRESS[p] - RELEASE_GAP : force[p] >= PRESS[p];
    if (now != down[p]) {
      down[p] = now;
      changed = true;
      Serial.print(PANEL_NAMES[p]);
      Serial.print(now ? " step (" : " lift (");
      Serial.print(force[p]);
      Serial.println(")");
      Joystick.setButton(p, now);
      digitalWrite(LAMP_PINS[p], (now && LAMPS_FOLLOW_STEPS) ? HIGH : LOW);
    }
  }
  if (changed) {
    Joystick.sendState();
  }
  if (SHOW_PRESSURE && millis() - lastShown >= 500) {
    lastShown = millis();
    for (uint8_t p = 0; p < 4; p++) {
      Serial.print(PANEL_NAMES[p]);
      Serial.print(' ');
      Serial.print(force[p]);
      Serial.print(p < 3 ? "  " : "\n");
    }
  }
}

Parts list

14 parts, plus the jumper wires. Every one is in the editor's parts bin.

How it is wired

14 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.

  • Ground: SparkFun Pro Micro pin GND; Resistor, 220 Ω (1) pin 2; Resistor, 220 Ω (2) pin 2; Resistor, 220 Ω (3) pin 2; Resistor, 220 Ω (4) pin 2
  • SparkFun Pro Micro pin 2; LED, blue (1) pin A
  • SparkFun Pro Micro pin 3; LED, red (1) pin A
  • SparkFun Pro Micro pin 4; LED, red (2) pin A
  • SparkFun Pro Micro pin 5; LED, blue (2) pin A
  • Ground: SparkFun Pro Micro pin GND; Force-sensing resistor (1) pin 1; Force-sensing resistor (2) pin 1; Force-sensing resistor (3) pin 1; Force-sensing resistor (4) pin 1
  • SparkFun Pro Micro pin A3; Force-sensing resistor (1) pin 2
  • SparkFun Pro Micro pin A2; Force-sensing resistor (2) pin 2
  • SparkFun Pro Micro pin A1; Force-sensing resistor (3) pin 2
  • SparkFun Pro Micro pin A0; Force-sensing resistor (4) pin 2
  • LED, blue (1) pin C; Resistor, 220 Ω (1) pin 1
  • LED, red (1) pin C; Resistor, 220 Ω (2) pin 1
  • LED, red (2) pin C; Resistor, 220 Ω (3) pin 1
  • LED, blue (2) pin C; Resistor, 220 Ω (4) pin 1

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.