Understanding Photoresistors

What is a Photoresistor?
A photoresistor (Light Dependent Resistor or LDR) is a passive component whose resistance decreases with increasing incident light intensity. They're made from semiconductor materials like cadmium sulfide (CdS).

Physical Principle:
When photons strike the semiconductor material, they provide energy to electrons, promoting them from the valence band to the conduction band. This increases the number of charge carriers, reducing resistance.

Typical Characteristics:
  • Dark Resistance: 1MΩ to 10MΩ
  • Bright Resistance: 100Ω to 1kΩ
  • Response Time: 10-100ms (relatively slow)
  • Spectral Peak: ~550nm (green light)
Important Note: LDRs are non-linear and have significant unit-to-unit variation. They're best for relative measurements, not absolute light level quantification.

Resistance vs. Light Intensity

Light ConditionIlluminance (lux)Typical Resistance
Complete Darkness01-10 MΩ
Moonlight0.1100-500 kΩ
Dim Indoor10-5010-50 kΩ
Normal Room100-3005-10 kΩ
Bright Office500-10001-2 kΩ
Direct Sunlight10,000-100,000100-500 Ω

Demo 1: Automatic Night Light (Voltage Divider)

Circuit Diagram

+5V | | [LDR] (Photoresistor) | +---> A0 (Analog Input) | [10kΩ] (Fixed Resistor) | GND LED Circuit: Pin 9 (PWM) ---[220Ω]---LED---|>|---GND

Theory

Voltage Divider Principle:
The LDR and fixed resistor form a voltage divider. The voltage at the junction (Vout) varies with light level:

Vout = Vin × (R2 / (R1 + R2))

Where R1 = LDR, R2 = Fixed resistor

Why 10kΩ?
The fixed resistor should be chosen near the middle of the LDR's resistance range for maximum sensitivity. With an LDR ranging from 1kΩ to 100kΩ, a 10kΩ resistor provides good response across typical indoor lighting conditions.

Calculations

Example Voltage Outputs:

Bright Conditions (RLDR = 1kΩ):
Vout = 5V × (10kΩ / (1kΩ + 10kΩ))
Vout = 5V × (10/11) = 4.55V
ADC reading = 4.55V × 1023/5V = 931

Dark Conditions (RLDR = 100kΩ):
Vout = 5V × (10kΩ / (100kΩ + 10kΩ))
Vout = 5V × (10/110) = 0.45V
ADC reading = 0.45V × 1023/5V = 92

Mid-Range (RLDR = 10kΩ):
Vout = 5V × (10kΩ / (10kΩ + 10kΩ))
Vout = 5V × 0.5 = 2.5V
ADC reading = 512

Arduino Code

// Automatic Night Light const int LDR_PIN = A0; const int LED_PIN = 9; // Calibration values (adjust based on your LDR and environment) const int DARK_THRESHOLD = 300; // Below this = dark const int BRIGHT_THRESHOLD = 700; // Above this = bright void setup() { pinMode(LED_PIN, OUTPUT); Serial.begin(9600); Serial.println("Automatic Night Light"); Serial.println("Cover sensor to activate light"); } void loop() { // Read light level int lightLevel = analogRead(LDR_PIN); // Map to LED brightness (inverted: darker = brighter LED) int ledBrightness = map(lightLevel, DARK_THRESHOLD, BRIGHT_THRESHOLD, 255, 0); ledBrightness = constrain(ledBrightness, 0, 255); // Set LED brightness analogWrite(LED_PIN, ledBrightness); // Display status Serial.print("Light Level: "); Serial.print(lightLevel); Serial.print(" | LED: "); Serial.print(ledBrightness); Serial.print(" | Status: "); if(lightLevel < DARK_THRESHOLD) { Serial.println("DARK - Light ON"); } else if(lightLevel > BRIGHT_THRESHOLD) { Serial.println("BRIGHT - Light OFF"); } else { Serial.println("DIMMING"); } delay(100); }

Use Cases

Demo 2: Light-Activated Alarm with Threshold Detection

Circuit Diagram

Voltage Divider (same as Demo 1): +5V ---[LDR]---+---[10kΩ]--- GND | +---> A0 Buzzer Circuit: Pin 8 ---[100Ω]---BUZZER(+) | GND Status LEDs: Pin 10 ---[220Ω]---LED(Green)---|>|---GND (Normal) Pin 11 ---[220Ω]---LED(Red)------|>|---GND (Alarm)

Theory

