LDR calculations using a capacitor and Raspberry Pi

Hi all,

I am trying to make a light sensor using an LDR a resistor and capacitor.

I have used information from the following websites:


While I can get the code working with a few tweaks I am struggling to understand how to turn the time taken to discharge the capacitor to Lumens.

Not sure if this will help but I am using a 0.1uF capacitor and a standard LDR

Essentially, is there a way I can calculate the Lumens/Intensity of light using the time it takes for a capacitor to charge.



Hi Andrew
Firstly what is a “standard” LDR. I think they come in all different resistance and characteristics. Could be wrong here But I don’t know what a “standard” one is.

Usually use this type of thing as one leg of a voltage divider. The selection of resistors either side of it and the LDR resistance (light and dark) will determine the voltage range obtained.
This will be an analog voltage which will have to be converted into a number to do anything with it. This would be done with an ADC but I understand most RPis don’t have this facility built in so it would have to be separate.

That top link is a sneaky way of measuring the LDR resistance (that is what it is doing). It is measuring the time it takes to charge the capacitor to the RPi threshold point whatever that is. Probably returns a number in microseconds.

The lower link does essentially the same thing. I don’t quite agree with this statement though.

A capacitor essentially acts like a battery, charging up while receiving power and then discharging when no longer receiving power

This is not true. A capacitor will hold its charge for a very long time when power is removed. It will just charge up to a maximum and stay there.
It needs to be discharged between readings. I am not familiar with Python so can’t quite see how these authors are doing this so you will have to depend on a RPi Guru to chip in here to help out.

I don’t know how accurate this method would be. The result depends on how accurate the capacitor value is, these things vary considerably. Also the LDR tolerance. with this in mind I think each setup would need to be separately calibrated. Maybe the voltage divider and ADC method would be better but it does involve more bits.

There would be. You have to calculate the LDR resistance value then go to some look up table to get the number of lumens it takes to get that value. I don’t know where you are going to find this, possibly in a LDR data sheet but if you are using some sort of cheap Chinese one I would not hold my breath while looking. Search Element 14 and see if any of the data sheets provide this information.

Calculating the resistance value. This entails knowing the EXACT voltage applied to the R/C combination (LDR/0.1µF) and the EXACT point (Voltage) the RPi switches. There is a formula and I would have to look it up. It involves “natural” logarithms (not base 10) and from memory is a bit complex.
Cheers Bob


Hi Andrew
Found the basic formula

Now all you have to do is find a math guru to get the R over to the left hand side.

There may be another way.
Establish the EXACT RPi switching voltage.
1 time constant (TC) = R (MΩ) x C (µF) (TC = seconds)
Arrange the input voltage to the R/C network to be (switching V/63.2)*100 (1 TC =63.2% of applied voltage).
We know the cap to be in this example 0.1µF
The RPi is measuring the time to switching V which in this case is conveniently 1 TC.
Time (seconds)=R(MΩ) x C(µF)
So Time / C = R.
I think this is correct. The old grey matter is getting a bit fuzzy these days.

I think this would be the easiest way to use the capacitor method. All you have to do is find the corresponding Lumen number somewhere.
Cheers Bob


Although I don’t know Python, my interpretation of the code is discharging the capacitor for 0.1 (I assume seconds) then spinning while upping the count until the input goes high and returning the count. My first thought is discharging a capacitor through a pin is not good practice, as it does not limit the current and it could fritz the pin. Maybe the pi has a limiting resistor on output so this works reliably but I’d check the specs to be sure. If there is no limiting resistor in the processor, I’d put a resistor somewhere where the circuit has a yellow line. 220Ω should be enough, it isn’t stressed so the lowest wattage in the bit bin is adequate.

The measurement is until the input is detected as high, and the voltage to do that is unclear. I found this quote " *Normally the voltage threshold is about 1.8V, but it isn’t guaranteed; it can be anywhere between the maximum input low and minimum input high , that is, between about 0.8 and 2.0V ." Also, it could be temperature dependent [my thought].

According to what I read, the resistance of an LDR is inversely proportional to the light intensity. So the count returned by the code is inversely proportional to light intensity. i.e convert count to intensity,
intensity = K/count. K is a constant that will have to be determined experimentally - there are too many variables to rely on specifications and calculate it. Find the count when exposed to a known light source, work out the K that gives the right answer.

