This version also supports a piezo speaker and “bendable” LEDs, thus combining all 3 Le Dominoux features into one.
The LEDs are bi-directional, meaning either one is an input as well as an output. The PIC samples each LED until it detects a small voltage change on one of them, then uses the other LED as a light output. In this experiment it’ll play a tune if the blink signal is lost.
These high-efficiency LEDs can generate over 1V when exposed to bright light. However, when connected to the PIC’s high-impedance ADC the LED may continue to hold its charge long after its exposure, thus making “off” measurements difficult, and causing the PIC to lose the blink signal. To ameliorate this the LED input is briefly switched to an logic input driven low, thus discharging any remaining voltage. This is done in the code (below) whenever a blink signal is lost. This fairly simplistic method works ok in the PIC basic environment. The PICAXE manual recommends grounding unused inputs — I found that by touching an unused ADC input I caused spurious readings on the other ADC inputs; the unused ADC is now grounded.
Update: most (if not all) bi-directional LED designs use 2 GPIO’s for each LED, and a “Reverse Bias and Discharge measurement” technique. This design uses only 1 GPIO per LED. I suspect the PIC’s ADC circuitry helps out but I’m no expert here.
PIC BASIC program:
;Demonstrates using a LED as a light sensor and emitter ; automatically selects a blinking input ; input on 1 or 4, output on 4 or 1 ; R. Elwin, 3/2011 symbol old1 = b1 symbol inpin = b2 symbol outpin = b5 symbol inaction = w6 symbol thresh = 8 ;ADC input drop indicates end of blink symbol ontime = 285 ;in ms symbol timeout = 500 ;in ms*3, when to look at inputs again b3 = 0 gosub pinselect ;stays here upon bootup until blinking detected inaction = 0 main: gosub readled if b6 = 1 then ; input off, output goes on high outpin pause ontime low outpin inaction = 0 endif pause 1 ;short delay between samples old1 = b0 ; check if nothing blinking inaction = inaction + 1 if inaction > timeout then inaction = 0 sertxd ("timeout",13,10) b3 = 1 ; play a tune gosub pinselect endif goto main ; figure out which pins to use ; when swapping try to 'drain' LED's charge by setting output low pinselect: low 1 low 4 if b3 = 1 then tune 0, 9,($09,$0B,$07,$27,$82) ;close encounter else pause 2 ;don't play tune, just pause endif input 1 input 4 pinselect2: if inpin = 4 then ; check other input inpin = 1 outpin = 4 else inpin = 4 outpin = 1 endif readadc inpin,old1 for b4 = 1 to 10 ; sample an input a few times for change gosub readled if b6 = 1 then return endif pause 1 ;short delay between samples old1 = b0 next b4 sertxd ("sampling=",#inpin,13,10) sertxd (" data=",#b0,13,10) goto pinselect2 ; read LED on ADC, returns b6=1 if dropped below threshhold, b0=input sample readled: b6 = 0 readadc inpin,b0 if old1 > b0 then b3 = old1 - b0 if b3 > thresh then b6 = 1 endif endifreturn