Led as Input Photodiode

Go To Last Post
16 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I’m trying to use a LED as a light sensor(input) connected to a Arduino Nano.

I connected the led with the Anode at digital pin 8 (PB0) with a resistance of 56 Ohm and the Cathode at an analog pin A0 (PC0).

LedAsInput

The main idea is to measure the voltage across the parasite capacitance in the LED which was stored during a short 5V pulse(turning PC0 high and then low) in reverse bias.

First example is very simple.

 

    uint16_t sen_time = 0;    //Variable for counting

    void setup() {

      Serial.begin(9600);

      // Setting pin 8 to OUTPUT and the rest to INPUT

      DDRB |= (1 << PB0); // Setting OUTPUT PB0

      PORTB &=  ~(1 << PB0);   // Setting Anode LOW 

      

      TCCR1B |= (1 << CS10); // Setting timer, no prescaling(f = 16Mhz)

    }

    

    void loop() {

    /* Reverse bias pulse */

      DDRC |= (1 << PC0);     //Setting A0 to OUTPUT

      PORTC |= (1 << PC0);    //Setting A0 to HIGH

     /* Setting Threestate Cathode */ 

      DDRC &=  ~(1 << PC0);    //Setting A0 to INPUT

      PORTC &=  ~(1 << PC0);   //Setting A0 to LOW

    

      TCNT1 = 0;  // Setting timer the moment we turn off 

      //Waiting for the led to discharge and counting

      while (analogRead(A0) != 0)

      {

        sen_time++;

      }

      Serial.print("TCNT:");

      Serial.println(TCNT1);

      Serial.print("sen_time:");

      Serial.println(sen_time);    //Print the value

      sen_time = 0;                //Setting the value to 0

    }

 

The results are as follows.

In normal conditions:

normal_light_LED_data

In darkness:

darkness_LED_data

In heavy light:

heavy_light_LED_data

 

 

The variable which is incremented sen_time is pretty much accurate, having high values for darkness and low values for heavy light. But I can’t understand why my timer has trash values all way around.

 

I’m trying to solve it with interrupts(Pin change interrupts) but getting the pin three-stated just triggers the interrupt all way around. Plus the TCNT got trush values whenever I read it. Getting pull-up resistors just keeps the pin high.

Some advices about how to solve this problem preferably with interrupts (due to time restriction on future project). Thank you and I hope to solve it as soon as possible!  

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

hcalin wrote:
I’m trying to use a LED as a light sensor(input)

Why?

 

Wouldn't it be so much easier to just use a proper photodiode?

 

Or, these days, a digital light sensor?

 

But, if you must, there was a thread about this not so long ago ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hcalin wrote:
The main idea is to measure the voltage across the parasite capacitance in the LED which was stored during a short 5V pulse(turning PC0 high and then low) in reverse bias.

Have you actually looked at that voltage with an oscilloscope to see if you are actually getting anything meaningful to measure.

 

I don't have a Uno schematic to hand, but your setup doesn't look like it's going to work at all...

 

Can you draw a proper schematic showing how the LED is actually connected to the microcontroller pins ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

awneil wrote:
there was a thread about this not so long ago ...
Not just recently - I remember this being discussed a number of times over the years. I'm guessing "reverse bias" would be a useful search term to filter out among all the threads about AVRs an LEDs (and of course "light sensor").

 

Like Andy, apart from the fact that it's an interesting experiment, I do wonder why you'd want to do it when there are better ways for micros to detect light levels.

EDIT: actually ignoring "AVR" all together I just typed "reverse bias led snsor" into Google (yup, even spelled "sensor" wrong!) and top hit was: https://www.sparkfun.com/news/2161 which turns out to not only include AVR but Arudino in fact.

Last Edited: Fri. Aug 10, 2018 - 02:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What kind of light and over what range of intensity are you wanting to measure?  i.e. what is the purpose of your light sensor?

Answer these and you will get better answers.

 

Jim

 

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
top hit was: https://www.sparkfun.com/news/2161

some interesting stuff in the comments on that - dating references back to 2003 ...

 

As one contributor notes, all semiconductors emit "light", and are sensitive to it - it's just that most are not very good at it, and are packaged in ways to further minimise it.

 

Which reminds me of school days scraping the black paint off OC71 transistors to turn them into OCP71 prototransistors ...

 

I also made a "solar panel" out of a load of surplus diodes by scraping the black paint off their glass encpsulations ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
Which reminds me of school days scraping the black paint off OC71 transistors to turn them into OCP71 prototransistors ...
been there, done that, worn that T-shirt :-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is some general background info (not processor related)

