To connect an HC-SR501 PIR motion sensor to an Arduino Uno R3, wire the VCC pin to 5V, GND to GND, and the OUT pin to Digital Pin 2. The sensor outputs a 3.3V HIGH signal when it detects infrared heat signatures within its 120-degree cone, up to 7 meters away. This guide covers the exact wiring, debounced code, and the top hardware pitfalls that cause false triggers or compilation failures in your sensor arduino pir projects.

Parts List and Hardware Specifications

Difficulty Rating: Beginner (2/5) | Estimated Build Time: 20 minutes

The HC-SR501 is the standard hobbyist PIR module. It relies on a pyroelectric sensor (usually the D203S) paired with a BIS0001 processing chip. The white plastic dome is a Fresnel lens that focuses infrared radiation from multiple focal points onto the sensor element, allowing it to detect motion rather than just static heat.

Required Components

  • Microcontroller: Arduino Uno R3 (ATmega328P) or Arduino Nano v3
  • Sensor Module: HC-SR501 PIR Motion Sensor (ensure it has the BIS0001 chip and dual potentiometers)
  • Wiring: 3x Male-to-Female or Male-to-Male jumper wires (22 AWG solid core recommended for breadboards)
  • Power: 5V USB cable or 7-12V DC barrel jack (do not rely on unregulated 9V batteries)

HC-SR501 Technical Specifications

Parameter Value / Range Notes
Operating Voltage 4.5V to 20V DC 5V is optimal for logic level matching
Output Logic HIGH ~3.3V Safe for 3.3V and 5V microcontrollers
Detection Angle < 120 degrees Determined by the Fresnel lens geometry
Detection Distance 3 to 7 meters Adjustable via the sensitivity potentiometer
Delay Time 0.3s to 200s Adjustable; sets how long OUT stays HIGH
Blockade Time 2.5s (default) Time sensor ignores motion after delay ends

Pin Mapping and Step-by-Step Wiring

Before wiring, locate the three-pin header on the HC-SR501. The pinout is almost always GND, OUT, VCC (from left to right when looking at the component side with the header at the bottom), but always verify the silkscreen on your specific board.

HC-SR501 Pin Arduino Uno R3 Pin Recommended Wire Color
VCC 5V Red
OUT Digital Pin 2 (D2) Yellow or Green
GND GND Black

Wiring and Calibration Steps

  1. De-energize the circuit: Unplug the Arduino USB cable before making connections to prevent accidental shorts on the 5V rail.
  2. Connect Power and Ground: Route the red wire from the sensor VCC to the Arduino 5V pin, and the black wire from sensor GND to Arduino GND.
  3. Connect the Signal: Route the yellow wire from the sensor OUT pin to Arduino Digital Pin 2.
  4. Adjust the Delay Potentiometer: Using a small Phillips screwdriver, turn the delay time potentiometer (usually on the right) fully counter-clockwise. This sets the delay to the minimum (~0.3 seconds), which is crucial for rapid testing.
  5. Adjust the Sensitivity Potentiometer: Turn the sensitivity potentiometer (usually on the left) to the 12 o'clock position for a medium detection range (~3-4 meters).
  6. Verify Trigger Mode: Look at the jumper cap near the potentiometers. Ensure it is in the 'H' position (outer pins) for retriggerable mode. This keeps the output HIGH as long as motion is continuously detected.

Complete Arduino Code with State-Change Handling

The following code targets the Arduino Uno R3 (and Nano v3). It includes a mandatory 30-second startup calibration lockout. When a PIR sensor powers on, it needs time to sample the ambient infrared baseline; reading the pin during this window will result in false triggers. The code also uses state-change detection to prevent flooding the Serial Monitor with repeated 'Motion Detected' messages.

/*
 * HC-SR501 PIR Motion Sensor - State Change Detection
 * Target Board: Arduino Uno R3 / Nano v3 (ATmega328P)
 * Author: ElectricalFlux
 */

// Pin Definitions
#define PIR_PIN 2       // Digital Pin 2 (supports external interrupts)
#define STATUS_LED 13   // Built-in LED on Uno R3

// Timing Constants
const unsigned long CALIBRATION_TIME = 30000; // 30 seconds for sensor baseline

// State Variables
int currentPirState = LOW;
int previousPirState = LOW;
unsigned long lockoutTimer = 0;
bool sensorReady = false;

void setup() {
  pinMode(PIR_PIN, INPUT);
  pinMode(STATUS_LED, OUTPUT);
  
  Serial.begin(115200);
  Serial.println(F("PIR Sensor Initializing..."));
  Serial.println(F("Calibrating baseline. Do not move in front of sensor."));
  
  // Hardware lockout: Allow the BIS0001 chip to stabilize
  lockoutTimer = millis();
  while(millis() - lockoutTimer < CALIBRATION_TIME) {
    // Blink LED slowly to indicate calibration mode
    digitalWrite(STATUS_LED, HIGH);
    delay(500);
    digitalWrite(STATUS_LED, LOW);
    delay(500);
  }
  
  sensorReady = true;
  Serial.println(F("Calibration complete. Sensor active."));
  
  // Read initial state to prevent false trigger on first loop iteration
  previousPirState = digitalRead(PIR_PIN);
}

void loop() {
  if (!sensorReady) return;

  currentPirState = digitalRead(PIR_PIN);

  // State-change detection (Edge triggering)
  if (currentPirState != previousPirState) {
    if (currentPirState == HIGH) {
      Serial.println(F("[EVENT] Motion Detected!"));
      digitalWrite(STATUS_LED, HIGH);
    } else {
      Serial.println(F("[EVENT] Motion Ended."));
      digitalWrite(STATUS_LED, LOW);
    }
    // Update state
    previousPirState = currentPirState;
  }
  
  // Small delay to debounce and yield processor time
  delay(50);
}

