Forum: Mikrocontroller und Digitale Elektronik LED als Sensor an Port Pin


von Glorb (Gast)


Lesenswert?

Hallo,
ich versuche gerade den in folgendem Paper genannten Aufbau zu 
implementieren:
http://www.merl.com/publications/docs/TR2003-35.pdf

Dabei geht es darum eine bidrektionale kommunikation mittels LEDs 
aufzubauen. Soweit so gut, ich möchte erstmal eine LED als Empfänger 
betreiben.

Hier sieht man noch einmal wie das ganze funktioniert:
http://people.duke.edu/~sd78/projectHub/projects/optoelectronics/principle_clip_image002.jpg

Ich verstehe was dabei passiert nun habe ich folgenden code dazu 
geschrieben:

Ein Timer ISR wird alle 100µs ausgelöst und soll dann die genannte 
"Entladungsmessung" durchführen, in diesem Beispiel wird ein Zähler 
solange erhöht bis die Entladung fertig ist.

ISR(TIMER0_COMPA_vect) {
  DDRC |= (1<<(PC1));
  PORTC |=  (1<<(PC1));
  PORTC &= ~(1<<(PC0));
asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
  DDRC &= ~(1<<(PC0));
  if((PORTC&(1<<PC0))) count++;
}

Die LED hängt mit der Kathode über einen Widerstand an PC0, Anode an 
PC1. Das Problem ist nun, der Zähler läuft einfach hoch ohne dass sich 
irgendetwas verändert hat. Wenn ich messe liegen an PC0 auch einfach 
noch 5V an nachdem die Pinrichtung umgedreht wurde. Vielleicht hat 
jemand eine Idee was ich falsch mache.

von Karl H. (kbuchegg)


Lesenswert?

Glorb schrieb:


>   DDRC &= ~(1<<(PC0));
>   if((PORTC&(1<<PC0))) count++;

PINC, nicht PORTC

Den Rest muss ich jetzt mal selber recherchieren.

von Glorb (Gast)


Lesenswert?

aua, danke! das ist schonmal ne gute idee :)

von Glorb (Gast)


Lesenswert?

hat aber noch nichts gebracht.

von Karl H. (kbuchegg)


Lesenswert?

Hmm

Das hier
1
An inexpensive way to make a photodetector out of an LED is to tie the
2
anode to ground and connect the cathode to a CMOS I/O pin driven high.
3
4
This reverse biases the diode, and charges the capacitance. Next switch
5
the I/O pin to input mode, which allows the photocurrent to discharge
6
the capacitance down to the digital input threshold. By timing how
7
long this takes, we get a measurement of the photocurrent and thus
8
the amount of incident light.

Hmm. das deckt sich aber nicht mit dem was du programmiert hast.

Nimm dir die Bilder her und schreib dir mal deine Pin-Bezeichnungen 
dazu. Und dann geh die Bilder (bzw. die Beschreibung) durch und sieh dir 
an, in welcher Reihenfolge du welchen Portpin wie beschalten musst. Und 
erst dann, wenn du dir 100% sicher bist, dass du die Reihenfolge der 
Ereignisse hast, erst dann setzt du dich hin und programmierst das.
Im Idealfall schreibst du dir in Stichworten die korrekte Reihenfolge 
tabellenarrtig auf und überprüfst die 3 mal gegen den Text bzw. die 
Bilder.

von Glorb (Gast)


Lesenswert?

korrekt da war allerdings noch etwas falsch:
PC0 ---RRRR---]<----- PC1

ISR(TIMER0_COMPA_vect) {
  DDRC |= (1<<(PC0));
  DDRC |= (1<<(PC1)); // beide Ausgänge

  PORTC |=  (1<<(PC1));  // Phase EMIT
  PORTC &= ~(1<<(PC0));

  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");

  PORTC |=  (1<<(PC0));  // Phase Reverse Bias
  PORTC &= ~(1<<(PC1));

  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
  // Phase Discharge
  DDRC &= ~(1<<(PC0)); // Eingang
  DDRC |= (1<<(PC1)); // Ausgang

  if((PORTC&(1<<PC0))) count++; // PC0 ist noch HIGH dann zählen
}

nochmal angepasst.

von Karl H. (kbuchegg)


Lesenswert?

Glorb schrieb:
> korrekt da war allerdings noch etwas falsch:
> PC0 ---RRRR---]<----- PC1
>
> ISR(TIMER0_COMPA_vect) {
>   DDRC |= (1<<(PC0));
>   DDRC |= (1<<(PC1)); // beide Ausgänge
>
>   PORTC |=  (1<<(PC1));  // Phase EMIT
>   PORTC &= ~(1<<(PC0));
>
>   asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
>
>   PORTC |=  (1<<(PC0));  // Phase Reverse Bias
>   PORTC &= ~(1<<(PC1));
>
>   asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
>   // Phase Discharge
>   DDRC &= ~(1<<(PC0)); // Eingang
>   DDRC |= (1<<(PC1)); // Ausgang
>
>   if((PORTC&(1<<PC0))) count++; // PC0 ist noch HIGH dann zählen

PINC

> }
1
Next switch
2
the I/O pin to input mode, which allows the photocurrent to discharge
3
the capacitance down to the digital input threshold. By timing how
4
long this takes,

Also
zuerst auf Input schalten
dann Zeit messen.

Du schaltest auf Input und siehst gleich am Pin nach.
Wie ich schon sagte: Schreib dir doch erst mal in Stichworten zusammen 
wie die Reihenfolge der Ereignisse sein muss

von Glorb (Gast)


Lesenswert?

