Better LED As Light Sensor

56,644

415

43

Posted in TechnologyArduino

Introduction: Better LED As Light Sensor

About: I'm a social-worker, working with 12 - 23 year-olds. I used to be a printer. In 2018 I opened a small makerspace (www.imdib.nl) in my house, where I have lasercutters, 3d-printers, Arduino's, Mindstorms and ...
As a result of the questions from lekirst  on this ible of my hand: LED-as-lightsensor-on-the-arduino/ and the cleaner code made by hansc44 at:  Arduino-Use-LED-as-a-light-sensor/ it was time to come with a better Ible. So here it is. (I didn't solve lekirst's problems yet so she probably is open for suggestions)

What is the idea?

You might know that a LED emits light when you put the right amount of volts on the right leads. The funny thing is that it also works the other way around. Not the leads, it doesn't work when you put the leads the other way around. But what does work is that when you shine light on a LED it will GIVE current. It is a very small current but just enough for an Arduino to detect.

What will it do?

When you darken the sensor led, for instance by covering it with your hand, it will turn on the other LED.

Does this work with any LED?

As far as I know, it works with any LED, but not with any LED as good.
green and red LEDs seem to work best.
If trough experimenting you find out that other colors even work better, let me know.

Does it work with any light?

This sketch works very reliable with normal daylight. It is not fully tested in dark rooms or bright sunlight yet.

Step 1: You Will Need

You will need
  • an Arduino board (Uno, Duemilanove or something like that)
  • two LEDs
And really that's it! (you could even do it with just one LED and use the SMD-LED on the Arduino board as the second LED)

You will need no tools.

You do need a computer with the Arduino software installed and a USB-cable to connect the Arduino board. (But if you have an Arduino board, you probably have that sorted already)

Step 2: Setting Everything Up

To set this project up, you just need to put the two LED's in the Arduino.
  • Put the LED that you want to use as the sensor with the long lead (this is the anode and positive lead) in pin analog 3 in the Arduino. This could also be an other analog pin, but then you need to change this in the sketch later on.
    Put the other, short lead in the GND.
     
  • Put the other LED with the long lead in pin (digital) 13 in the Arduino. Put the short lead in the GND that is next to pin 13.

Now you just need to hook up the Arduino board with the computer and the fun can begin.

Step 3: Uploading the Sketch

//Copy the following sketch in your Arduino software and upload it to the Arduino board. (be sure to select the right board and com-port in the Arduino software)

int led = 13;                                        // the pin where you will put the LED
int sensorpin = A3;                           // the analog pin where you put your sensorLED
int resetteller = 0;                              // the rest are counters and variables to calculate with
int sens = 0;
int teller = 0;
int basis = 1024;
int test = 1024;
int test2 = 1024;
int test3 = 1024;

// this are the values to play with to get better (or worse) results
int marge = 5;                         // the space between a positive and negative reading
int vertraging = 1;                  // the speed of the readings; a lower number is a higher speed
int samples = 70;                   // the amount of samples to compare to make one reading
int resetsamples = 30;          // how many cycles to run the light on before you don't trust the value anymore

void setup() {
  pinMode(led, OUTPUT);
  Serial.begin(9600);                                   // no real part of the program, just for debugging
  for(teller =0; teller < samples; teller++) {// remember the lowest value out of many readings
   sens = analogRead(sensorpin);
   if (sens < basis){basis = sens;}
   delay(vertraging);                                     // the sensor needs a delay here to catch its breath
  }
}


