HC-SR501 PIR Motion Sensor Tutorial: Reliable Motion Detection, Sensitivity & Delay Tuning, Repeat/Non-Repeat Modes, and Arduino Alarm Automation

Beginner Tutorial Views: 1820

This tutorial is a detailed, practical guide to using the HC-SR501 Adjustable Pyroelectric Infrared (PIR) Motion Sensor Module (Leobot Product #1616) for motion-triggered projects. You will learn what PIR sensors actually detect (changes in IR heat patterns), how to wire it correctly, how to tune the sensitivity (range) and delay time, how to use the jumper for repeatable (retrigger) vs non-repeatable modes, and how to write robust Arduino code that avoids false triggers and noisy outputs.

HC-SR501 PIR Motion Sensor Tutorial: Reliable Motion Detection, Sensitivity & Delay Tuning, Repeat/Non-Repeat Modes, and Arduino Alarm Automation

This tutorial is a detailed, practical guide to using the HC-SR501 Adjustable Pyroelectric Infrared (PIR) Motion Sensor Module (Leobot Product #1616) for motion-triggered projects. You will learn what PIR sensors actually detect (changes in IR heat patterns), how to wire it correctly, how to tune the sensitivity (range) and delay time, how to use the jumper for repeatable (retrigger) vs non-repeatable modes, and how to write robust Arduino code that avoids false triggers and noisy outputs.

Tutorial Beginner–Intermediate Sensors PIR HC-SR501 Arduino Security Automation Low Power
What this module does: The HC-SR501 uses a pyroelectric sensor to detect motion by sensing changes in infrared radiation (heat patterns) in its field of view. It’s commonly used in alarms, lights, and occupancy-triggered automation.
Critical rule: PIR sensors detect motion of warm bodies (change over time), not “presence”. A perfectly still person can eventually stop triggering. If you need “presence”, combine PIR with another sensor (microwave radar, ultrasonic, ToF, pressure mat, etc.).

1) What PIR sensors detect (and why they false-trigger)

A PIR sensor detects motion by measuring changes in infrared (IR) energy across two sensing elements. When a warm object (human/animal) moves across the Fresnel lens zones, the IR pattern changes and the module outputs a trigger.

Why false triggers happen

  • Rapid temperature changes: heaters turning on, hot air blasts, sunlight shifting.
  • Moving warm air: aircon vents, fans, open windows.
  • Electrical noise: long wires, weak power, relay/motor switching nearby.
  • Bad placement: lens facing direct sun or reflecting surfaces.
Design intent: PIR is best as a “someone moved here” trigger, not as a precision sensor. Your logic should assume occasional false triggers and handle them gracefully.

2) Key specs you should actually care about

Specs vary slightly by vendor/clone, but typical HC-SR501 characteristics are:

  • Supply voltage: ~4.5–20VDC
  • Output level: typically ~3.3V HIGH (logic signal)
  • Detection distance: adjustable, typically ~3–7 meters
  • Delay time: adjustable, typically ~0.5–200 seconds
  • Modes: repeatable (retrigger) / non-repeatable
  • Detection angle: typically around a ~100° cone
Arduino input note: Output HIGH is usually ~3.3V even if you power the module from 5V. That’s still read as HIGH by most Arduinos, and it’s also safe for 3.3V MCUs. (Always verify your exact board if you’re doing something critical.)

3) Pinout and wiring (Arduino / ESP32)

HC-SR501 modules commonly expose 3 pins:

  • VCC: power input (often labeled VCC, +, or “+5V” on some PCBs)
  • OUT: digital output (HIGH when motion is detected)
  • GND: ground

3.1 Wiring to Arduino UNO/Nano

  • VCC ? 5V (or VIN if your board expects higher input and you know what you’re doing)
  • GND ? GND
  • OUT ? D2 (or any digital input)

3.2 Wiring to ESP32 / ESP8266

  • VCC ? 5V (many dev boards provide 5V from USB) or a suitable supply within module range
  • GND ? GND
  • OUT ? a GPIO input (reads HIGH at ~3.3V typically)
Noise tip: If you have long cable runs, add a small decoupling capacitor near the module (e.g., 0.1µF across VCC-GND) and keep the OUT wire away from relay/motor wiring.

4) Adjustments: sensitivity + delay + mode jumper

4.1 Sensitivity / range potentiometer

  • Controls how easily motion triggers the output (effectively range / threshold).
  • Start mid-range, then adjust in small steps.
  • If you get false triggers, reduce sensitivity before doing anything else.

