LED Sensing

A little used technique is to use an LED as both a light emitter and a light detector. One marvels, not that it is done well, but that it is done at all.


A little used technique is to use an LED as both a light emitter and a light detector. Just like a dog walking on its hind legs one marvels, not that it is done well, but that it is done at all.


It is a little known fact that an LED can be used not only to generate light but also to sense it. However, from a solid state physics point of view a diode is simply a PN junction, so a rectifier diode, light emitting diode and photo diode basically are all the same thing.

A semiconductor can be doped or mixed with two types of impurity that result in material that conducts electricity in two different ways. One is with an excess of electrons is called N type and the other with a shortage of electrons is called P type. This is because a shortage of electrons can behave, as far as electricity conduction is concerned, just like an excess of positive charges. These positive charges are called holes in recognition of what they are, the absence of an electron. So electricity can be conducted by the flow of holes in P type material or electrons in N type.

So when a P and N type material come together to form a junction some of the holes in the P type materiel move into the N type material where the combine and cancel each other out. Similarly some electrons at the junction move into the P type material and cancel each other out. So around the junction an area of materials builds up that has neither electrons or holes and so will not conduct electricity at all. This is known as in intrinsic region or I type. This seals off the path for the migration of any more holes and electrons and the I region stabilises.

To get electricity to flow you have to apply an external voltage  that adds more electrons to the N side and more holes to the P side. This builds up a potential that is big enough to break through this intrinsic layer. However, if you put a smaller voltage across it you just put an extra charge or electrostatic pulling power across the I layer. Now if a photon (small bundle of electromagnetic energy or light particle) wanders into this I layer it might interact with one of the atoms and give up it’s energy into the atom’s electron. This not only frees up an electron for conduction it also leaves a hole behind where the electron was, we say we have generated an electron hole pair. These would normal recombine but the electric field across the region pulls them apart causing a tiny current to flow. The more photons (light) the more the current adds up and so you have a current that is proportional to the light falling on the diode, this is called a photo current.


So let’s see how we can make use of this effect. The photo current is very small in an LED because the geometry of the junction is not designed to maximise it like it is in a photo diode. What we need to do is to find a way to integrate (a posh way of saying add up) all the little photo currents over a set time. To do this we use a trick, we make the diode look like a capacitor, those conducing regions separated by an insulator look like a capacitor. So we charge it up and then time how long it takes the photo current to discharge it, just like this:-

This involves a bit of electronic gymnastics with the ends of the LED, but as the Arduino has configurable pins this is easily done in software. The other trick is instead of waiting for the capacitor to discharge enough to give a logic zero, which can be a long time, simply measure the voltage across it, after you have given it a short time to discharge. I call this the integration time because it is integrating (adding up) all the small photon currents.

The LED is not an ideal device, that is, not all of the discharge is caused by photons, other causes include thermal noise and leakage. So given enough time the charge will decay without any light. Finally, as LEDs are not designed as light sensors, the light sensing ability varies from LED to LED. There are some types that are better than others. Red LEDs are the best as they will be sensitive to all colours of light where as blue LEDs will be sensitive to only blue light. Worst of all are white LEDs some types will only respond to UV light. The junction size is important so the smaller an LED is the more sensitive it will be as the capacitance is smaller and it takes less photons to discharge it. Finally a clear package will let more light in than a coloured one. If you want to use LED light sensors as touch sensors then surface mount LEDs are probably best.


Wire up the LED so that the anode is connected to a digital pin and the cathode is connected to a an analogue input pin. Don’t forget a current limiting resistor in each LED. So, that’s simple enough.


I used a piece of strip board to span the Arduino and soldered surface mount LEDs to it:-

Of course, the tracks on the strip board are broken underneath the LEDs, using a sharp knife.

This is another one I made using clear LEDs.


First of all in the setup() you must globally disable the internal pull up resistors with:-

    _SFR_IO8(0x35) |= 0x10;   // global disable pull up resistors

If you don’t do this, then it won’t work at all.

Steps to take:-

  1. 1)Light up the LED by making the anode positive (logic one) and the cathode negative (logic zero) - this fully discharges the LED as a capacitor.

  2. 2)Charge up the capacitor by making the anode negative and the cathode positive, as this is a small capacitor it will take no time at all in other words for as short a time as you can.

  3. 3)Put the diode into the measurement mode, by making the anode negative (it already is) and the cathode connected to an analogue input.

  4. 4)Make a measurement of the analogue voltage, this is a reference level to be used later.

  5. 5)Wait while the photon current is integrated - the longer the more sensitive but too long and effects other than photo current dominate.

  6. 6) Measure the voltage again and subtract it from the reference value you took before the integration time. This figure is your light reading.

You can apply this to just one LED or, as in the circuit above, to many. However, I have found that when you apply it to many LEDs they can interact. That is cover up one and the readings from the others do down a bit. This interaction comes about because of the multiplexer inside the Arduino that switches the separate inputs to the one analogue to digital converter (A/D). Basically there is charge left in the system from the measurement of the previous  sensor messing up the next reading. Therefore there are a few other tricks in the code to minimise the interaction like juggling about with the order in which they are scanned and discharging the A/D input after the reading has been made. The sketch for the Arduino can be downloaded here Sensor_LEDs.pde.

It can be difficult to see any effect of changing light level from the numbers so I wrote a small routine in Processing to display the results in a graphical way. The code for this is here LED_Sensor.pde.

Finally I made a system where the LED would change between bright or dim depending if it was covered or not. Not it is not just a matter of setting it bright if covered, you have to hold that state until it is covered again before turning it on to dim. This nearly worked reliably, but was sometimes hit and miss. However, it proved very difficult to video due to the brightness of the LEDs and their flashing nature. The results are better than is shown in the video. If you want to get the code then down load it here Sensor_Feedback.pde.


This work shows it is possible to use an LED as a light sensor. However, I wouldn't incorporate this into a final project as I feel it is not a solid, reliable, technique. It can work well in daylight but under artificial lighting things can get tricky. The code give here offer the experimenter an basis for further work.

Further work

I did try to expand this into using a 5x7 matrix LED but could not get a light response to a single LED, only columns or rows. That is covering up a whole columns showed light sensitivity likewise covering up a whole row also worked, however covering a single LED showed no effect. I don’t know if this was something to do with the type of LED matrix having light leaking between the spots or if it was the fact they were directly driven off the Arduino pins with no drivers and so had to have high series resistors.


LED Sensing