I have this idea but I do not know if it makes sense. The idea is to use a red transparent LED connected to an input of a microcontroller. In parallel it is also connected to an output of the same microcontroller.

What I would like to do is detect when a red laser hits the LED. My hope is that the light hitting the LED produces a small voltage that can be detected on the microcontroller. When this is detected, the output turns the LED on for one second. (Obviously while the LED is on, the input is ignored.)

Can this be done?

  • 2
    \$\begingroup\$ Why don't you try it? Get a red led and a red laser pointer and see whether you can measure a voltage when the laser hits it. If I have one about I might try it later today \$\endgroup\$ Apr 16, 2021 at 10:49
  • \$\begingroup\$ " in parallel it is also connected to a Output of the same microcontroller." You have to disconnect the output while sensing. Otherwise it will drive away the weak photovoltage signal. \$\endgroup\$
    – tobalt
    Apr 16, 2021 at 11:31
  • 2
    \$\begingroup\$ You only need one pin. Configure it as an analog input for sensing, then convert it to a GPIO output for driving the LED. It may be easier to detect the laser if you can arrange for the laser to pulse at a specific frequency. Then you will be detecting that frequency only, and this may allow you to reject ambient light better. Although ambient light pulses also. You just have to pulse the laser at a different frequency. \$\endgroup\$
    – user57037
    Apr 16, 2021 at 19:21

3 Answers 3


Ordinary LEDs can also be used to detect incident light, because they work as photodiodes too.

You will need to amplify the incoming signal.

Take a look at this projects (Jeff Han is the first one that used LEDs as sensors):



Or google "LEDs as sensors"

Source: https://hackaday.com/2015/10/13/citizenscience/

An LED as a light sensor

When light arrives, the LED acts like a current source that the virtual ground (inverting input pin) injects into resistor R1.

R1 is big because the signal is low.

That operational amplifier might need also a negative voltage supply because the output voltage becomes negative when current arrives.

See the next picture for a circuit that doesn't need a negative voltage supply.

Design by Texas Instruments: https://www.ti.com/tool/TIPD176

A photo diode as a light sensor

The noninverting input is slightly pulled up in order to avoid a negative voltage supply.

About 10 years ago, I saw a schematics showing an operational amplifier that was used to amplify the low-level signal coming from the LED.

It was designed by Jeff Han I guess.

It should still be around.

  • 2
    \$\begingroup\$ Photodiodes are optimized for light detection where LEDs are optimized for light production but they are effectively the same device. \$\endgroup\$
    – jwh20
    Apr 16, 2021 at 11:08

Yes, certainly is possible.

For further info, I suggest finding a copy of a MERL reseach report by Dietz et al from 2003 how they did it.

It does not in fact produce enough voltage to detect it with the MCU directly. It usually is done in a way that enables the generated photocurrent to discharge the parasitic junction capacitance of the LED which is first charged in reverse bias by the MCU, and so the MCU can monitor the IO pin how long it takes the voltage to decay until there is a change seen on the MCU logic level.


Justme's answer is very possible. Expanded here.
I have used photodiodes directly connected to a GPIO pin, along with a small-value capacitor to detect light. A LED should work as detector too.
The GPIO digital pins must be able to switch from input to output - most are versatile-enough to do this. It may help if the GPIO pins can generate an interrupt-on-change, but polling can be done too. If possible, GPIO2 should have a Schmitt-style input characteristic, although I have used a straight CMOS input-style successfully too. A microcontroller timer is useful too, to measure the time to charge the capacitor.


simulate this circuit – Schematic created using CircuitLab

Using a red laser as a light source should make detection easy, since it is so intense: much more intense than ambient light (unless your LED is looking directly at the sun).

When you want the LED to emit light:

  • RA5 becomes an output, logic low.
  • RA4 becomes an output, logic high. R1 limits LED current.

When you want the LED to detect laser light:

  • RA5 is an output, logic high.
  • RA4 is an output, logic low, so that C1 discharges down to Vss (GND)...LED will be un-lit....
  • RA4 then switches to input, and a timer is started simultaneously.
  • At this point photocurrents detected in LED charge C1 toward Vdd.
  • RA4 is monitored until it switches to logic high. Then timer is stopped.
    The timer gives an indication of detected light. Its count value is small when the LED sees a bright light. Its count value is high when the LED sees a dim light.

