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:
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)
Resistance vs. Light Intensity
| Light Condition | Illuminance (lux) | Typical Resistance |
|---|---|---|
| Complete Darkness | 0 | 1-10 MΩ |
| Moonlight | 0.1 | 100-500 kΩ |
| Dim Indoor | 10-50 | 10-50 kΩ |
| Normal Room | 100-300 | 5-10 kΩ |
| Bright Office | 500-1000 | 1-2 kΩ |
| Direct Sunlight | 10,000-100,000 | 100-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.
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
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
- Automatic Lighting: Street lights, garden lights, hallway lights
- Display Brightness: Auto-dimming screens and instruments
- Photography: Light meters, automatic camera settings
- Solar Tracking: Optimizing solar panel orientation
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:
Schmitt Trigger Behavior:
This software implementation mimics a Schmitt trigger, a fundamental circuit in digital electronics used for noise-immune switching.
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
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.
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
- Security Systems: Detect when dark enclosures are opened
- Safety Monitoring: Ensure machine guards are in place
- Environmental Control: Greenhouse light monitoring
- Scientific Experiments: Light-triggered data logging
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.
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
| Issue | Solution |
|---|---|
| AC Light Flicker | Average readings over 20ms (one AC cycle) |
| Temperature Drift | Use ambient temperature compensation or differential sensing |
| Aging Effects | Periodic recalibration, compare against reference |
| Limited Range | Use different fixed resistor values for different applications |
| Slow Response | Use 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
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