Debugging: First Three Things to Check When It Fails

PIR sensors are notoriously finicky on the workbench. If your build is not behaving, run through this ranked troubleshooting sequence before rewriting your code.

1. The First Three Hardware Checks

  1. Power Supply Ripple and Sag: The BIS0001 chip is highly sensitive to voltage fluctuations. If you are powering the Arduino via a cheap, unbranded USB wall wart or a laptop USB port that is sagging below 4.8V, the sensor will continuously reset and output erratic HIGH/LOW signals. Fix: Use a high-quality 5V 2A USB power supply or power the Arduino via the barrel jack with a 9V adapter.
  2. Potentiometer Physical Positions: If the Serial Monitor spams 'Motion Detected' and never prints 'Motion Ended', your delay time potentiometer is likely turned fully clockwise. This sets the hardware delay to ~200 seconds. Fix: Turn the delay potentiometer fully counter-clockwise to drop the hardware delay to 0.3 seconds.
  3. Thermal Stabilization (Warm-up): If the sensor triggers immediately upon power-up even with no one in the room, it is reacting to its own internal temperature rise. Fix: Ensure the 30-second software lockout in the setup() function is intact, and physically cover the lens with a cup during power-on.

2. Resolving Exact Error Strings

Compile Error: error: 'PIR_PIN' was not declared in this scope

  • Cause 1: You copied the loop() but forgot the #define PIR_PIN 2 at the top of the sketch.
  • Cause 2: Typo in the variable name (e.g., using pirPin in the loop but defining PIR_PIN).
  • Fix: Ensure the exact #define macros from the code block above are present at the very top of your file, before void setup().

Runtime Error: Serial Monitor outputs ⸮⸮⸮⸮⸮⸮ (garbage characters) or nothing at all.

  • Cause 1: Baud rate mismatch. The code initializes Serial at 115200, but the IDE Serial Monitor dropdown is set to 9600.
  • Fix: Change the baud rate dropdown in the bottom right corner of the Arduino IDE Serial Monitor to 115200.

For deeper hardware integration, always refer to the Arduino digitalRead() Reference to understand how floating pins can cause phantom readings if the OUT wire is disconnected.

Extending and Simplifying the Build

How to Simplify (No Microcontroller Required)

If you only need to turn on a 12V LED strip or a 120V AC porch light when someone walks by, you do not need an Arduino. The HC-SR501 can directly drive a 5V relay module. Connect the sensor VCC to a 5V power supply, GND to ground, and the OUT pin directly to the IN pin of a standard 5V optocoupler relay module. Wire your load through the relay's Normally Open (NO) and Common (COM) terminals. This eliminates code entirely and reduces the failure points to just the hardware.

How to Extend (IoT and Environmental Gating)

To make the build smarter, add environmental gating. Wire a GL5528 photoresistor (LDR) in a voltage divider configuration to Arduino Analog Pin A0. Modify the code to only register digitalRead(PIR_PIN) if the analog reading from the LDR indicates it is dark outside. For IoT integration, swap the Arduino Uno R3 for an ESP32 DevKit V1. The ESP32 is 3.3V logic native (which perfectly matches the PIR's 3.3V output), and you can use the WiFi library to publish the motion events to an MQTT broker like Mosquitto for Home Assistant integration. See the Adafruit PIR Sensor Guide for more on integrating PIRs with microcontrollers.

Frequently Asked Questions

Why is my PIR motion sensor Arduino project triggering falsely with no one in the room?

False triggers are almost always caused by environmental heat sources or power noise. Ensure the sensor is not pointed at an HVAC vent, a window with direct sunlight, or a heat-generating appliance like a refrigerator compressor. Electrically, long unshielded jumper wires between the sensor and the Arduino can act as antennas, picking up EMI from nearby AC mains wiring. Keep the wire run under 12 inches, or add a 0.1µF ceramic capacitor across the VCC and GND pins on the sensor module to filter high-frequency noise.

Can I power the HC-SR501 PIR sensor with 3.3V from an Arduino Pro Mini or ESP32?

No. The HC-SR501 has an onboard voltage regulator (usually an LDO) designed to step down 5V to 3.3V for the BIS0001 chip. If you feed it 3.3V, the regulator will drop the voltage below the chip's minimum operating threshold, causing it to brownout and behave erratically. You must power the VCC pin with at least 4.5V. However, the output signal from the OUT pin is safely regulated to 3.3V, meaning it is perfectly safe to connect the OUT pin directly to a 3.3V ESP32 GPIO without a logic level shifter.

How do I change the HC-SR501 from retriggerable to non-retriggerable mode for Arduino interrupts?

Look at the bottom left corner of the sensor module (component side). You will see a jumper cap bridging two of three available pins. If the jumper is on the outer two pins (labeled 'H' on some boards), it is in retriggerable mode (the timer resets with every new motion). To change it to non-retriggerable mode (labeled 'L'), remove the jumper cap and place it on the inner two pins. In non-retriggerable mode, the OUT pin will go LOW exactly when the delay timer expires, regardless of whether you are still waving your hand in front of the lens.

What is the minimum distance a PIR sensor can detect motion for an Arduino security setup?

The HC-SR501 struggles with detection closer than 1 to 1.5 meters. The Fresnel lens is designed to focus distant infrared gradients onto the dual sensing elements. If a heat source is too close, it floods both elements simultaneously, and the differential comparator inside the BIS0001 chip registers zero change, resulting in no trigger. If you need to detect presence at a distance of 10 to 30 centimeters (like a soap dispenser or automatic trash can), you should use a Time-of-Flight (ToF) sensor like the VL53L0X or a standard infrared proximity sensor instead of a PIR.