A smaller capacitor at C1 can detect quite low light levels (candle flame). A 27 pf capacitor for C1 works fine. At 330 pf, the LED could still detect a candle flame 30 cm away (a 5mm dia. LED with lens). For bright environments, a capacitor 1 nf or more might be appropriate. A GREEN LED worked too. The 24-bit counter in the software below can make a measurement up to 4 seconds before overflow.
I have measured leakage currents on GPIO input pins to be far below spec-sheet values in many Microchip's PIC microcontrollers - below 1nA.

Edit: This project interested me enough to code it up, build and try out on a breadboard. At room temperature, dark current of LED and leakage current of microcontroller input pin RA4 were impressively low. LED photocurrents of a fraction of a nanoamp could be detected reliably.
As a light detector, the RED LED could charge up the 330pf capacitor to the +2v threshold in a few seconds in a rather dim indoor room. A white sheet of paper reflecting window-light to the LED increased count rate enough to light up the LED.

;RED LED light detector. When excited with light, the reverse-biased LED is used
;as a current source to charge a capacitor.
;Ambient light on RED LED charges the capacitor slowly. A counter uses
;internal clock to measure charge time, which is proportional to current.
; RA4 (pin 3) on LED anode. Add a current-limiting series resistor!
; RA5 (pin 2) is used as digital output to drive LED cathode
; MCLR (pin 4) is used as MCLR (master reset)
; RA0, RA1, RA2 go high at end of charge period for 32us, then tristate
;TTL logic levels are used on I/O pins rather than schmitt thresholds high=2V
;April 2021 glen_geek
#include <xc.inc>
#define skpnc btfsc STATUS,0    ;why doesn't pic-as accommodate these macros?
#define skpc btfss STATUS,0 ;why doesn't pic-as accommodate these macros?
#define clrc bcf STATUS,0   ;why doesn't pic-as accommodate these macros?
#define skpnz btfsc STATUS,2    ;why doesn't pic-as accommodate these macros?
#define skpz btfss STATUS,2 ;why doesn't pic-as accommodate these macros?
PSECT udata_shr,class=COMMON    ;precious RAM addressable from every RAM page
;    ORG 0x70
ambient: DS 3       ;measured ambient light level detected by LED
current: DS 3       ;current light level detected by LED
cnt:    DS 3        ;a general-purpose counter (or local variable).

GLOBAL ambient
PSECT resetVec, class=CODE, delta=2 ;linker should map this to address 0000h
resetVec:       ;reset vector, watchdog vector, MCLR vector
    pagesel startup
    clrf ambient+0
    clrf ambient+1   ;start off ambient at zero
    bra startup     ;configure peripherals

;24-bit cnt contains a mesurement of light level. If cnt > ambient then
;the measurement was darker than threshold - so LED should remain off.
;If cnt < ambient, LED has seen a higher light level. So turn it ON for
;about a second. Then continue with repeated measurements.
    movf ambient+2,w
    subwf cnt+2,w   ;compare most-sig (cnt-ambient)
    return      ;comparison complete, status flags show result
    movf ambient+1,w
    subwf cnt+1,w
    return      ;comparison complete, status flags show result
    movf ambient+0,w
    subwf cnt+1,w
    return      ;comparison complete, status flags show result

delayarc:       ;delay up to 193 us. W has delay value
    clrf cnt+1      ;ensure 24-bit cnt ends up "0"
    clrf cnt+2
delay:          ;accept a delay count in W, delay by current instruction-
    movwf cnt+0     ;rate / 3. (loop time is 3 instructions). This is
    decfsz cnt+0,f    ;a blocking-type subroutine
    bra $-1

lightup:        ;turn on LED for about 1 second.
    banksel LATA
    movlw 0x17      ;preset anode HI, cathode LOW to turn LED ON.
    movwf LATA
    banksel TRISA   ;both pin3 & pin4 OUTPUT (RA0, RA1, RA2 as well).
    clrf TRISA      ;at this point LED turns ON.
    movlw 21
    movwf cnt+1
    clrw        ;maximum delay (193 us)
    call delay
    decfsz cnt+2,f  ;maximum delay
    bra luil
    decfsz cnt+1,f
    bra luil        ;falling thru, LED goes off, capacitor discharges:
