Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

HC-SR501 PIR with Arduino Nano — motion on interrupt pin D2

Connect an HC-SR501 PIR sensor to an Arduino Nano on D2 (INT0), wait out the warm-up, and log when motion starts and how long it lasts.

Arduino C++Verified — core avr 1.8.8, 3 Nov 2026Compile-only

Community draft — report a mistake

The HC-SR501 is the white-domed PIR used in stair lights, intruder alarms and automatic washroom fans. It does the detection itself; the Nano only watches one output pin.

This sketch uses D2 with an interrupt, so the Nano notices motion even while it’s busy, and it times each motion event. That’s the starting point for a light that stays on only while someone is in the room.

Wiring

Arduino NanoOnly the pins used are shown · 5 V logicHC-SR501 PIR motion sensor5VGNDD2VCCOUTGND
Every connection
Arduino NanoHC-SR501 PIR motion sensorWireNotes
5VVCCred
D2OUTyellowD2 is INT0 — one of only two external-interrupt pins on the Nano.
GNDGNDblack

4.5–20 V (5 V typical) part, 5 V board. Power it from 5 V (VIN/5V pin). Its output is a 3.3 V logic signal, so it connects directly to ESP32, Pico and Uno GPIOs.

Board quirks

  • Only D2 (INT0) and D3 (INT1) support attachInterrupt() on the Nano. A PIR on any other pin has to be polled.
  • The HC-SR501 output is 3.3 V HIGH. The ATmega328P reads anything above 3 V as HIGH at 5 V supply, so it works without a resistor.
  • After power-up the PIR fires randomly for up to a minute — the sketch waits 60 s before arming.
  • Two orange trimmers set sensitivity (Sx) and hold time (Tx, 3 s–5 min). Turn Tx fully anticlockwise while testing. The jumper selects single (L) or repeat (H) trigger.

Code

pir-nano.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// HC-SR501 PIR motion sensor on an Arduino Nano, on external interrupt INT0 (D2).
// VCC → 5V, OUT → D2, GND → GND. Lights the on-board LED and logs how long motion lasted.
const uint8_t PIR_PIN = 2;  // D2 = INT0, D3 = INT1: the Nano's only external-interrupt pins
volatile bool changed = false;

void onPir() { changed = true; }

void setup() {
  Serial.begin(115200);
  pinMode(PIR_PIN, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.println(F("PIR warming up for 60 s - stay out of view"));
  delay(60000UL);
  attachInterrupt(digitalPinToInterrupt(PIR_PIN), onPir, CHANGE);
  Serial.println(F("Ready"));
}

void loop() {
  static unsigned long startedAt = 0;
  if (changed) {
    changed = false;
    bool motion = digitalRead(PIR_PIN) == HIGH;
    digitalWrite(LED_BUILTIN, motion ? HIGH : LOW);
    if (motion) {
      startedAt = millis();
      Serial.println(F("Motion detected"));
    } else {
      Serial.print(F("Motion ended after "));
      Serial.print((millis() - startedAt) / 1000.0, 1);
      Serial.println(F(" s"));
    }
  }
}

Expected serial output

Serial Monitor · 115200Output
PIR warming up for 60 s - stay out of view
Ready
Motion detected
Motion ended after 4.2 s

Common errors

Triggers by itself

Warm-up not finished, a noisy supply, or sunlight/heaters in view. A 100 µF capacitor across VCC/GND and pointing it away from windows help.

Output stays HIGH for minutes

The Tx trimmer is turned up. Turn it anticlockwise for the 3-second minimum.

↑↓ to move · Enter to open