BysMax

PIR Motion Sensor with Arduino — HC-SR501 Wiring, Code & Projects

14 min

A PIR (Passive Infrared) sensor detects motion by sensing changes in infrared radiation emitted by humans and animals. The HC-SR501 is the standard model for Arduino projects — it's cheap, reliable, and needs just one digital pin.

Time to complete: 10 minutes
Skill level: Beginner

How PIR Sensors Work

PIR sensors contain a pyroelectric element divided into two halves. A moving warm body crosses from one half to the other, creating a voltage difference that triggers the output. The Fresnel lens on the front focuses infrared radiation onto the sensing element and widens the detection angle.

The sensor does NOT detect heat directly — it detects changes in heat. A person standing perfectly still won't trigger it.

HC-SR501 Specifications

ParameterValue
Operating voltage4.5V to 20V
CurrentLess than 60 µA (standby)
Output voltage3.3V HIGH / 0V LOW
Detection rangeUp to 7 meters
Detection angle120°
Output pulse width0.3 to 200+ seconds (adjustable)
Delay after triggerAdjustable
Temperature range-15°C to +70°C
Dimensions32 × 24 mm

HC-SR501 Pinout

PinLabelConnect to
LeftVCC5V (or up to 12V)
MiddleOUTDigital pin
RightGNDGND

The OUT pin outputs 3.3V HIGH when motion is detected. This is safe to connect directly to Arduino digital pins even though Arduino runs at 5V — digital inputs recognize 3.3V as HIGH.

Adjustment Potentiometers

The HC-SR501 has two orange potentiometers on the back:

Sensitivity pot (left):

  • Turn clockwise → increases detection distance (up to 7 m)
  • Turn counterclockwise → decreases detection distance (min ~3 m)

Time delay pot (right):

  • Turn clockwise → longer output HIGH pulse (up to ~5 min)
  • Turn counterclockwise → shorter output pulse (min ~0.3 sec)

Trigger mode jumper (between the pots):

  • H (Repeatable): Output stays HIGH as long as motion continues. Pin must go LOW before retriggering.
  • L (Non-repeatable): Output pulses once per motion event, ignores motion until timeout completes.

For most projects, use H mode.

Wiring — Arduino Uno/Nano

HC-SR501Arduino
VCC5V
OUTDigital pin 7
GNDGND

Three wires. Done.

Code — Basic Motion Detection

const int PIR_PIN = 7;  // HC-SR501 OUT pin
const int LED_PIN = 13; // Built-in LED

void setup() {
  Serial.begin(9600);
  pinMode(PIR_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);

  // HC-SR501 needs 30-60 seconds to warm up and calibrate
  Serial.println("Warming up PIR sensor...");
  delay(30000);
  Serial.println("PIR sensor ready. Waiting for motion...");
}

void loop() {
  int motionDetected = digitalRead(PIR_PIN);

  if (motionDetected == HIGH) {
    digitalWrite(LED_PIN, HIGH);
    Serial.println("Motion DETECTED!");
  } else {
    digitalWrite(LED_PIN, LOW);
    // Serial.println("No motion");  // Uncomment to see "no motion" state
  }

  delay(100);
}

The 30-second warm-up is essential. Skip it and the sensor will trigger false positives for the first minute of operation. For a deployed project, remove the delay(30000) and just allow 1 minute after power-on before using the room.

Code — Motion Alarm with Buzzer

const int PIR_PIN  = 7;
const int LED_PIN  = 13;
const int BUZZ_PIN = 8;

bool lastState = LOW;

void setup() {
  Serial.begin(9600);
  pinMode(PIR_PIN,  INPUT);
  pinMode(LED_PIN,  OUTPUT);
  pinMode(BUZZ_PIN, OUTPUT);

  Serial.println("Calibrating (30 sec)...");
  delay(30000);
  Serial.println("ARMED — monitoring for motion");
}

void loop() {
  bool motionNow = digitalRead(PIR_PIN);

  if (motionNow == HIGH && lastState == LOW) {
    // Motion started
    Serial.println("ALERT: Motion detected!");
    digitalWrite(LED_PIN, HIGH);
    tone(BUZZ_PIN, 2000, 300);  // 300 ms beep at 2 kHz
  }

  if (motionNow == LOW && lastState == HIGH) {
    // Motion stopped
    Serial.println("Motion cleared");
    digitalWrite(LED_PIN, LOW);
    noTone(BUZZ_PIN);
  }

  lastState = motionNow;
  delay(100);
}