void loop() {                                            
for(teller =0; teller < samples; teller++) {// remember the lowest value out of many readings
   sens = analogRead(sensorpin);
   delay(vertraging);                                   // the sensor needs a delay here to catch its breath
   if (sens < test){
   test3 = sens;                                            // remember the 3 lowest readings
   test2 = test3;
   test = test2;}
  }
  if (test < basis-marge && test2 < basis-marge && test3 < basis-marge){//all 3 low readings mus be < the basis reading
    digitalWrite(led, HIGH);
    resetteller++;                                         // count how long the LED stays on
  }
    else{
      digitalWrite(led, LOW);
      basis = test;                                         // if the lowest test reading is higher than the basis, basis will be reset
      resetteller = 0;
    }
    if (resetteller > resetsamples){basis = test;}//if LED stays on to long, we don't trust it and reset basis
    Serial.print(basis);Serial.print("  ");Serial.print(test);Serial.print("  ");Serial.println(sens);//just for debugging
    test = 1024;
}

Step 4: About the Sketch

What does it do?

When you darken the sensor led, for instance by covering it with your hand, it will turn on the other LED.

Why is this one better?

This sketch works much more reliable than the previous version.
This sketch has the serial monitor functionality.
All the tweaking is done in the top of the sketch with four variables.
I did put a lot more explanations in the sketch

Is this sketch perfect?

No, it is far from perfect, but is works great most of the time. Sometimes it doesn't work at all for no apparent reason. But when it works, it will keep on working for hours.
Besides that does it still not do what lekirst wants it to do: The LED sensor is also the emitting sensor that stays on as long as it is touched.
I'm sorry that I use Dutch names for the variables some of the time, but that is because Dutch isn't Dutch to me.

How to tweak

You can change the "marge". This will set how sensitive the sketch will be for light changes. A low value is a high sensitivity.

When you change the "vertraging" you can set the speed of the sensor. A low value is a high speed. My Arduino doesn't work when I set it al the way to 0, but with 1 it works most of the time. Somehow the Arduino needs a short rest in-between sensing.

With the "samples" you change the accuracy of the sketch. More samples is a higher accuracy, but with a higher value it will also react slower.

The last value you can tweak is the "resetsamples". This value sets how long the sketch will accept a low reading on the sensor (and turn on the LED) until it doesn't trust it anymore and reset the sensor back to zero.

What else?

Well if you want to put your emitting LED in an other pin, you should change the value of "led" to the number of the pin you want to use.
The same goes for the value of "sensorpin" if you want to use an other analog pin for your sensor LED.



You might notice that the LED turns off after a short time when I keep my hand over the sensor. This is because of the "resetsamples" value. When you increase this value, the LED will stay on longer. But when the sensor makes a mistake because of changing light or something, it also takes longer for the sketch to correct this.

