Analog Voltage Reading Method
The easiest way to measure a resistive sensor is to connect one end to Power and the other to a pull-down resistor to ground. Then the point between the fixed pulldown resistor and the variable photocell resistor is connected to the analog input of a microcontroller such as an Arduino (shown)For this example I'm showing it with a 5V supply but note that you can use this with a 3.3v supply just as easily. In this configuration the analog voltage reading ranges from 0V (ground) to about 5V (or about the same as the power supply voltage).
The way this works is that as the resistance of the photocell decreases, the total resistance of the photocell and the pulldown resistor decreases from over 600KΩ to 10KΩ. That means that the current flowing through both resistors increases which in turn causes the voltage across the fixed 10KΩ resistor to increase. Its quite a trick!
| Ambient light like… | Ambient light (lux) | Photocell resistance (Ω) | LDR + R (Ω) | Current thru LDR +R | Voltage across R |
|---|---|---|---|---|---|
| Dim hallway | 0.1 lux | 600KΩ | 610 KΩ | 0.008 mA | 0.1 V |
| Moonlit night | 1 lux | 70 KΩ | 80 KΩ | 0.07 mA | 0.6 V |
| Dark room | 10 lux | 10 KΩ | 20 KΩ | 0.25 mA | 2.5 V |
| Dark overcast day / Bright room | 100 lux | 1.5 KΩ | 11.5 KΩ | 0.43 mA | 4.3 V |
| Overcast day | 1000 lux | 300 Ω | 10.03 KΩ | 0.5 mA | 5V |
This table indicates the approximate analog voltage based on the sensor light/resistance w/a 5V supply and 10KΩ pulldown resistor.
If you're planning to have the sensor in a bright area and use a 10KΩ pulldown, it will quickly saturate. That means that it will hit the 'ceiling' of 5V and not be able to differentiate between kinda bright and really bright. In that case, you should replace the 10KΩ pulldown with a 1KΩ pulldown. In that case, it will not be able to detect dark level differences as well but it will be able to detect bright light differences better. This is a tradeoff that you will have to decide upon!
You can also use the "Axel Benz" formula by first measuring the minimum and maximum
resistance value with the multimeter and then finding the resistor value
with: Pull-Down-Resistor = squareroot(Rmin * Rmax), this will give you slightly better range calculations
| Ambient light like… | Ambient light (lux) | Photocell resistance (?) | LDR + R (?) | Current thru LDR+R | Voltage across R |
|---|---|---|---|---|---|
| Moonlit night | 1 lux | 70 KΩ | 71 KΩ | 0.07 mA | 0.1 V |
| Dark room | 10 lux | 10 KΩ | 11 KΩ | 0.45 mA | 0.5 V |
| Dark overcast day / Bright room | 100 lux | 1.5 KΩ | 2.5 KΩ | 2 mA | 2.0 V |
| Overcast day | 1000 lux | 300 Ω | 1.3 KΩ | 3.8 mA | 3.8 V |
| Full daylight | 10,000 lux | 100 Ω | 1.1 KΩ | 4.5 mA | 4.5 V |
This table indicates the approximate analog voltage based on the sensor light/resistance w/a 5V supply and 1K pulldown resistor.
Note that our method does not provide linear voltage with respect to brightness! Also, each sensor will be different. As the light level increases, the analog voltage goes up even though the resistance goes down:
Vo = Vcc ( R / (R + Photocell) )
That is, the voltage is proportional to the inverse of the photocell resistance which is, in turn, inversely proportional to light levels.
Simple Demonstration of Use
This sketch will take the analog voltage reading and use that to determine how bright the red LED is. The darker it is, the brighter the LED will be! Remember that the LED has to be connected to a PWM pin for this to work, I use pin 11 in this example./* Photocell simple testing sketch.
Connect one end of the photocell to 5V, the other end to Analog 0.
Then connect one end of a 10K resistor from Analog 0 to ground
Connect LED from pin 11 through a resistor to ground
For more information see http://learn.adafruit.com/photocells */
int photocellPin = 0; // the cell and 10K pulldown are connected to a0
int photocellReading; // the analog reading from the sensor divider
int LEDpin = 11; // connect Red LED to pin 11 (PWM pin)
int LEDbrightness; //
void setup(void) {
// We'll send debugging information via the Serial monitor
Serial.begin(9600);
}
void loop(void) {
photocellReading = analogRead(photocellPin);
Serial.print("Analog reading = ");
Serial.println(photocellReading); // the raw analog reading
// LED gets brighter the darker it is at the sensor
// that means we have to -invert- the reading from 0-1023 back to 1023-0
photocellReading = 1023 - photocellReading;
//now we have to map 0-1023 to 0-255 since thats the range analogWrite uses
LEDbrightness = map(photocellReading, 0, 1023, 0, 255);
analogWrite(LEDpin, LEDbrightness);
delay(100);
}
Simple Code for Analog Light Measurements
This code doesn't do any calculations, it just prints out what it interprets as the amount of light in a qualitative manner. For most projects, this is pretty much all thats needed!/* Photocell simple testing sketch.
Connect one end of the photocell to 5V, the other end to Analog 0.
Then connect one end of a 10K resistor from Analog 0 to ground
For more information see http://learn.adafruit.com/photocells */
int photocellPin = 0; // the cell and 10K pulldown are connected to a0
int photocellReading; // the analog reading from the analog resistor divider
void setup(void) {
// We'll send debugging information via the Serial monitor
Serial.begin(9600);
}
void loop(void) {
photocellReading = analogRead(photocellPin);
Serial.print("Analog reading = ");
Serial.print(photocellReading); // the raw analog reading
// We'll have a few threshholds, qualitatively determined
if (photocellReading < 10) {
Serial.println(" - Dark");
} else if (photocellReading < 200) {
Serial.println(" - Dim");
} else if (photocellReading < 500) {
Serial.println(" - Light");
} else if (photocellReading < 800) {
Serial.println(" - Bright");
} else {
Serial.println(" - Very bright");
}
delay(1000);
}
BONUS! Reading Photocells Without Analog Pins
Because photocells are basically resistors, its possible to use them even if you don't have any analog pins on your microcontroller (or if say you want to connect more than you have analog input pins). The way we do this is by taking advantage of a basic electronic property of resistors and capacitors. It turns out that if you take a capacitor that is initially storing no voltage, and then connect it to power (like 5V) through a resistor, it will charge up to the power voltage slowly. The bigger the resistor, the slower it is.This capture from an oscilloscope shows whats happening on the digital pin (yellow). The blue line indicates when the sketch starts counting and when the couting is complete, about 1.2ms later.
This is because the capacitor acts like a bucket and the resistor is like a thin pipe. To fill a bucket up with a very thin pipe takes enough time that you can figure out how wide the pipe is by timing how long it takes to fill the bucket up halfway.
/* Photocell simple testing sketch.
Connect one end of photocell to power, the other end to pin 2.
Then connect one end of a 0.1uF capacitor from pin 2 to ground
For more information see http://learn.adafruit.com/photocells */
int photocellPin = 2; // the LDR and cap are connected to pin2
int photocellReading; // the digital reading
int ledPin = 13; // you can just use the 'built in' LED
void setup(void) {
// We'll send debugging information via the Serial monitor
Serial.begin(9600);
pinMode(ledPin, OUTPUT); // have an LED for output
}
void loop(void) {
// read the resistor using the RCtime technique
photocellReading = RCtime(photocellPin);
if (photocellReading == 30000) {
// if we got 30000 that means we 'timed out'
Serial.println("Nothing connected!");
} else {
Serial.print("RCtime reading = ");
Serial.println(photocellReading); // the raw analog reading
// The brighter it is, the faster it blinks!
digitalWrite(ledPin, HIGH);
delay(photocellReading);
digitalWrite(ledPin, LOW);
delay(photocellReading);
}
delay(100);
}
// Uses a digital pin to measure a resistor (like an FSR or photocell!)
// We do this by having the resistor feed current into a capacitor and
// counting how long it takes to get to Vcc/2 (for most arduinos, thats 2.5V)
int RCtime(int RCpin) {
int reading = 0; // start with 0
// set the pin to an output and pull to LOW (ground)
pinMode(RCpin, OUTPUT);
digitalWrite(RCpin, LOW);
// Now set the pin to an input and...
pinMode(RCpin, INPUT);
while (digitalRead(RCpin) == LOW) { // count how long it takes to rise up to HIGH
reading++; // increment to keep track of time
if (reading == 30000) {
// if we got this far, the resistance is so high
// its likely that nothing is connected!
break; // leave the loop
}
}
// OK either we maxed out at 30000 or hopefully got a reading, return the count
return reading;
}