https://userpages.umbc.edu/~martins/PHYS650/02860Mims.pdf

When in the dark remember-the future looks brighter than ever.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I’m thinking a better solution would be to use the comparator and input capture features.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's very suspicious that the values of TCNT1 are all in a 8 bit number range (0-255). It seems the high byte is being ignored, thus the values seem random.

The value of TCNT1 should be larger than sen_time, since the timer is running at max speed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Like Clawson mentiones, this has been discussed before on AVRfreak.

As a hobby it could be fun to play with this, but beyond that it has no application, because those properties of LED's are neither optimized / designed in / tested in LED's.

Results may vary a lot on the led used.

Some of the led's generate a voltate of > 1V when shone on with a bright light, measured with a regular DMM (Probably 10MOhm or 11MOhm input impedance).

Other leds from the parts pile do not generate a voltage at all.

Start experimenting with a lead that has a noticable difference you can measure with a DMM.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the replies.

 

El Tangas wrote:

It's very suspicious that the values of TCNT1 are all in a 8 bit number range (0-255). It seems the high byte is being ignored, thus the values seem random.

The value of TCNT1 should be larger than sen_time, since the timer is running at max speed.

 

Hi. That is one of my questions. I can't understand why this happens.

 

awneil wrote:

Why?

 

Wouldn't it be so much easier to just use a proper photodiode?

Yes, of course it would be. I am in the training process at some multinational in my first month. One of the training projects is to transmit bytes of data using just 2 LEDs. 

Another one would be to make a 'touch pad' using the same principle using a 8x8 led matrix, turning ON the LEDs besides your fingers on they touch the screen. 

awneil wrote:

Have you actually looked at that voltage with an oscilloscope to see if you are actually getting anything meaningful to measure.

 

I don't have a Uno schematic to hand, but your setup doesn't look like it's going to work at all...

 

Can you draw a proper schematic showing how the LED is actually connected to the microcontroller pins ?

Yes, it is exactly like this, varying according to the light on the diode.

 LED discharge

 

Hi awneil. As I said in my post the Anode is connected to PB0 and the Cathode is connected to PC0. The microcontroller is ATmega328p.

Why do you say it wouldn't work at all? I mean it works with a variable. :D (but not with interrupts)

 

clawson wrote:

Not just recently - I remember this being discussed a number of times over the years. I'm guessing "reverse bias" would be a useful search term to filter out among all the threads about AVRs an LEDs (and of course "light sensor").

 

Like Andy, apart from the fact that it's an interesting experiment, I do wonder why you'd want to do it when there are better ways for micros to detect light levels.

EDIT: actually ignoring "AVR" all together I just typed "reverse bias led snsor" into Google (yup, even spelled "sensor" wrong!) and top hit was: https://www.sparkfun.com/news/2161 which turns out to not only include AVR but Arudino in fact.

 

Hi clawson.I've made some research before posting so I understand how this is supposed to work. The signal is exactly like that one. I can't understand why the timer has trash values when printed. 

But of course, I'll search more, thanks for the answer:).

 

ki0bk wrote:

What kind of light and over what range of intensity are you wanting to measure?  i.e. what is the purpose of your light sensor?

Answer these and you will get better answers.

 

Jim

 

Hi ki0bk, I've shown the purpose at the start of this post. There are 2 blue LEDs doing the transmission(half duplex). Mainly to detect a spark of light and the absence of that spark.

 

Kartman wrote:
I’m thinking a better solution would be to use the comparator and input capture features.

This could be a nice idea. I'll check into it. Thanks :)

Last Edited: Sun. Aug 12, 2018 - 11:35 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hcalin wrote:

El Tangas wrote:

It's very suspicious that the values of TCNT1 are all in a 8 bit number range (0-255). (...)

 

Hi. That is one of my questions. I can't understand why this happens.

 

Try to print only the high byte, TCNT1H, maybe it will give more sensible values.

 

edit: just remembered this detail: https://www.avrfreaks.net/forum/...

So try this: do a dummy read of TCNT1L to some temporary variable, then print TCNT1H.

Last Edited: Sun. Aug 12, 2018 - 01:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas wrote:

Try to print only the high byte, TCNT1H, maybe it will give more sensible values.

 

edit: just remembered this detail: https://www.avrfreaks.net/forum/...

So try this: do a dummy read of TCNT1L to some temporary variable, then print TCNT1H.

 

