The HC-SR501 is the undisputed workhorse for a motion detector for Arduino projects. It costs about $2.50, runs on 5V to 20V, and outputs a clean 3.3V HIGH signal when it detects infrared body heat. However, its internal voltage regulator and analog timing circuits make it notoriously prone to false triggers if wired or powered incorrectly.
This guide targets the Arduino Uno R3 and Arduino Nano v3 (both ATmega328P variants). We will walk through the exact wiring, robust C++ code with hardware-fault error handling, and the specific quirks of the BISS0001 controller chip that cause 90% of debugging headaches on the bench.
Project Spec Sheet & Parts List
Estimated Time: 20 minutes
Target Board: Arduino Uno R3 / Arduino Nano v3 (5V logic)
| Component | Exact Variant / Spec | Estimated Cost |
|---|---|---|
| Microcontroller | Arduino Uno R3 (Rev3) or Nano v3 (ATmega328P) | $12.00 - $25.00 |
| PIR Sensor | HC-SR501 (Standard 3-pin with BISS0001 IC) | $2.00 - $3.50 |
| Pull-down Resistor | 10kΩ (1/4W, 5% tolerance) | $0.10 |
| Wiring | 22 AWG solid core or M-F jumper dupont cables | $5.00 |
| Power Supply | 5V 2A USB wall adapter (Avoid cheap unregulated PC USB ports) | $8.00 |
Pin Mapping & Wiring Steps
The HC-SR501 has three pins: VCC, OUT, and GND. The OUT pin actively drives HIGH (approx 3.3V) and LOW (0V). Because the output can float if the sensor is disconnected or unpowered, we use a 10kΩ external pull-down resistor on the signal line to keep the Arduino input anchored to GND.
| HC-SR501 Pin | Arduino Pin | Notes & Constraints |
|---|---|---|
| VCC | 5V | Do not use 3.3V. The onboard LDO needs ≥4.5V headroom. |
| OUT | D2 | Digital Pin 2. Capable of hardware interrupts (INT0). |
| GND | GND | Must share a common ground with the Arduino. |
Numbered Wiring Steps:
- Connect the HC-SR501 VCC pin to the Arduino 5V pin.
- Connect the HC-SR501 GND pin to the Arduino GND pin.
- Insert a 10kΩ resistor between Arduino Digital Pin 2 and GND on your breadboard.
- Connect the HC-SR501 OUT pin to Arduino Digital Pin 2 (junction with the pull-down resistor).
- Locate the two orange potentiometers on the HC-SR501. Turn the Time Delay pot fully counter-clockwise (minimum ~0.3s delay) and the Sensitivity pot to the 12 o'clock position (approx 4.5m range) for initial bench testing.
Complete Arduino Code with State Lock Detection
The BISS0001 chip inside the HC-SR501 can occasionally lock into a HIGH state due to power rail ripple or electromagnetic interference. The code below includes a software watchdog that monitors for an impossible continuous HIGH state, throwing a specific error string to the Serial monitor so you know the hardware has faulted rather than just detecting a stationary person.
/*
* HC-SR501 PIR Motion Detector for Arduino
* Target: Arduino Uno R3 / Nano v3 (ATmega328P)
* Author: ElectricalFlux Bench Team
*/
// Pin Definitions
const int PIR_PIN = 2; // Digital Pin 2 (Hardware Interrupt capable)
const int LED_PIN = 13; // Onboard LED for visual confirmation
// Timing & Threshold Constants
const unsigned long CALIBRATION_TIME = 30000; // 30s boot calibration
const unsigned long MAX_HIGH_DURATION = 600000; // 10 minutes max valid motion
// State Variables
int currentMotionState = LOW;
unsigned long motionStartTime = 0;
bool isCalibrated = false;
void setup() {
Serial.begin(115200);
pinMode(PIR_PIN, INPUT); // External 10k pull-down used, no internal pull-up
pinMode(LED_PIN, OUTPUT);
Serial.println("SYS: Booting HC-SR501...");
Serial.println("SYS: Calibrating ambient IR for 30 seconds. Stand clear.");
// Wait for the BISS0001 chip to sample ambient infrared baseline
unsigned long bootTime = millis();
while (millis() - bootTime < CALIBRATION_TIME) {
digitalWrite(LED_PIN, HIGH);
delay(250);
digitalWrite(LED_PIN, LOW);
delay(250);
}
isCalibrated = true;
Serial.println("SYS: Calibration complete. Monitoring...");
}
void loop() {
if (!isCalibrated) return;
currentMotionState = digitalRead(PIR_PIN);
if (currentMotionState == HIGH) {
digitalWrite(LED_PIN, HIGH);
// Record the exact time motion started
if (motionStartTime == 0) {
motionStartTime = millis();
Serial.println("EVT: Motion Detected");
}
// Error Handling: Check for hardware lock-up
// The HC-SR501 max physical delay is ~5 mins. If HIGH > 10 mins, it's a fault.
if (millis() - motionStartTime > MAX_HIGH_DURATION) {
Serial.println("ERR: PIR_STATE_LOCKED_HIGH");
Serial.println("ACT: Check 5V rail for ripple or cycle sensor power.");
// Blink LED rapidly to indicate hardware fault
for(int i=0; i<5; i++) {
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
delay(100);
}
motionStartTime = 0; // Reset to prevent serial flooding
delay(2000);
}
} else {
digitalWrite(LED_PIN, LOW);
if (motionStartTime != 0) {
unsigned long duration = millis() - motionStartTime;
Serial.print("EVT: Motion Ended. Duration: ");
Serial.print(duration / 1000);
Serial.println("s");
motionStartTime = 0;
}
}
delay(50); // Small debounce delay to prevent serial buffer flooding
}
Debugging: First 3 Things to Check When It Fails
When your Serial monitor spits out ERR: PIR_STATE_LOCKED_HIGH or the sensor triggers constantly without physical movement, do not throw the module away. The HC-SR501 is highly susceptible to its environment. Run through these three ranked checks:
- Power Supply Ripple (The "Always HIGH" Syndrome): The HC-SR501 uses a cheap linear dropout regulator (LDO) to step 5V down to 3.3V for the BISS0001 chip. If you power the Arduino via a cheap PC USB port or an unregulated wall wart, high-frequency ripple on the 5V rail passes through the LDO. The BISS0001 interprets this voltage noise as an IR threshold breach, locking the OUT pin HIGH. Fix: Power the Arduino with a high-quality 5V 2A switching wall adapter, or add a 100µF electrolytic capacitor directly across the HC-SR501 VCC and GND pins.
- Missing Initialization Time: If the sensor triggers immediately upon uploading code, you are reading the pin before the BISS0001 has stabilized. The chip requires 30 to 60 seconds on boot to sample the ambient infrared baseline of the room. Fix: Ensure your
setup()function includes a blocking delay or non-blocking timer of at least 30,000ms before reading the OUT pin. - Potentiometer Misconfiguration: The Time Delay potentiometer has a range of 0.3 seconds to roughly 5 minutes. If it was bumped to the maximum position during handling, the sensor will hold the OUT pin HIGH for 5 minutes after a single hand wave, making it appear "stuck." Fix: Turn the Time Delay pot fully counter-clockwise, then advance it 2mm clockwise for a ~1-second reset window.
INPUT_PULLUP on the PIR signal pin. The HC-SR501 actively drives the line. Engaging the internal 20k-50k pull-up resistor creates a voltage divider with the sensor's output impedance, which can pull the "LOW" state up to ~0.8V, dangerously close to the ATmega328P's 1.5V logic threshold and causing phantom triggers.
Extending and Simplifying the Build
How to Extend:
To make this a functional room automator, add a 5V relay module to switch a 120V AC desk lamp. Wire the Arduino D8 pin to the relay IN pin, and add digitalWrite(RELAY_PIN, HIGH) inside the motion detection block. You can also wire a GL5528 Photoresistor (LDR) in a voltage divider to Analog Pin A0, disabling the PIR logic in the code if the room's ambient light exceeds 700 lumens.
How to Simplify (ESP32 Migration):
If you want to simplify the build by adding Wi-Fi for MQTT alerts, migrating to an ESP32 DevKit v1 is ideal. The ESP32 operates on 3.3V logic. Because the HC-SR501's LDO outputs roughly 3.3V to its internal chip, the OUT pin naturally outputs ~3.3V when HIGH. This makes it directly compatible with ESP32 GPIO pins without a logic level shifter. Just remember to still power the HC-SR501 VCC pin with 5V to keep the LDO happy.
Frequently Asked Questions
Can I power the HC-SR501 motion detector for Arduino directly from a 3.3V pin?
No. While the BISS0001 chip inside runs on 3.3V, the module's VCC pin feeds an onboard LDO (usually an HT7133). If you feed 3.3V into VCC, the LDO drops it to roughly 2.8V. This causes the BISS0001 to brownout, resulting in erratic timing and a permanently locked HIGH output. Always feed VCC with 4.5V to 20V. If you absolutely must run the sensor on a 3.3V system, you have to physically bypass the onboard LDO by soldering a jumper wire directly to the 3.3V pad on the BISS0001 chip.
Why does my PIR sensor keep triggering when no one is in the room?
False triggers are usually caused by environmental IR shifts, not ghosts. The Fresnel lens focuses infrared light onto the pyroelectric sensor. If the sensor faces a window, sunlight shifting across the room will trigger it. Similarly, HVAC vents blowing hot or cold air across the sensor's field of view will create the thermal delta required to trip the BISS0001. Finally, RF interference from nearby Wi-Fi routers or two-way radios can induce voltage spikes on the high-impedance analog traces of the HC-SR501. Moving the sensor away from HVAC drafts and adding a 0.1µF ceramic decoupling capacitor across the VCC/GND pins solves 95% of phantom triggers.
How do I change the detection range on the HC-SR501?
You have two methods. Electrically, adjust the orange "Sensitivity" potentiometer. Clockwise increases the range up to 7 meters; counter-clockwise drops it to roughly 3 meters. Physically, you can alter the Fresnel lens. The multi-faceted plastic dome creates distinct "zones" of detection. If you want a narrow hallway beam instead of a 120-degree wide room sweep, you can mask the sides of the dome with opaque electrical tape, forcing the sensor to only "see" through the front-facing facets.
What is the difference between the HC-SR501 and the RCWL-0516 microwave sensor?
The HC-SR501 uses Passive Infrared (PIR) to detect changes in body heat. It requires a direct line of sight, cannot see through walls, and is highly directional. The RCWL-0516 uses Doppler radar (microwave) at roughly 3.2GHz. It detects physical movement regardless of temperature, penetrates drywall and thin wood, and has a 360-degree detection radius. Use the HC-SR501 for targeted room occupancy where you don't want the sensor triggering from the hallway next door. Use the RCWL-0516 for hidden installations behind plastic enclosures or drywall.






