Using LEDs as photodiodes (light sensors):


LEDs are commonly used as lights, but then can also be used as photodiodes to detect light. Normally, LEDs are turned on by driving current from the anode ((+) side, indicated by a longer leg) to the cathode ((-) side, indicated by a shorter leg) [see the crude text-based schematic in the comments of the code below]. This is known as "forward biasing" the LED. However, photodiodes are designed to operate in "reverse bias". In reverse bias, LEDs (or photodiodes) can be used to sense light in two ways: 1) photovoltaic mode, where the photodiode generates a tiny voltage (like a solar cell) proportional to the incident light, and 2) photoconductive mode, where the diode turns "on" and allows more current flow to be driven through it, proportional to the incident light. In photovoltaic mode, a positive voltage is generated on the LED's anode [again, see schematic below], with the potential to drive a current into the cathode and *out* of the anode. In photoconductive mode, you place a positive voltage on the LED's cathode (ie: the LED is reverse-biased, and will not emit light this way) from a voltage source. The more incident light that strikes the LED, the more it turns "on" as a photodiode, allowing current flow into the cathode and out of the anode.


This example circuit uses a single LED as a photodiode in *photoconductive* mode to sample the ambient light level and then glow at an appropriate brightness. It is tragically flawed by a slow refresh rate in the dark, but nonetheless it shows how to sense light.

// This example shows one way of using an LED as a light sensor.
// You will need to wire up your components as such:
//           + digital2
//           |
//           <
//           > 100 ohm resistor
//           <
//           |
//           |  LED Cathode (LED_N_SIDE, normally (-))
//           |
//         -----
//          / \  LED, maybe a 5mm, clear plastic is good
//         -----
//           |
//           |  LED Anode (LED_P_SIDE, normally (+))
//           |
//           + digital3
// What we are going to do is apply a positive voltage at digital2 and
// connect digital3 to GND. This is backwards for the LED, current will
// not flow and light will not come out, but we will charge up the 
// capacitance of the LED junction and the Arduino pin.
// Then we are going to disconnect the output HIGH drivers from 
// digital2 (making it now a high-impedance INPUT) and count how
// long it takes the stored charge at digital2 to bleed off through 
// the LED to GND at digital3. The brighter the light, the faster it will 
// bleed away to digital3 (GND), thereby causing the INPUT reading
// at digital2 to change from HIGH to LOW.
// Then just to be perverse we will display the brightness back on the 
// same LED by turning it on for a millisecond. This happens more often
// with brighter lighting, so the LED is dim in a dim room and brighter 
// in a bright room. Quite nice.
// (Though a nice idea, this implementation is flawed because the refresh
// rate gets too long in the dark and it flickers disturbingly.)
#define LED_N_SIDE 2
#define LED_P_SIDE 3

void setup()

void loop()
  unsigned int j;

  // Apply reverse voltage, charge up the pin and led capacitance
  pinMode(LED_N_SIDE, OUTPUT);
  pinMode(LED_P_SIDE, OUTPUT);
  digitalWrite(LED_N_SIDE, HIGH);
  digitalWrite(LED_P_SIDE, LOW);

  // Isolate the pin 2 end of the diode by changing it from OUTPUT HIGH to 
  // INPUT LOW (high impedance input with internal pull-up resistor off)
  pinMode(LED_N_SIDE, INPUT);
  digitalWrite(LED_N_SIDE,LOW);  // turn off internal pull-up resistor

  // Count how long it takes the diode to bleed back down to a logic 0 at pin 2
  for ( j = 0; j < 30000; j++) {
    if ( digitalRead(LED_N_SIDE)==0) break;
  // You could use 'j' for something useful, but here we are just using the
  // delay of the counting.  In the dark it counts higher and takes longer, 
  // increasing the portion of the loop where the LED is off compared to 
  // the 1000 microseconds where we turn it on.

  // Turn the light on for 1000 microseconds
  digitalWrite(LED_P_SIDE, HIGH);
  digitalWrite(LED_N_SIDE, LOW);
  pinMode(LED_P_SIDE, OUTPUT);
  pinMode(LED_N_SIDE, OUTPUT);
  // we could turn it off, but we know that is about to happen at the loop() start

Additional reading, circuits & references:

"Background" & "Additional reading, circuits & references" sections & information added by Gabriel Staples ( on 15 Jan 2017.