Limit switch triggers by itself or homing fails: wiring, pull-up and debounce

Use a pull-up, prefer a normally closed switch for safety, and ignore changes shorter than a few milliseconds.

What the message means

Long wires next to motor cables pick up noise. A floating input or a bouncing contact is read as a hit.

Fix it in this order

  1. Use INPUT_PULLUP, or an external pull-up, so the pin never floats.
  2. Wire the switch normally closed where safety matters, so a broken wire stops the machine.
  3. Keep switch wires away from motor and driver cables, or use twisted or shielded wire.
  4. Add a small capacitor, such as 100 nF, across the input.
  5. Require the signal to hold for a few milliseconds before you act on it.
  6. Home slowly and back off a little after the hit.

Why it happens

The contacts of a mechanical switch do not close cleanly. They touch and part several times in a short moment, usually thousands of a second, and the input sees each one as a separate press. The exact time depends on the switch.

A floating input has no defined level and picks up noise, and long wires beside motor cables pick up more of it through coupling. A pull-up fixes the idle level, and requiring the signal to hold for a few milliseconds filters out both bounce and short spikes. A normally closed switch is the safer choice because a broken wire then looks like a hit.

If you see this, do this

You seeDo this
Triggers while the motors runNoise. Shield and add a capacitor.
Never triggersWiring or wrong pin state.

floating input and pull-up, bounce.

Last reviewed: November 2026. These are the usual causes and the order that finds them fastest. Test on your own board; clones and cables differ.

Why this happens

A mechanical contact does not close in one clean step. The metal surfaces touch, spring apart and touch again over a short period, typically up to a few milliseconds and sometimes more for a worn switch. A microcontroller reading the pin at full speed sees each of these as a separate press. Homing code that triggers on the first edge may stop at the right place, but code that counts edges, or that re-arms the motion on release, sees a mess.

False triggers while a motor runs have a different cause. An input pin with only a weak pull-up is a high-impedance node, and a long wire next to a motor cable behaves like an antenna. The AVR internal pull-up is typically in the tens of kilohms, which is weak against noise coupled from a stepper driver. A stronger external pull-up of a few kilohms lowers the impedance and reduces the pickup.

How to confirm the cause

  • Print the pin state to the serial monitor with the machine stationary. A stable HIGH means the pull-up works. A value that flickers with the switch untouched points to a floating or noisy line.
  • Count edges for one press. If a single press makes several edges, the switch is bouncing and needs debounce.
  • Run the motors with the switch wire disconnected from the switch but still connected to the board. If triggers still appear, the wire is picking up noise, and the cause is not the switch.
  • Wiggle the wire at the switch and at the board. A trigger when you move it points to a loose crimp or a broken strand.
  • Check that the switch ground and the board ground are joined and that the switch does not share a return path with motor current.

Worked example

A switch wired between the pin and ground, read with the internal pull-up and a 10 ms hold time. A press reads LOW. If you wire a normally closed switch, the logic is reversed.

const uint8_t PIN = 2;
bool stable = HIGH, last = HIGH;
uint32_t t0 = 0;
void setup() { pinMode(PIN, INPUT_PULLUP); Serial.begin(115200); }
void loop() {
  bool r = digitalRead(PIN);
  if (r != last) { last = r; t0 = millis(); }
  if (millis() - t0 > 10 && r != stable) {
    stable = r;
    if (stable == LOW) Serial.println("hit");
  }
}

Common mistakes

  • Debouncing with delay() inside a motion loop, which stops the motor control from running.
  • Polling too slowly while the axis moves fast, so the switch is passed before it is seen.
  • Mixing up normally open and normally closed logic in the code.
  • Running the switch wire in the same bundle as motor or driver wires.
  • Setting no overtravel, so the carriage keeps pushing after the switch triggers.

If this did not fix it

  • Check that the pin is set to the right mode. A pin left as a plain input has no pull-up.
  • Check that no interrupt or step-generation routine blocks the input from being read at the time it matters.
  • Check the mechanics. A switch that is only just touched by the carriage will trigger intermittently.