discharge:      ;discharge capacitor, LED anode off at 0V
    banksel LATA
    movlw 0x27      ;preset anode LOW, cathode HIGH. LED reverse-biased. RA0 hi.
    movwf LATA

    movlw 0x00      ;make both (pin3) & (pin4) OUTPUTS, RA0, RA1, RA2 as well.
    banksel TRISA
    movwf TRISA     ;here's the cap discharge, LED anode to GND(Vss).on RA4
    movlw 40        ;wait a bit to ensure capacitor is discharged to 0V
    call delayarc   ;with 16MHz INTRC clock, this delay takes about 32 us.
    movlw 0x17      ;switch RA4 to INPUT, so capacitor can charge up
    movwf TRISA     ;note that RA4 input has TTL threshold. RA0 floats (low).

    banksel PORTA   ;monitor LED anode voltage until it goes HIGH.
    clrf TMR0       ;reset TMR0 to 0.
    bcf INTCON,2    ;ensure TMR0 overflow flag is reset too.
    btfsc PORTA,4   ;when capacitor is charged, save the count.
    bra savecnt
    btfss INTCON,2  ;has TMR0 interrupt flag set?
    bra cntlp
    bcf INTCON,2    ;yes, reset it, then increment high-order 16 bit counter.
    incf cnt+1,f
    bra cntlp
    incf cnt+2,f
    bra cntlp
savecnt:        ;capacitor has charged up to TTL threshold
    movf TMR0,w     ;get lowest 8-bits of count
    movwf cnt+0
    return      ;24-bit unsigned count (little-endian) saved in cnt.

startup:        ;configure FOSC to 16 MHz internal RC osc (good 'nuf)
    banksel OSCCON
    movlw 0x78
    movwf OSCCON    ;speed up to 16 MHz Fosc (4 MIPS)
    banksel WPUA
    clrf WPUA       ;turn off weak pull-ups pedantic(OPTION_REG default is OFF)
    banksel ANSELA
    clrf ANSELA     ;force all I/O to be digital, not analog

    banksel OPTION_REG  ;configure 8-bit TMR0. Clk_source is FOSC/4 (4MHz)
    movlw 0xD8      ;prescaler not used (1:1) 3 prescaler rate bits unused.
    movwf OPTION_REG    ;TMR0 starts counting
    bcf INTCON,2    ;ensure TMR0 overflow flag reset. GIE remains off.

    call lightup    ;turn on LED (alive indicator), then make a measurement
    movf cnt+0,w    ;of ambient light level (24-bit). Save it into "ambient"
    movwf ambient+0
    movf cnt+1,w
    movwf ambient+1
    movf cnt+2,w
    movwf ambient+2

    asrf cnt+2,f    ;divide cnt by 8 (shift right 3 times)
    rrf cnt+1,f
    rrf cnt+0,f
    asrf cnt+2,f
    rrf cnt+1,f
    rrf cnt+0,f
    asrf cnt+2,f
    rrf cnt+1,f
    rrf cnt+0,f

    movf cnt+0,w    ;reduce ambient 0.875. This becomes threshold.
    subwf ambient+0,f   ;a new measurement will be compared against this
    movf cnt+1,w    ;threshold. If the count is LOWER, then LED has
    subwfb ambient+1,f  ;seen a brighter light than ambient. So we'd light up.
    movf cnt+2,w
    subwfb ambient+2,f

    call discharge  ;ensure LED is off, discharge capacitor, start counting.
    call threshold  ;do threshold comparison (cnt - threshold)
    skpc        ;decide if cnt < threshold
    call lightup    ;yes: light LED for about a second...
    bra mainloop    ; no: don't light LED, repeat measurment.
    END resetVec
  • \$\begingroup\$ What intensity of light does this require to give a detectable signal (for the microcontroller)? \$\endgroup\$ Apr 17, 2021 at 5:31
  • \$\begingroup\$ @PeterMortensen To detect candle-flame using a phototransistor instead of photodiode, and a small-value capacitor (hazily recall tens of picofarads), counter values differed markedly from darkness. Was using a standard CMOS logic input to detect logic 0/1 threshold (not a Schmitt input gate). I'd expect a LED diode detector to supply 100x less photocurrent. It is nice that count values become large at low light levels, so that tiny changes can be sensed. \$\endgroup\$
    – glen_geek
    Apr 17, 2021 at 15:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.