Threshold Detection:
Digital systems often need to make binary decisions from analog inputs. A threshold with hysteresis prevents rapid switching near the boundary (known as "chattering").

Hysteresis:
The system has two thresholds:
  • Upper Threshold: Must exceed this to trigger alarm
  • Lower Threshold: Must drop below this to cancel alarm
The gap between thresholds prevents oscillation when light level hovers near the boundary.

Schmitt Trigger Behavior:
This software implementation mimics a Schmitt trigger, a fundamental circuit in digital electronics used for noise-immune switching.

Calculations

Hysteresis Gap Calculation:

Assume we want to detect when someone opens a dark box (light suddenly increases):

Normal (dark) ADC value: ~200
Light exposed ADC value: ~800

Upper threshold (alarm ON): 500
Lower threshold (alarm OFF): 400
Hysteresis gap: 100 counts = 0.49V

This 100-count gap prevents false triggering from minor fluctuations or shadows.

Arduino Code

// Light-Activated Alarm with Hysteresis const int LDR_PIN = A0; const int BUZZER_PIN = 8; const int LED_NORMAL = 10; // Green const int LED_ALARM = 11; // Red const int UPPER_THRESHOLD = 500; // Trigger alarm const int LOWER_THRESHOLD = 400; // Cancel alarm const int ALARM_DURATION = 5000; // 5 seconds bool alarmActive = false; unsigned long alarmStartTime = 0; void setup() { pinMode(BUZZER_PIN, OUTPUT); pinMode(LED_NORMAL, OUTPUT); pinMode(LED_ALARM, OUTPUT); Serial.begin(9600); Serial.println("Light-Activated Alarm System"); Serial.println("Monitoring for sudden light increase..."); digitalWrite(LED_NORMAL, HIGH); // Start in normal state } void loop() { int lightLevel = analogRead(LDR_PIN); // Hysteresis threshold logic if(!alarmActive && lightLevel > UPPER_THRESHOLD) { // Light suddenly increased - trigger alarm alarmActive = true; alarmStartTime = millis(); Serial.println("\n*** ALARM TRIGGERED! ***"); } else if(alarmActive && lightLevel < LOWER_THRESHOLD) { // Light back to normal (but keep alarm for duration) // Don't cancel immediately } // Check alarm duration if(alarmActive && (millis() - alarmStartTime > ALARM_DURATION)) { alarmActive = false; Serial.println("Alarm reset\n"); } // Update outputs if(alarmActive) { // Sound buzzer and flash red LED digitalWrite(LED_NORMAL, LOW); digitalWrite(LED_ALARM, (millis() / 200) % 2); // Flash at 2.5 Hz tone(BUZZER_PIN, 2000, 100); // 2kHz beep Serial.print("ALARM! Light: "); Serial.print(lightLevel); Serial.print(" Time remaining: "); Serial.print((ALARM_DURATION - (millis() - alarmStartTime)) / 1000); Serial.println("s"); } else { // Normal state digitalWrite(LED_NORMAL, HIGH); digitalWrite(LED_ALARM, LOW); noTone(BUZZER_PIN); Serial.print("Normal - Light: "); Serial.println(lightLevel); } delay(100); }

Use Cases

Advanced Topics

Improving LDR Measurements

1. Averaging for Noise Reduction:
Take multiple readings and average them to reduce noise from AC lighting flicker (50/60 Hz) and random fluctuations.

2. Exponential Moving Average:
Smoothed = α × Current + (1-α) × Previous
where α = 0.1 to 0.3 for good smoothing

3. Calibration:
Store minimum and maximum readings during a calibration period, then map all subsequent readings to this range for consistent operation across different LDRs and environments.

4. Logarithmic Response:
LDR resistance varies roughly logarithmically with light intensity. For linear light measurement, apply log() transformation to ADC values.

Practical Design Considerations

IssueSolution
AC Light FlickerAverage readings over 20ms (one AC cycle)
Temperature DriftUse ambient temperature compensation or differential sensing
Aging EffectsPeriodic recalibration, compare against reference
Limited RangeUse different fixed resistor values for different applications
Slow ResponseUse photodiodes or phototransistors for faster response

Alternative Light Sensors

Photodiode: Fast response (μs), linear output, current-based, good for high-speed applications

Phototransistor: Amplified photodiode, faster than LDR, moderate cost

Digital Light Sensors (BH1750, TSL2561): I2C/SPI interface, calibrated lux output, excellent accuracy

Solar Cells: Generate voltage from light, can power low-current circuits directly