Share

    Recommendations

    • Spotless Contest

      Spotless Contest
    • Microcontroller Contest

      Microcontroller Contest
    • Space Challenge

      Space Challenge
    user

    We have a be nice policy.
    Please be positive and constructive.

    Tips

    Questions

    43 Comments

    Use code below for real light sensing with LED.

    Connections: LED's cathode to GND pin, LED's anode to A0 pin (Anode is smaller part in LED)

    you can see result on pin13 arduino's built in led, also serial terminal

    Green or red classic 5mm LEDs gives best result

    --------------------------------------------------------------------------------------------

    // the setup routine runs once when you press reset:

    void setup() {

    // initialize serial communication at 9600 bits per second:

    pinMode(13, OUTPUT);

    Serial.begin(9600);

    }

    // the loop routine runs over and over again forever:

    void loop() {

    // read the input on analog pin 0:

    int sensorValue = analogRead(A0);

    Serial.println(sensorValue);

    if (sensorValue < 50) { digitalWrite(13, HIGH);}

    else if (sensorValue >= 50) { digitalWrite(13, LOW);}

    else { // digitalWrite(led, HIGH);

    delay(500);

    digitalWrite(13, LOW);}

    }

    This does not use the LED as a light sensor but rather an antenna. It picks up 50/60Hz noise from the grid. If you put your hand close to the LED without changing the incident light you will see the thing still "working". If you remove the LED and replace it with a small wire it will continue "working".

    2 replies

    Any elaboration on how it should be done?

    Search for an article (and a video) from Scott E. Hudson: "Using Light Emitting Diode Arrays as Touch-Sensitive Input and Output Devices". He reverse biases the LED and then waits for the LED capacitance to discharge. The discharge rate is correlated to the leakage current and thus is light dependent.

    I found your description on my search for building a "reactive light" for geocaching and I'm very happy since most examples I had were for ATTINY in BASCOM. (google for the german "Reaktivlicht"). But it seems there is a small error in your code (which doesn't make any problems but it will not work as intended according to your comments. Look here:

    if (sens < test){
    test3 = sens; // remember the 3 lowest readings
    test2 = test3;
    test = test2;}
    }

    if (test < basis-marge && test2 < basis-marge
    && test3 < basis-marge){//all 3 low readings mus be < the
    basis reading

    After

    test3 = sens; // remember the 3 lowest readings
    test2 = test3;
    test = test2;}

    test, test2 and test3 will have the same value (sens), therefore your if statement will just compare the lowest reading.

    So you could just use

    if (sens<test) test=sense;
    }
    if (test < basis-marge && test2 < basis-marge &&
    test3 < basis-marge){//all 3 low readings mus be < the basis
    reading
    ...

    instead.

    If you want to be less tolerant and require that all three lowest values stay below basis - merge you could use the following:

    for ....{ ...

    if(sens < test3) {

    if(sens < test2) {

    if(sens < test) { // sens is smaller than all three test values

    test3 = test2;

    test2 = test;

    test = sens;

    } else { // sens is smaller than test3 and test2 but not than test

    test3 = test2;

    test2 = sens;

    }

    } else { // sense is smaller than test3 but not smaller than test2 and test

    test3 = sens;

    }

    } // after this you have test < test2 < test3!

    }

    if (test3 < basis-marge){//all 3 low readings mus be < the basis
    reading

    digitalWrite(led, HIGH);

    resetteller++; // count how long the LED stays on

    }

    Since nobody complained so far this discussion may be purely academical. Somaybe you should just use the version from my comment to keep your code shorter.

    1 reply

    Hello Dirk,

    Yes I see what you mean. That's what happens when you are writing code at night :), but somehow it works very reliable for me. It looks like one reading might be enough.

    Thank you for looking into the code.

    What you made is some sort of antenna (in this case EM detector) on the A0 pin. Try to put your hand near the sensor LED but not between the LED and the light and you will see. BTW is true LED can act like light sensors but you will need an amplifier.

    To see that i'm right take off the LED and pass your hand over the Arduino A0 pin ;)

    And if you put a wire on this port the effect will be amplified.

    5 replies

    I know how to use the A0 port as an EM detector, but this is not it. You will see that it value changes with light changes and for my 4x4x4 interactive led-cube I used the same methode with shielded wires.

    Can you put the link to the video or put the video?
    Thank you.

    I will try again the circuit but i'm sure that it is the same problem. A0 allways give these values and reacts to small charge changes. Thank you btw.

    Can you put the link to the video or put the video?
    Thank you.

    That's strange? what is different? Other LED? longer leads?

    Great enhancment

    please keep going further

    can you tell me how can i make it sense more than one LED like putting 2 more sensing leds and operate the same ?

    thanks a lot

    5 replies

    You can use as many sensing led's as you have analog ports at your disposal. Just be sure to use shielded wire to connect them. If you don't use shielded wire the interference in the air might confuse the Arduino.

    Thanks for fast replay.

    What i mean is that the code will be different, i tried to add more LEDs and modify the code in the Arduino software but i cannot make it for 2 more led sensors please help me doing it for total of 3 leds and 3 digital output(each LED sensor has its own digital output).

    Thanks again

    Can you send me the code you wrote? So I can see what went wrong. You might use personal mail for that.

    kindly waiting for your email

    have a good day

    I can't find where you send the code.