A light dependent resistor (LDR), also known as a photoresistor, drops its electrical resistance as light intensity increases. To read this analog change with a microcontroller, you must build a voltage divider circuit that converts the resistance shift into a variable voltage (0V to 5V), which the Arduino's internal Analog-to-Digital Converter (ADC) translates into a 10-bit integer (0-1023). This guide covers the exact hardware, wiring, smoothing code, and bench-level debugging required to get reliable readings from a light dependent resistor Arduino setup.
Project Overview and Difficulty Rating
Target Board: Arduino Uno R3 (ATmega328P) or Arduino Nano v3 (ATmega328P). The code and pinouts below specifically target the Uno R3's 5V logic and 10-bit ADC architecture.
Hardware Spec Sheet and Parts List
Choosing the right fixed resistor for your voltage divider is the most common point of failure in LDR circuits. The fixed resistor should roughly match the LDR's resistance at your target lighting level to maximize the voltage swing across the ADC range. The GL5528 is the industry-standard hobbyist LDR, peaking in sensitivity around 540nm (green-yellow light, similar to human vision).
| Component | Exact Variant / Spec | Notes |
|---|---|---|
| Microcontroller | Arduino Uno R3 (ATmega328P) | 5V logic, 10-bit ADC (6 channels) |
| Photoresistor | GL5528 (5mm diameter) | 10-20kΩ at 10 lux; ~1MΩ in total darkness |
| Fixed Resistor | 10kΩ (Brown-Black-Orange-Gold) | 1/4W carbon film; matches GL5528 at room light |
| Wiring | 22 AWG solid core jumper wires | Pre-cut breadboard lengths |
| Breadboard | Standard 830-tie-point | Ensure power rails are continuous |
For a deeper understanding of how the voltage divider circuits work to scale down resistance into readable voltage, refer to standard DC circuit theory. The formula governing this is Vout = Vin * (R_fixed / (R_LDR + R_fixed)).
Pin Mapping and Wiring Steps
This topology places the LDR on the high side (connected to 5V) and the fixed 10kΩ resistor on the low side (connected to GND). This means more light = lower LDR resistance = higher voltage at the analog pin.
| Arduino Uno R3 Pin | Wire Color | Destination |
|---|---|---|
| 5V | Red | LDR Leg 1 |
| A0 | Yellow | Voltage Divider Junction (LDR Leg 2 + 10kΩ Leg 1) |
| GND | Black | 10kΩ Leg 2 |
- Insert the GL5528 LDR: Place the two legs across the breadboard's center trench. Polarity does not matter; photoresistors are non-polarized.
- Insert the 10kΩ Resistor: Place one leg in the same row as one of the LDR legs (this creates the junction). Place the other leg in an empty row.
- Wire the Junction to A0: Use a yellow jumper wire to connect the shared LDR/Resistor row directly to the Arduino's A0 pin.
- Wire Power and Ground: Connect the empty LDR leg to the 5V rail. Connect the empty 10kΩ resistor leg to the GND rail.
- Verify Connections: Tug gently on the jumper wires at the Arduino header to ensure they are fully seated in the female sockets.
Complete Arduino C++ Code
Raw analogRead() values from an LDR are notoriously noisy due to 50/60Hz mains hum coupling into the high-impedance voltage divider. This code implements an Exponential Moving Average (EMA) filter to smooth the data, along with strict pin definitions and serial initialization checks.
// Light Dependent Resistor Arduino Code with EMA Smoothing
// Target: Arduino Uno R3 (ATmega328P)
#define LDR_PIN A0 // Analog pin connected to the voltage divider junction
#define LED_PIN 13 // Built-in LED for threshold indication
#define THRESHOLD 500 // ADC value (0-1023) to trigger 'dark' state
// EMA Filter parameters (Alpha = 0.1 for heavy smoothing)
const float ALPHA = 0.1;
float smoothedValue = 0.0;
void setup() {
pinMode(LED_PIN, OUTPUT);
// Initialize serial and verify connection
Serial.begin(9600);
while (!Serial) {
; // Wait for serial port to connect. Needed for native USB boards (e.g., Leonardo), harmless on Uno.
}
// Prime the filter with an initial reading to prevent startup spikes
smoothedValue = analogRead(LDR_PIN);
Serial.println("LDR Sensor Initialized. Shining light lowers resistance, raising ADC value.");
}
void loop() {
// Read raw 10-bit ADC value (0 to 1023)
int rawValue = analogRead(LDR_PIN);
// Apply Exponential Moving Average filter
smoothedValue = (ALPHA * rawValue) + ((1.0 - ALPHA) * smoothedValue);
// Cast to integer for clean serial output
int finalValue = (int)smoothedValue;
// Output data for Serial Plotter or Monitor
Serial.print("Raw: ");
Serial.print(rawValue);
Serial.print(" | Smoothed: ");
Serial.println(finalValue);
// Threshold logic: Turn on LED if room is dark (low light = low ADC value in this topology?
// Wait, our topology: More light = higher voltage. So Dark = LOW value.)
if (finalValue < THRESHOLD) {
digitalWrite(LED_PIN, HIGH); // Turn on LED when dark
} else {
digitalWrite(LED_PIN, LOW); // Turn off LED when bright
}
delay(50); // 20Hz sampling rate
}
Debugging: Analog Read Stuck at 1023 or 0
The most common failure mode when building a light dependent resistor Arduino circuit is a frozen serial output. If your serial monitor prints Sensor Value: 1023 continuously (or 0 continuously) regardless of how much light hits the sensor, follow this ranked troubleshooting path.
1. Voltage Divider Topology: Did you swap the LDR and the 10kΩ resistor? If the 10kΩ is on top and LDR on bottom, the logic is inverted, but it shouldn't pin at 1023 unless the LDR is shorted.
2. Ground Continuity: A floating ground on the 10kΩ resistor will cause the analog pin to read maximum voltage (1023).
3. Pin Definition Mismatch: Ensure
#define LDR_PIN A0 matches the physical wire. Plugging into A1 while the code reads A0 will yield random noise or 0.
Ranked Causes for Pinned Readings
- Cause: Floating Analog Pin (Reads random 0-1023 or pinned 1023)
Fix: The junction wire between the LDR and 10kΩ resistor is not making contact with the A0 header. Reseat the jumper wire. Measure continuity from the breadboard junction row to the Arduino A0 pin with a multimeter. - Cause: Missing Ground Path (Reads 1023 constantly)
Fix: The 10kΩ resistor is not connected to GND. The ADC is reading the full 5V through the LDR. Set your DMM to DC Volts, probe the bottom leg of the 10kΩ resistor and the Arduino GND pin. It should read 0.00V. If it reads 5V, your ground wire is broken or disconnected. - Cause: Shorted LDR (Reads 1023 constantly)
Fix: The two legs of the LDR are in the same breadboard row, or the LDR is internally damaged (shorted). Remove the LDR and measure its resistance across the legs with a DMM. In room light, it should read between 5kΩ and 20kΩ. If it reads near 0Ω, replace the component. - Cause: Missing 5V Supply (Reads 0 constantly)
Fix: The LDR is not receiving 5V. Check the red jumper wire from the Arduino 5V pin to the breadboard power rail.
Extending and Simplifying the Build
Once your basic light dependent resistor Arduino circuit is reading cleanly, you can adapt it for real-world home automation or simplify it for binary triggers.
How to Extend: Adding a 5V Relay Module
To switch a 120V AC lamp based on room darkness, add an opto-isolated 5V relay module. Wire the relay's VCC to 5V, GND to GND, and the IN pin to Arduino Digital Pin 8. Replace the LED_PIN logic in the code above with RELAY_PIN. Safety Warning: Never connect mains AC voltage directly to an Arduino or a breadboard. Use a properly rated relay module and enclosed terminal blocks for the high-voltage side.
How to Simplify: Using an LM393 Comparator Module
If you only need a simple "Is it dark? Yes/No" trigger and want to free up the Arduino's ADC and processing cycles, buy a pre-built LDR module with an LM393 comparator chip (usually ~$2.00). These modules feature a digital output (DO) pin and a small blue trimmer potentiometer. You can wire the DO pin to any digital Arduino pin and use digitalRead(), entirely bypassing the analog smoothing code and voltage divider math.
Frequently Asked Questions
Can I power a light dependent resistor Arduino setup with 3.3V?
Yes. The LDR and voltage divider are purely passive and scale linearly with the supply voltage. If you are using a 3.3V board (like an Arduino Due, ESP32, or Raspberry Pi Pico), wire the top of the LDR to 3.3V instead of 5V. The ADC will still map the voltage to its maximum digital value (e.g., 1023 for a 10-bit ADC, or 4095 for a 12-bit ADC like the ESP32), representing the full 3.3V range. Ensure your microcontroller's analog pins are strictly 3.3V tolerant before connecting.
Why does my LDR analog read fluctuate by 10-20 points in stable light?
This is caused by electromagnetic interference (EMI), specifically 50Hz or 60Hz mains hum from nearby AC wiring or fluorescent lights coupling into the high-impedance voltage divider node. The Arduino's ADC samples quickly and catches these AC ripple peaks. The Exponential Moving Average (EMA) filter provided in the code above is specifically designed to mathematically crush this high-frequency noise. If physical noise persists, add a 0.1µF (100nF) ceramic capacitor in parallel with the 10kΩ fixed resistor to create a hardware low-pass filter.
How do I calibrate the lux value for a GL5528 photoresistor?
The GL5528 datasheet provides a logarithmic resistance-to-lux curve, typically expressed as R = A * (Lux)^(-gamma). However, component variance is high (often ±20% from the factory). To calibrate, place a commercial lux meter (or a calibrated smartphone ambient light sensor app) next to the LDR. Record the Arduino's raw ADC value and the real lux level at three points: dim room light, bright desk lamp, and direct sunlight. Map these three data points in your code using a piecewise linear interpolation function rather than relying on the theoretical datasheet formula.
What is the difference between an LDR and a digital light sensor like the BH1750?
An LDR (like the GL5528) is a passive, analog component that changes resistance based on light. It is cheap, slow to react (20-50ms response time), and highly non-linear. A digital sensor like the BH1750 is an active IC that uses a photodiode and an internal ADC to calculate lux, outputting the data via the I2C protocol. The BH1750 is vastly more accurate, responds in milliseconds, and rejects 50/60Hz flicker internally. Choose an LDR for simple, low-cost threshold triggers (like a nightlight). Choose a BH1750 when you need precise, calibrated lux measurements for data logging or plant grow-light monitoring.