Still there are trush values on the timer.

Last Edited: Mon. Aug 13, 2018 - 08:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hcalin wrote:
I am in the training process at some multinational in my first month.

So why are you not discussing this with your teachers / supervisors / mentors ?

 

They know exactly what you have been given to do - we don't.

 

They can see exactly what you have, and how you have set it up - we can't

 

They can see exactly what you are doing, and exactly what is happening - we can't

 

They can interact directly with you in real time without having to type everything out, post it, and wait for replies - we can't

 

 

I said in my post the Anode is connected to PB0 and the Cathode is connected to PC0. The microcontroller is ATmega328p.

It is never great trying to describe circuit details in words.

 

This is exactly why we have circuit diagrams - aka, "schematics" - it is a far clearer and more effective way to describe stuff like this.

 

So, as requested, please provide a proper schematic showing how this actually connects to the actual microcontroller pins.

 

Why do you say it wouldn't work at all?

I think that would become clear from seeing a proper schematic...

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

hcalin wrote:
Still there are trush values on the timer.
But Timer 1 (and timer 0) are used by the Arduino framework itself?!?

 

Timer 0 is used for core timing functions like "millis" and

 

Timer 1 is for analogWrite() (so it's doing PWM to generate a varying voltage on output pins).

 

If you are willing to forgo the use of analogWrite() you can "take over" the use of timer 1 but you cannot do it by simply using:

      TCCR1B |= (1 << CS10); // Setting timer, no prescaling(f = 16Mhz)

You have mistakenly used |= which means you are just adding a bit into the existing settings. You also don't touch TCCR1A.

 

This is what Arduino already does with Timer 1:

	// timers 1 and 2 are used for phase-correct hardware pwm
	// this is better for motors as it ensures an even waveform
	// note, however, that fast pwm mode can achieve a frequency of up
	// 8 MHz (with a 16 MHz clock) at 50% duty cycle

#if defined(TCCR1B) && defined(CS11) && defined(CS10)
	TCCR1B = 0;

	// set timer 1 prescale factor to 64
	sbi(TCCR1B, CS11);
#if F_CPU >= 8000000L
	sbi(TCCR1B, CS10);
#endif
#elif defined(TCCR1) && defined(CS11) && defined(CS10)
	sbi(TCCR1, CS11);
#if F_CPU >= 8000000L
	sbi(TCCR1, CS10);
#endif
#endif
	// put timer 1 in 8-bit phase correct pwm mode
#if defined(TCCR1A) && defined(WGM10)
	sbi(TCCR1A, WGM10);
#endif

So in TCCR1B the CS11 bit is already set and because F_CPU is very likely 16MHz bit CS10 is also set. In TCCR1A bit WGM10 is set.

 

So your line:

      TCCR1B |= (1 << CS10); // Setting timer, no prescaling(f = 16Mhz)

does nothing (because that bit is already set before setup() is called) but the comment is wrong. You think you are setting "no prescaling" so that the timer runs a /1 (16MHz) but, because of the bits already set, it's running at /64 (250kHz).

 

Also because of the WGM10 bit being set in TCCR1A it is running in 9 bit Phase correct PWm mode:

 

 

As you can see here this means the timer only counts 0 to 0x1FF so the count will never exceed 511.

 

What I suggest is:

    void setup() {
      Serial.begin(9600);

      // Setting pin 8 to OUTPUT and the rest to INPUT
      DDRB |= (1 << PB0); // Setting OUTPUT PB0
      PORTB &=  ~(1 << PB0);   // Setting Anode LOW 

        // take COMPLETE control of timer 1
      TCCR1A = 0; // no WGM selection (mode 0 = "normal")
      TCCR1B = (1 << CS10); // Setting timer, no prescaling(f = 16Mhz)
      TCCR1C = 0; // may have been default anyway - but be safe!
    }

There is a VERY important lesson to learn here. Do not be so keen to use |= and &=~ to set/reset bits. The first write to an SFR in a program should almost always be a simple assignment with =.

 

Also do not assume you know the values in the SFRs without first checking. Some people (I'm one) think it's perhaps "overkill" to deliberately set all SFRs back to their supposedly known power on default values at the start (though there's an argument to say that if you have the flash space and time it does no harm and it catches those cases when code finds its way back to 0x0000 in an unintended way). But if there's any other software in the system that you personally did not write (which may just mean the CRT of the C compiler or, in Arduino's case, a whole bunch of stuff before setup()) then familiarize yourself with what it does and how it might affect what you plan to do.