This code triggers only on state changes (rising edge on motion start), so the buzzer doesn't loop continuously.

Code — Automatic Light with Timeout

Turn on a light for 10 seconds after motion is detected:

const int PIR_PIN  = 7;
const int RELAY_PIN = 8;  // Relay controlling a lamp or LED strip

unsigned long lastMotionTime = 0;
const unsigned long LIGHT_TIMEOUT = 10000;  // 10 seconds

bool lightOn = false;

void setup() {
  Serial.begin(9600);
  pinMode(PIR_PIN,   INPUT);
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);  // Light off

  delay(30000);  // PIR warm-up
  Serial.println("Automatic light READY");
}

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

  if (motion == HIGH) {
    lastMotionTime = now;
    if (!lightOn) {
      digitalWrite(RELAY_PIN, HIGH);
      lightOn = true;
      Serial.println("Light ON");
    }
  }

  if (lightOn && (now - lastMotionTime >= LIGHT_TIMEOUT)) {
    digitalWrite(RELAY_PIN, LOW);
    lightOn = false;
    Serial.println("Light OFF (timeout)");
  }

  delay(100);
}

This uses millis() instead of delay() so the Arduino remains responsive to other tasks while the timer runs.

Simulate on Wokwi

Wokwi supports the HC-SR501. Add it to your circuit and click the sensor to toggle motion detection:

  1. Go to wokwi.com → New Project → Arduino Uno
  2. Add PIR sensor, connect OUT to pin 7, VCC to 5V, GND to GND
  3. Paste the basic code (remove the delay(30000) for simulation)
  4. Click the PIR sensor icon to trigger motion events

See the Wokwi simulator guide for setup.

Troubleshooting

Sensor triggers randomly, no one is nearby:

  • Wait the full 30-second calibration period before using
  • Keep away from heat vents, direct sunlight, and incandescent lights — these emit IR radiation
  • Check that no other heat sources (motor drivers, voltage regulators) are near the sensor

Sensor doesn't detect me walking past:

  • The Fresnel lens is most sensitive to lateral movement (crossing the beam), not walking straight toward it
  • Turn the sensitivity pot clockwise to increase range
  • Point the sensor at the expected motion path, not at the doorway head-on

Output stays HIGH all the time:

  • Wrong jumper position. Move jumper to H mode
  • VCC is too high — use 5V, not 12V for typical setups

Sensor triggers only once then stops:

  • Jumper is in L (non-repeatable) mode. Switch to H mode
  • The time delay pot is set too long — turn it counterclockwise to reduce timeout

30-second warm-up is too slow for my project:

  • It's a hardware requirement of pyroelectric sensors. You can reduce to ~10 seconds in a room with stable temperature, but expect occasional false triggers.

Range and Coverage Tips

  • Mount at 2–2.5 meters height for best room coverage
  • Angle the sensor down 15–20° to cover floor level
  • For hallway detection: mount at end of hall, pointing toward entry
  • Multiple sensors in series (any triggers the alarm): wire all OUT pins to the same digital input with pull-down resistor

Frequently Asked Questions (FAQ)

What is a PIR sensor used for? Security alarms, automatic lights, energy-saving systems, baby monitors, wildlife cameras, touchless switches. Any application where detecting human presence is useful.

What's the detection range of the HC-SR501? Up to 7 meters when the sensitivity potentiometer is at maximum. Typical indoor range with default settings is 3–5 meters.

Can HC-SR501 detect animals? Yes. It detects any warm-blooded animal including dogs, cats, and birds. The detection depends on the size and heat signature of the animal relative to the background.

Can I use HC-SR501 with ESP32? Yes. The OUT pin (3.3V HIGH) is safe for ESP32 GPIO inputs. Connect OUT to any GPIO, use digitalRead(). No changes to the code needed.

Why does my PIR sensor trigger after I install it? All pyroelectric sensors need 30–60 seconds to adjust to the ambient temperature of the room. This is normal. After calibration, false triggers stop.

Can PIR see through walls or glass? No. Glass blocks infrared, and walls are opaque to IR. PIR sensors require line of sight.

Comentarios (0) /hi/blog/arduino-pir-motion-sensor