If the time is too short (i.e. a count of one at low light levels) then increase the capacitor value. If it is too long then decrease it. The time to charge is linearly related to the capacitor size so 0.22µF will take 2.2 times as long as 0.1µF for the same light intensity.


Hi Alan

Agree. Probably would 'fritz the pin" almost guaranteed.
Don’t really know enough about the characteristics of a digital input pin, probably needs a series resistor anyway. Anything you hang across the capacitor is going to interfere with the charging curve so the whole thing becomes meaningless or at best complicated.

The “flexibility” of the trigger point is another problem so methinks the ADC method using the LDR as one leg of a voltage divider would be the easiest and most reliable.
The down side here is because what Andrew is primarily interested in is the resistance of the LDR the supply to the divider will have to be a constant current source. This is not that difficult to arrange but if you are looking of an ADC range to 5V your primary supply would need to be something like 9 or 10V. The constant current circuitry has to drop 2 or 3V to start with.
Cheers Bob


I think you are overthinking this. Andrew said he was primarily interested in light level. He hasn’t said if this is to trigger an event at a specific light level, or to get a measure of the light level. Also not stated is the required accuracy - is ± 30% good enough? or the range (the range is huge - daylight 10,000 lux to starlight 0.001 lux approximately).

If ± 30% is good enough, variations due to trigger level, temperature etc are probably irrelevant, and counts from about 5 up will be relevant. I don’t know what size python’s “counter” is but if it is 16-bit binary then the maximum count is over 50,000 so can measure resistance changes of 1000:1.

Further reading says the resistance is NOT 100% inversely proportional to light, but less. The factor is described as γ and varies for different types of LDR. This described as:

γ value: Logarithm of the ratio of the standard resistance value under 10Lux and that under 100Lux.
γ=Log(R10/R100)/Lg(100/10) where
R10,R100 are the resistances under 10Lux and 100Lux respectively.

Values quoted are 0.5 to 0.9. So calibrating an unknown LDR will require at least two known intensity sources. The upside is a 1000:1 resistance ratio is a larger lux ratio.

Better accuracy may be difficult. Getting an accurate trigger point is easy, use a comparator like an LM393 with a fixed resistance divider on one side and the LDR+capacitor on the other side. This is a bridge configuration so I suspect it would be relatively immune to voltage variations. But there would be other factors such as the minimum on resistance of the LDR to consider (I think it doesn’t matter how much light is applied, there will be a residual resistance).

If the lux range to measure is more than can be covered by the method, two capacitors could be used - say 0.1µF and 1nF. Instead of connecting the ground leg to ground, connect to a GPIO pin. Set pin as input renders it inoperative, set as output 0 it comes into effect. It would be unnecessary to do this to the smaller capacitor, just the larger one. The ratio is unlikely to be 100:1 due to component variation so would need to be determined if it was important.


Hi Alan
Very well put. I realise Andrew’s primary interest is in light level but the only tangible thing he has to measure is the LDR resistance. Then he has to convert that into whatever unit he needs. That is what I was getting at.

Your suggestion of a LM393 is an excellent idea. Gets rid of the GPIO switching uncertainty and is readily controllable.

A constant current source would get rid of the capacitor charge non linearity. The charging curve would be a straight line. It is by the way, many years ago I had occasion to make up a time base which had to be nice and linear. I did this with a 555 and charged the timing cap via a constant current source and finished up with a beautiful sawtooth wave. The straight line might be easier to handle and manipulate.

The problem with capacitor discharge remains. I have an idea this could be done with a mosfet and small series resistor across the cap. This could be switched by the RPi in the normal manner as part of the timing cycle. The resistance of the Mosfet would be very high when off and should not interfere with the capacitor timing.

I think you would agree this problem has got a bit above the simple LDR and capacitor scheme linked previously. But I also think you would agree that to have something useable and more importantly repeatable a bit of massaging and added complexity is required.
Cheers Bob
EDIT. Sorry. Delete reference to a constant current source. that will defeat the purpose. The resistance of the source will change to keep the current constant so the combined resistance of the source and LDR will appear not to change. FORGET this bit.

1 Like

I’m happy with the LDR+capacitor scheme if discharging through a resistor. The non linearity of charging is irrelevant, it is the time to get to a particular voltage and that is the inverse of the resistance of the LDR. How it got there doesn’t change the result. Also, discharging the capacitor via a GPIO port is fine with a 220Ω resistor over 0.1 seconds, unless the value is many µF (then the time constant comes into play). The trigger point was less than 2V and even with a comparator it is likely to be half the supply - 2.5V. 2.5V through 220Ω is just over 10mA and the GPIO ports can tolerate 22mA.