4.2 Delay time potentiometer

  • Controls how long OUT stays HIGH after motion is detected.
  • Typical adjustable range is very wide (~0.5–200 seconds).
  • Short delays are better for “event” systems; longer delays are better for “keep light on while moving”.

4.3 Mode jumper: repeatable vs non-repeatable

  • Repeatable (retrigger): if motion continues, the timer extends (OUT stays HIGH longer).
  • Non-repeatable: once triggered, it holds HIGH for the delay, then must go LOW before triggering again.
Practical choice: Use repeatable for lights/occupancy-style triggers, non-repeatable for “single event” alarms.

5) Warm-up time and stabilization (non-negotiable)

PIR modules typically need a short stabilization period after power-up. During this time, they may output random triggers while their internal reference settles.

  • Plan for a warm-up delay in firmware (often 10–60 seconds in real projects).
  • Do not treat “first seconds after boot” as valid security data.
Security system rule: Always implement an “arming delay” (e.g., 30 seconds) so you can exit the room without triggering your own alarm.

6) Placement & lens physics: coverage, blind spots, and mounting height

  • Mount height: higher generally increases coverage, but too high can reduce sensitivity to small motion.
  • Angle: aim across likely motion paths, not directly at a doorway where motion is “toward” the sensor.
  • Across vs toward: PIR tends to trigger better when a person moves across lens zones rather than straight toward it.
  • Avoid heat sources: don’t point at heaters, sunny windows, or active vents.
Mechanical tip: If you’re putting it in a box, the front “window” must pass IR. Many plastics are opaque to IR; test before committing.

7) Arduino Example 1: basic motion detect + LED

This is the simplest “does it work?” example. OUT goes HIGH when motion is detected.


/*
  HC-SR501 PIR Motion Sensor - Basic Test

  Wiring:
    PIR VCC -> 5V
    PIR GND -> GND
    PIR OUT -> D2

  Behavior:
    - Turns LED on while motion output is HIGH.
*/

const int PIN_PIR = 2;
const int PIN_LED = 13;

void setup() {
  pinMode(PIN_PIR, INPUT);
  pinMode(PIN_LED, OUTPUT);
}

void loop() {
  int motion = digitalRead(PIN_PIR);
  digitalWrite(PIN_LED, motion ? HIGH : LOW);
}
    

8) Arduino Example 2: robust motion events (debounce + hold + cooldown)

Real builds benefit from “event shaping”:

  • Warm-up ignore window
  • Minimum HIGH duration before accepting a trigger (reduces noise spikes)
  • Cooldown so you don’t spam events

/*
  HC-SR501 PIR Motion Sensor - Robust Event Handling

  - Warm-up ignore: ignore triggers for WARMUP_MS after boot
  - Debounce: require PIR to be HIGH continuously for CONFIRM_MS
  - Hold: treat motion as "active" for HOLD_MS after a confirmed trigger
  - Cooldown: minimum gap between confirmed events

  Wiring:
    PIR OUT -> D2
*/

const int PIN_PIR = 2;
const int PIN_LED = 13;

const unsigned long WARMUP_MS  = 30UL * 1000UL;  // 30s ignore after boot
const unsigned long CONFIRM_MS = 150UL;          // require 150ms stable HIGH
const unsigned long HOLD_MS    = 10UL * 1000UL;  // keep "motion active" for 10s
const unsigned long COOLDOWN_MS= 2UL  * 1000UL;  // 2s between confirmed events

unsigned long bootMs;
unsigned long highStartMs = 0;
unsigned long motionUntilMs = 0;
unsigned long lastEventMs = 0;

void setup() {
  pinMode(PIN_PIR, INPUT);
  pinMode(PIN_LED, OUTPUT);
  bootMs = millis();
}

void loop() {
  unsigned long now = millis();
  bool inWarmup = (now - bootMs) < WARMUP_MS;

  bool pirHigh = (digitalRead(PIN_PIR) == HIGH);

  if (!inWarmup) {
    if (pirHigh) {
      if (highStartMs == 0) highStartMs = now;

      bool confirmed = (now - highStartMs) >= CONFIRM_MS;
      bool cooldownDone = (now - lastEventMs) >= COOLDOWN_MS;

      if (confirmed && cooldownDone) {
        lastEventMs = now;
        motionUntilMs = now + HOLD_MS;
        // You can log / trigger actions here
      }
    } else {
      highStartMs = 0;
    }
  }

  bool motionActive = (!inWarmup) && (now < motionUntilMs);
  digitalWrite(PIN_LED, motionActive ? HIGH : LOW);
}
    
