LED Touch Sensor
http://web.ndak.net/jdgrotte/touchsensor/MVI_0120.AVI
Has anybody ever done this? Used an LED to sense light, basically
use it as a touch panel? Well, as it turns out, a bunch of
other people have done this...but I haven't, so that's what makes it
cool in my book. I think I earn style points. I was doing
some reading in the good book (otherwise known as 'The Art of
Electronics') and found a section talking about this, so I figured
I'd try it out. I ended up with a string of 7 IR LEDs ('cause
that's all I had on hand), anodes to a common pin, cathodes to
different pins on a PIC18F4620, all pins are schmidt trigger types
(PortD, PortC, PortA.4, etc. The TTL inputs draw too much current and
don't give a decent reading). I've also got an LCD hooked up for a
display of whatever was going on. (Note: I tried using
standard LEDs of various colors, but they didn't seem to work very
well for me. I would've liked to use visible light LEDs to give
a neat looking input panel type of thing, but it didn't work.
Oh well).
Jist of the story, the software runs, I've got the
LEDs lined up in a row, I run my finger over (but not touching) the
IR LEDs, I set up a block on the LCD to basically follow my finger
running over the IR LEDs! This is neat.
To read the IR LEDs,
set 2 pins as output. You first forward bias the IR LED (one pin
high, one pin low) for about 1ms. Next you reverse bias (high goes
low, and low goes high) to essentially 'charge' them up for another
1ms or so (every diode has a certain amount of capacitance when
reverse biased. Then you set the pin that's high when the LED is
reverse biased to an input. Immediately after that you set up a
counter inside a tight if/then. When the input changes from a 1 to a
0 (because the voltage 'stored' in the LEDs capacitor is decaying),
you save the count and exit the if/then. The count you get when you
exit the if/then is inversely proportional to the amount of light
hitting the IR LED, the lower the number, the more the light; the
higher, the darker. I then compare all of the numbers, looking for
the lowest number and display a solid block in that character
position.
Here's a snippet of example PBP code (without the
generic sections like LCD defines, config settings, etc. oh, and my
PIC is running at 40mhz, I don't know how well it'll work at slower
speeds, if at all.):
looper var byte : anode var porta.1
'common anode of all IR LEDs
t1 var portc.5 : t2 var portc.4 : t3
var portc.1 : t4 var portc.0 : t5 var porte.2 : t6 var porte.1 : t7
var porta.4 'all IR LEDs cathodes pins
touchval var word[7] :
touchmin var word[7] : touchmax var word[7] : touchrange var word[7]
: touchpos var word[7] : touchaverage var word[7] : touchmidpoint var
word[7] : maxval var byte : maxtemp var word
skipsubs:
'generic setup I use for all my programs, YMMV
flags=0 : pause
1000 : intcon=0 : intcon.7=1 : intcon.6=1 : intcon.5=1 : intcon2=0 :
intcon2.2=1 : intco3=0 : pir1=0 : pir2=0 : pie1=0 : pie1.5=1 :
pie1.4=1 : pie2=0 : t0con=0 : t0con.7=1 : t0con.6=1
t0con=t0con+2
: t1con=0 : t2con=0 : t3con=0 : ccp1con=0 : ccp2con=0 : pwm1con=0 :
eccp1as=0 : sspstat=0 : sspcon1=0 : sspcon2=0 : txsta=0 : txsta.6=0 :
txsta.5=1 : txsta.4=0 : txsta.2=1 : rcsta=0
rcsta.7=1 : rcsta.6=0
: rcsta.4=1 : baudcon=0 : baudcon.3=1 : spbrgh=4 : spbrg=16 :
adcon0=0 : adcon1=$f : adcon2=$ff : cmcon=7 : cvrcon=0 : hlvdcon=0 :
trisa=0 : porta=0 : trisb=0 : portb=0 : trisc=0
portc=0 : trisd=0
: portd=0 : trise=0 : porte=0 : input switch1 : input switch2 :
output led1 : led1=1 : led1=0 : pause 200 : led1=1 : pause 200 :
led1=0 : pause 200 : led1=1 : pause 200 : led1=0 : pause 200
led1=1
: pause 200 : led1=0 : pause 200 : led1=1 : pause 200 : led1=0 :
pause 200 : lcdout $fe,1 : switchignorecount=0 : menu=1 :
switchdelay=1000 : output serialdataoutputpin : input
serialdatainputpin
touchmin = 65000 : touchmax =
100
loop2:
led1 = counter.0
for looper = 1 to 7 'light
an LED, even though you can't see it
output
anode : anode=1 : input t1 : t1=0 : input t2 : t2=0 : input t3 : t3=0
: input t4 : t4=0 : input t5 : t5=0 : input t6 : t6=0 : input t7 :
t7=0
select case looper
case 1
output t1 : t1 = 0
case
2
output t2 : t2 = 0
case
3
output t3 : t3 = 0
case
4
output t4 : t4 = 0
case
5
output t5 : t5 = 0
case
6
output t6 : t6 = 0
case
7
output t7 : t7 = 0
end select
pause 1 : anode = 0
select case looper 'reverse
bias that same LED
case
1
output t1 : t1 = 1
case
2
output t2 : t2 = 1
case
3
output t3 : t3 = 1
case
4
output t4 : t4 = 1
case
5
output t5 : t5 = 1
case
6
output t6 : t6 = 1
case
7
output t7 : t7 = 1
end select
pause 1
select case looper 'switch that LED to
an input to read it
case 1
input t1
case
2
input t2
case
3
input t3
case
4
input t4
case
5
input t5
case
6
input t6
case
7
input t7
end select
loop3a:
'run a counter in a tight loop (loop3a) and keep checking and waiting
for the particular LED input to drop from a logic 1 to a logic 0
because the voltage sitting on the LED due to the internal
capacitance drops 'slowly'
touchval[ looper ] =
touchval[ looper ] + 1 : if touchval[ looper ] > 65000 then goto
kickoutloop3a
'if we wait too long or the pin
is stuck, we'll never get out of the loop
select case looper
case
1
if t1 = 1 then goto loop3a
case 2
if t2 = 1 then goto loop3a
case 3
if t3 = 1 then goto loop3a
case 4
if t4 = 1 then goto loop3a
case 5
if t5 = 1 then goto loop3a
case 6
if t6 = 1 then goto loop3a
case 7
if t7 = 1 then goto loop3a
end
select
kickoutloop3a:
counter = counter + 1
'just a counter to show a 'heartbeat'
next looper
maxval =
0 : maxtemp = 0 'maxval keeps track of which led had the lowest
value, maxtemp keeps track of the lowest value
for looper = 1
to 7 'check al 7 LEDs to find the lowest one
if
touchval[ looper ] > maxtemp then
maxtemp = touchval[ looper ] : maxval = looper
endif
next looper
'clear out the line, then display the
number of the darkest LED
lcdout $fe,$80," ":lcdout
$fe,$80+(7-maxval),DEC1 (7-maxval ) : lcdout $fe,$c0," ":lcdout
$fe,$c0+(7-maxval),$ff
for looper = 1 to 7 : touchval[ looper ] =
0 : next looper
goto loop2
END
For some reason, this
only seems to work with the IR LEDs I have on hand. That might be
because they are all cheap LEDs. Somebody might get this to work with
visible light LEDs, I don't know. Then I wonder if this will work
with those bargraph LEDs. You could do something silly like those
slider thingies on Star Trek where they run their fingers up a panel
and the lights follow.
As soon as I get some more ambition, I'll
post a quick schematic of how this is all hooked up, but rest
assured, it's all very simple:
All LED anodes to one pin (TTL input type, NOT Schmidt trigger)
All LED cathodes to a schmidt trigger I/O port (i.e. on a PIC18F4620, PortD, PortC, some of PortA, etc.)
Normal power, ground, oscillator, etc. Although I did have to run my PIC18F4620 at 40mhz to get any reliable results. You might get away with a lower clock speed, maybe with a cleaner circuit, not on a solderless breadboard, that sort of thing.
And a generic LCD display hookup.
Like I said, I'm getting a kick out of this....
Maybe somebody
else will too..