To connect an Arduino with motion sensor capabilities using the standard HC-SR501 PIR (Passive Infrared) module, wire the sensor VCC to the Arduino 5V pin, GND to GND, and the OUT pin to Digital Pin 2. The HC-SR501 operates on 5V to 20V input, but its internal voltage regulator drops the OUT signal to a safe 3.3V HIGH when motion is detected, making it directly compatible with both 5V and 3.3V microcontrollers without logic level shifters.
Building a reliable motion detection circuit goes beyond simple jumper wires. PIR sensors are highly susceptible to power supply ripple, thermal drafts, and improper calibration timing. This guide provides the exact hardware specifications, a robust C++ codebase with a mandatory warm-up sequence, and a debugging framework for the most common failure modes encountered on the bench.
Project Spec Sheet and Bill of Materials
Estimated Build Time: 25 minutes
Target Board Variant: Arduino Uno R3 (ATmega328P) or identical footprint clones.
| Component | Exact Variant / Specification | Est. Price (2026) |
|---|---|---|
| Microcontroller | Arduino Uno R3 (DIP ATmega328P) | $24.00 |
| Motion Sensor | HC-SR501 PIR Module (with BISS0001 IC) | $2.50 |
| Indicator LED | 5mm Diffused Red LED | $0.10 |
| Current Limiting Resistor | 220Ω or 330Ω (1/4W) | $0.05 |
| Power Decoupling Capacitor | 100µF Electrolytic (16V or higher) | $0.20 |
| Wiring | 22 AWG solid core jumper wires | $4.00 |
Pin Mapping and Wiring Procedure
The HC-SR501 features a 3-pin header. Looking at the module with the dome lens facing away from you and the pins pointing down, the left pin is GND, the center is OUT, and the right is VCC. Always verify this with a multimeter if you are using an unbranded clone, as some manufacturers reverse the VCC and GND pins, which will instantly destroy the BISS0001 timing IC.
| HC-SR501 Pin | Arduino Uno R3 Pin | Wire Color (Standard) |
|---|---|---|
| VCC (Right) | 5V | Red |
| OUT (Center) | Digital Pin 2 | Yellow |
| GND (Left) | GND | Black |
- Place the decoupling capacitor: Insert the 100µF capacitor across the breadboard's 5V and GND rails. This is non-negotiable for PIR sensors; they draw sudden current spikes when triggering, which causes voltage sags that reset the internal BISS0001 chip, leading to infinite trigger loops.
- Wire the sensor: Connect the HC-SR501 VCC to the 5V rail, GND to the ground rail, and OUT to Arduino Digital Pin 2.
- Wire the indicator: Connect the 220Ω resistor from Arduino Digital Pin 13 to the anode (long leg) of the LED. Connect the cathode to GND.
- Set the potentiometers: Using a small Phillips screwdriver, turn the Tx (Time Delay) potentiometer fully counter-clockwise to set the hardware delay to its minimum (~3 seconds). Turn the Sx (Sensitivity) potentiometer to the middle position.
- Set the jumper cap: Place the jumper on the HC-SR501 in the H position (closest to the diode). This enables "Retrigger" mode, where the output stays HIGH as long as motion is continuously detected.
Complete Arduino Code with Calibration Delay
The most common mistake beginners make when coding an Arduino with motion sensor setups is polling the pin immediately on boot. Pyroelectric sensors require a 30 to 60-second calibration period to establish a baseline thermal profile of the room. If you read the pin during this window, you will get erratic false positives. The code below targets the Arduino Uno R3 and includes this mandatory blocking calibration phase, along with software debounce logic.
// Target Board: Arduino Uno R3 (ATmega328P)
// Sensor: HC-SR501 PIR Motion Sensor
#define PIR_PIN 2
#define LED_PIN 13
#define CALIBRATION_TIME 45000 // 45 seconds for thermal baseline
unsigned long lastTriggerTime = 0;
const unsigned long DEBOUNCE_DELAY = 500; // 500ms software debounce
bool motionState = false;
void setup() {
Serial.begin(115200);
pinMode(PIR_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
Serial.println("SYSTEM: Initializing PIR sensor...");
Serial.println("SYSTEM: Calibrating thermal baseline. Do not move.");
// Mandatory warm-up period
for (int i = 0; i < 45; i++) {
delay(1000);
if (i % 10 == 0) {
Serial.print("Calibrating... ");
Serial.print(45 - i);
Serial.println("s remaining");
}
}
Serial.println("SYSTEM: Calibration complete. Active.");
}
void loop() {
int sensorValue = digitalRead(PIR_PIN);
unsigned long currentMillis = millis();
if (sensorValue == HIGH && (currentMillis - lastTriggerTime > DEBOUNCE_DELAY)) {
if (!motionState) {
motionState = true;
digitalWrite(LED_PIN, HIGH);
Serial.println("[EVT] Motion Detected!");
lastTriggerTime = currentMillis;
}
}
else if (sensorValue == LOW && motionState) {
motionState = false;
digitalWrite(LED_PIN, LOW);
Serial.println("[EVT] Motion Ended.");
}
}
Note: If you attempt to compile this and receive the compiler error 'PIR_PIN' was not declared in this scope, ensure you have not accidentally deleted the #define macros at the top of the sketch or placed them after the setup() function.
Debugging: First Three Things to Check When It Fails
When your serial monitor outputs the exact error string [ERR] Sensor stuck HIGH. Output: "Motion Detected!" repeating >5Hz. or the LED simply never turns off, do not immediately assume the sensor is defective. PIR modules are analog thermal devices masquerading as digital switches. Here are the first three things to check, ranked by probability.
- Power Supply Ripple and Ground Loops (80% of failures): The HC-SR501 is incredibly sensitive to voltage noise. If you are powering the Arduino via a cheap, unregulated USB wall wart, the 5V rail will have high-frequency ripple. The BISS0001 IC interprets this ripple as thermal noise and triggers continuously. Fix: Ensure the 100µF capacitor is installed directly at the sensor's power rails. If the issue persists, power the Arduino from a regulated bench supply or a high-quality laptop USB-C hub.
- The Tx Potentiometer is Cranked to Maximum (15% of failures): The time delay potentiometer has a range of roughly 3 seconds to 200 seconds. If it is turned fully clockwise, the OUT pin will remain HIGH for over three minutes after a single trigger, making it appear "stuck." Fix: Turn the Tx potentiometer fully counter-clockwise, then advance it exactly one-eighth of a turn to set a reliable ~5-second hardware delay.
- Thermal Drafts and RF Interference (5% of failures): PIR sensors do not detect "motion"; they detect changes in infrared radiation. A hot air vent, a sunbeam moving across the floor, or even a nearby 2.4GHz WiFi router (which can induce currents in the sensor's unshielded traces) will cause false triggers. Fix: Move the sensor away from HVAC registers and windows. If RF interference is suspected, wrap the sensor's PCB in aluminum foil tape, ensuring the tape does not touch any components or the dome lens, and ground the tape to the Arduino GND.
Extending and Simplifying the Build
Depending on your end goal, you may want to strip this project down to its bare essentials or expand it into a full IoT node.
How to Simplify:
If you are building a simple closet light trigger and want to minimize components, remove the external LED and resistor entirely. Modify the code to use pinMode(LED_BUILTIN, OUTPUT) and target the Arduino's onboard Pin 13 LED. You can also power the HC-SR501 directly from a 3S LiPo battery (11.1V - 12.6V) connected to the Arduino's Vin pin, bypassing the USB regulator entirely for a portable, wireless setup.
How to Extend:
To prevent the sensor from triggering during the day, add an LDR (Light Dependent Resistor) voltage divider to Analog Pin A0. Wire a 10kΩ resistor from A0 to GND, and the LDR from A0 to 5V. Read the analog value in your loop(); if the value is above 600 (indicating daylight), ignore the PIR's HIGH signal. For a smart home integration, swap the Arduino Uno for an ESP32 DevKit V1. The HC-SR501's 3.3V output is natively compatible with the ESP32's GPIO pins, allowing you to publish the motion state directly to an MQTT broker for Home Assistant automation.
FAQ: Arduino with Motion Sensor Questions
Can I power an Arduino with motion sensor using a 3.3V board like the ESP32?
Yes, but with a specific wiring caveat. The HC-SR501 requires a minimum of 4.5V on its VCC pin to operate its internal voltage regulator and BISS0001 IC. You must power the sensor's VCC from the ESP32's 5V (VIN) pin, not the 3V3 pin. However, because the sensor's OUT pin natively outputs 3.3V when HIGH, you can connect the OUT pin directly to any ESP32 GPIO without needing a logic level shifter or voltage divider.
Why does my HC-SR501 give false triggers when the room is completely empty?
"Empty room" false triggers are almost always caused by environmental thermal shifts rather than electrical faults. The Fresnel lens focuses infrared energy onto the pyroelectric crystal. If an air conditioning vent blows across the sensor, or if direct sunlight heats up a wall within the sensor's field of view, the rapid temperature delta mimics a human body moving. Additionally, if the sensor is missing its white plastic Fresnel dome, it will act as an omnidirectional thermal antenna and trigger from minor ambient temperature fluctuations.
How far can the Arduino with motion sensor detect movement?
With the standard Fresnel lens and the Sx sensitivity potentiometer turned to maximum, the HC-SR501 has a detection cone of roughly 110 degrees and a maximum range of 7 meters (23 feet). However, the reliable detection range for a human-sized heat source is typically 4 to 5 meters. Detection range drops significantly if the subject is moving directly toward the sensor rather than laterally across its field of view, as PIR sensors rely on the subject crossing the distinct thermal zones created by the lens facets.
What is the difference between the H and L jumper settings on the PIR?
The 3-pin header with the jumper cap dictates the retrigger behavior. In the H position (Retrigger), the output goes HIGH on motion, and the internal timer resets every time new motion is detected. The pin stays HIGH as long as you keep moving. In the L position (Non-Retrigger), the output goes HIGH for the duration set by the Tx potentiometer, and then goes LOW for a brief lockout period (approx. 3 seconds), during which it will ignore all motion. For most Arduino lighting and alarm projects, the H position is the correct choice.