Using the proposed scheme, the calculation of lux from the count is messy, it will involve logarithms, but Python should be able to handle that. I am all for putting the complexities into software where possible, much easier to change than getting out the soldering iron. The only hardware problem is to find the right capacitor for the LDR that gives sensible counts for the lux range of interest. That can be done by a breadboarding it before committing to the soldering iron.

1 Like

Hi Alan

Yes that is fine. I was more thinking of what the digital input looks like from the point of view from the capacitor. If it sits idle at a high impedance then that is OK. If it happens to sit high, low or anything else it will influence the capacitor charge. I am inclined to think it is high impedance but I don’t know is why I suggested a Mosfet switched by a GPIO.
Cheers Bob

1 Like

Hi Andrew Allan and Bob,

Neat project!

As to hopefully not create too much noise in the topic, I’d also check out this reflectance sensor: https://core-electronics.com.au/qtr-hd-25rc-reflectance-sensor-array-25-channel-4mm-pitch-rc-output.html

Before jumping into making up a circuit I’d be sure to get the rough idea figured out in a simulation (I like LTspice and Falstad)

And a multimeter on hand to check the current state of the system is paramount (I imagine a 0.1uF capacitor will discharge much too fast in most instances and wont be able to measure the transient - but sweeping with a potentiometer and polling the value should be able to get the actual TRUE/FALSE output from the GPIO).


1 Like

I looked at the specification of an RP2040 GPIO pin, leakage when configured as an input is less than 1µA, implying many MΩ. With the caveat that the pull up/down is disabled. I have relied on high impedance with the PIC processors and not been disappointed.

The only “tunable” component is the size of capacitor. The unknown is how long the Python loop takes to increase the counter by 1. Andrew165226 implies he already has this working so I don’t know a simulation would be much help. It is not too hard to work out that an 0.1µF capacitor charged to 2V from a 5V supply through a 1MΩ resistor takes about 50ms and through a 1KΩ resistor is about 50µs RC time constant / voltage calcultor. If the loop increases the counter every few µs then this should give usable results.

The problem is calibration. Although I stated earlier that two known light sources would be required to calculate the constant γ this is probably not true. Using one source at two distances would work just as well. The light intensity falls as the square of distance so measuring with the light 1 meter away and at 3.16 meter away (√10) will give a 10:1 difference in lux. There are hints online that the light meter in a camera can be used to get an approximate lux value by pointing at a light source (illuminated piece of white card) and noting the aperture setting, exposure time, and ISO value. But this may be way past what OP wants.


Hi All,

Interesting project!

@Andrew165226 I know it kind of defeats the purpose but could you use a digital lux sensor? They come factory calibrated and usually use I2C or some other protocol that makes connecting it to the Pi easy.

I think Andrew is going to be using the Pi Single board computer, the Pico/RP2040 would be muuuuuuuuch easier since it has an onboard ADC


Hi All
It would seem that basically Andrew wants to measure the value of an LDR and convert that value to Lumens.
The capacitor charge method seems popular but the means of doing it vary somewhat.

I have another idea to throw into the mix which is probably one of the simplest and gets rid of a few variables like GPIO trigger points etc.

Use a 555 timer in the triggered monostable mode as below.
Use the LDR as the timing resistor.
Trigger the 555 when a measurement is to be made, ie; just prior th an exposure.
Measure the time “T” of the output pulse.
Calculate the value of “R”.
This should return the value of the LDR at any one time. Then calculate the Lumen value and use it as intended.

Measuring pulse “T”…
I don’t know how a RPi does this but I have found Arduino quite good at it (the NanoEvery anyway) using the “pulseIn (pin, HIGH)” command and surprisingly accurate. Returns a value in microseconds.
I am playing with a project at the moment which entails the measurement of a pulse string. I need to display the period (µsec), frequency (Hz), pulse duration (µsec) and duty cycle (%). To do this I measure the duration of both the HIGH and LOW periods which the NanoEvery does quite well, then add them to get the total period (thus frequency). So far I have achieved very pleasing results comparing to my digital oscilloscope and 2 multimeters readings of frequency and duty cycle. That is all I have got to compare with but with results so close it has to be near the mark. Accurate enough for my intended purpose anyway.
Cheers Bob