Why HOLD_MS helps: PIR output behavior depends on the onboard delay pot + mode jumper. This software hold makes your downstream logic stable even if you re-tune hardware later.

9) Arduino Example 3: alarm/relay trigger with arming + siren timer

This pattern is extremely common: arm the system, then if motion occurs, trigger an alarm for a fixed time. (For a real siren/relay, use a proper relay or MOSFET stage with flyback protection.)


/*
  HC-SR501 PIR Motion Sensor - Simple Alarm Logic

  States:
    - Arming delay (exit time)
    - Armed
    - Alarm active for ALARM_MS, then re-arm after RESET_MS

  Wiring:
    PIR OUT -> D2
    ALARM OUT (buzzer/relay control) -> D8 (through proper driver if needed)
*/

const int PIN_PIR   = 2;
const int PIN_ALARM = 8;

const unsigned long ARM_DELAY_MS = 30UL * 1000UL;
const unsigned long ALARM_MS     = 20UL * 1000UL;
const unsigned long RESET_MS     = 10UL * 1000UL;

enum State { ARMING, ARMED, ALARMING, RESETTING };
State st = ARMING;

unsigned long stateMs = 0;

void setState(State s) {
  st = s;
  stateMs = millis();
}

void setup() {
  pinMode(PIN_PIR, INPUT);
  pinMode(PIN_ALARM, OUTPUT);
  digitalWrite(PIN_ALARM, LOW);
  setState(ARMING);
}

void loop() {
  unsigned long now = millis();
  bool motion = (digitalRead(PIN_PIR) == HIGH);

  switch (st) {
    case ARMING:
      digitalWrite(PIN_ALARM, LOW);
      if (now - stateMs >= ARM_DELAY_MS) setState(ARMED);
      break;

    case ARMED:
      digitalWrite(PIN_ALARM, LOW);
      if (motion) setState(ALARMING);
      break;

    case ALARMING:
      digitalWrite(PIN_ALARM, HIGH);
      if (now - stateMs >= ALARM_MS) setState(RESETTING);
      break;

    case RESETTING:
      digitalWrite(PIN_ALARM, LOW);
      if (now - stateMs >= RESET_MS) setState(ARMED);
      break;
  }
}
    

10) Common mistakes

  • Mistake: Treating PIR as “presence” instead of “motion”.
    Fix: Use PIR as a trigger; add other sensors if you need continuous occupancy.
  • Mistake: Testing immediately on power-up and concluding it’s “random”.
    Fix: Add a warm-up ignore period and/or arming delay.
  • Mistake: Pointing it at a sunny window or heater/vent.
    Fix: Relocate/angle sensor away from thermal noise sources.
  • Mistake: Long wiring next to relay/motor mains lines.
    Fix: Separate routing, add decoupling, and improve wiring discipline.
  • Mistake: Expecting perfect, zero-false-trigger behavior.
    Fix: Add filtering logic (confirm time, cooldown, and event shaping).

11) Troubleshooting (random triggers, no triggers, short range)

Random triggers

  • Cause: warm-up/stabilization. Fix: ignore first 30–60 seconds; use arming delay.
  • Cause: thermal noise (sun/heater/vent). Fix: reposition; reduce sensitivity.
  • Cause: electrical noise / long wires. Fix: add decoupling cap; shorten OUT wire; keep away from switching loads.

No triggers / too insensitive

  • Cause: sensitivity pot too low. Fix: increase sensitivity gradually.
  • Cause: placement wrong (motion toward sensor). Fix: orient so motion crosses lens zones.
  • Cause: power issue. Fix: verify stable VCC/GND connections.

Output stays HIGH “too long”

  • Cause: delay pot set high (can be up to ~200s). Fix: reduce delay pot.
  • Cause: repeatable mode retriggering. Fix: switch to non-repeatable mode or handle it in firmware.

12) Quick checklist


HC-SR501 PIR Motion Sensor Checklist
-----------------------------------
 Wired correctly: VCC, GND, OUT (common ground to MCU)
 Warm-up / arming delay implemented (ignore early random triggers)
 Sensitivity tuned to environment (reduce first if false triggers)
 Delay tuned to use-case (short for events, longer for lights)
 Mode jumper set intentionally: repeatable vs non-repeatable
 Sensor placed away from sunlight/heaters/vents; aimed across motion paths
 If needed: software filtering (confirm time + cooldown + hold)
    

Products that this may apply to