Ich verstehe es so wie auf den Bildern gezeigt: Reverse Bias und dann 
Input. Mein Fehler ist vielleicht, dass ich das immer wieder im Timer 
stattfinden lasse. Was ich eigentlich zum Test erst einmal zeigen will: 
Das Programm läuft, die LED ist unbeleuchtet, nichts passiert. Sobald 
diese beleuchtet wird soll der Zähler hochzählen bis die LED wieder 
unbeleuchtet ist.

von Karl H. (kbuchegg)


Lesenswert?

Glorb schrieb:
> Ich verstehe es so wie auf den Bildern gezeigt: Reverse Bias und dann
> Input.

Schau dir nicht nur die Bilder an. Lies auch den Text!
Denn wann gewartet wird, siehst du in den Bildern nicht.

Das steht eindeutig:

zuerst wird auf reverse geschaltet, wodurch die 'Kapazität' geladen 
wird. Ok. da wirst du ein bischen warten müssen

Danach auf Input schalten

und jetzt hängt es davon ab, wie lange es dauert bis der Eingangspin 
wieder auf 0 gefallen ist, ob man davon ableitet das die LED beleuchtet 
ist oder nicht.

Die Zeit NACH dem Umschalten auf Input ist das entscheidende!

von Glorb (Gast)


Lesenswert?

d.h. ich habe etwa folgendes modell:

Timer_ISR() {
   if((PINC&(1<<PC0))) count++;
}


void main() {
   timer_setup();

   DDRC |= (1<<(PC0));
   DDRC |= (1<<(PC1));
   while(1) {
      cli();
      PORTC |=  (1<<(PC0));  // Phase Reverse Bias
      PORTC &= ~(1<<(PC1));
      asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
      DDRC &= ~(1<<(PC0));
      sei();
   }
}

ich stehe noch etwas auf dem schlauch wie man sieht, pseudocode zum 
ablauf ist willkommen.

von Glorb (Gast)


Lesenswert?

ich habe einen Erfolg zu vermelden :).

Meine version ist noch nicht genau das was ich haben will aber es 
scheint zu gehen:
void main() {
  uart_init();

measure:
  count = 0;

  DDRC |= (1<<(PC0));
  DDRC |= (1<<(PC1)); // beide Ausgänge

  PORTC |=  (1<<(PC0));  // Phase Reverse Bias
    PORTC &= ~(1<<(PC1));

  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");

  DDRC &= ~(1<<(PC0));
  PORTC &= ~(1<<(PC0)); // das war wichtig!

  while((PINC&(1<<PC0))) count++;

  if(count>5000) goto measure;

  {
    char buffer[32];
    sprintf(buffer,"count: %d",count);
    put_stamped(buffer);
  }

  goto measure;
  while(1) {}
  return 0;
}


Auf jedenfall kann ich jetzt eine Anzahl sehen wenn die LED entladen 
wird, halte ich eine Taschenlampe drauf ist die Zahl klein, im 
Tageslicht ist sie groß. Wie es sein sollte. Natürlich muss ich das 
ganze nun noch auf den Timer umbauen!

von Vlad T. (vlad_tepesch)


Lesenswert?


von Glorb (Gast)


Lesenswert?

oh danke, das hätte etwas zeit erspart :). Allerdings muss ich das ganze 
sowieso Interrupt gesteuert bauen, von daher.

von Michael S. (mikel_x)


Lesenswert?

Moin moin...

Hab mal ein paar Versuche dazu gemacht:
(Die Zahlenwerte in Klammern wurden mit untenstehendem, kleinen Prog. 
emittelt)

1.)Bestrahlung mit 60W Reflektor-Glühlampe

a) mit roten LEDs ging garnix.
b) gelbe LEDs: gut (dunkel ca. 1640; max. hell: 5)
c) grüne LEDs: gut (dunkel ca. 1640; max. hell: 5)


2.) LED mit LED bestrahlen (Kopf an Kopf)
Vorweg: eine rote LED als Sender, zeigt keine Wirkung bei beliebigen 
Empfänger-LEDs.

a) rote LED als Empfänger zeigt auch keine Wirkung, egal womit sie 
bestrahlt wird. Selbst mit nem roten Laserpointer bestrahlt, zeigte sie 
keine verwertbare Reaktion.

Empf.-LED, bestrahl mit anderer LED:

b) gelb, mit gelb bestrahlt = gut  (dunkel ca. 1640; max.hell: ca. 480)

c) grün, mit grün bestrahlt = besser  (dunkel ca. 1640; max.hell: ca. 
300)

d) gelb, mit grün bestrahlt = beste (dunkel ca. 1640; max.hell: ca. 200)

e) grün, mit gelb bestrahlt = s. schlecht (dunkel ca. 1640; max.hell: 
ca. 1610)


Fazit:
2c) grün/grün ist vielversprechend, zumal damit eine bidirektionale 
optische Kopplung, durch beidseitige Umpolung der LEDs, möglich wird...



++++++++++++++++++++++++++++++++++++++++++
Das Testprogramm in Bascom, mit Ausgabe auf Terminalprog über 
USB/serial(TTL) mit TX an PinB.4..:

$regfile = "attiny85.dat"
$crystal = 1000000
$hwstack = 40
$swstack = 16
$framesize = 32


Ddrb = &B000010
Dim A As Word

Open "ComB.4:1200,8,N,1,inverted" For Output As #1

Do

  Set Portb.0
  Waitus 40
  Reset Portb.0

   While Pinb.0 = 1
    Incr A
   Wend

 Print #1 , "Counts:    " ; A
 A = 0

Loop

Close #1
End

++++++++++++++++++++++++++++++++++++++++++++++

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.