Unterbechnung einer Lichtschranke möglichst schnell erfassen

Hallo.
Ich möchte, dass die Unterbrechung einer Lichtschranke möglichst schnell erfasst wird.
Der entsprechende Eingang am Arduino Mega 2560 wird LOW, wenn das passiert. Der Arduino braucht in dieser Zeit nichts weiter zu tun, als auf LOW zu warten.

Wie erfasse ich diesen LOW-Zustand schneller:
Erstens:
while(true)
{
if (digitalRead(PIN_LICHTSCHRANKE) == LOW) { "tue dies und das"}
}

oder zweitens mittels eines interrup auf diesen Pin?
attachInterrupt(0, "tue dies und das", FALLING);

oder drittens??

Der "Lösungsweg" wäre für mich fast ebenso interessant wie das Ergebnis.

Gruß
Andreas

Dafür braucht man keine Interupts. Ich hoffe mal, while(true) bzw. while(1) soll deine loop darstellen. Das ist vollkommen ausreichend, wenn in jedem loop Durchgang überprüft wird. delays und sonstige Systembremsen sollten aber garnicht erst in den Sketch kommen!

Mit Interrupt geht's aber vermutlich nen Tick schneller.
Und statt digitalread den Port direkt auslesen ist sicher auch flotter. Kommt halt drauf an, worum es geht.

Wenn ich raten soll: fotografieren?

richtig geraten :slight_smile: war vielleicht auch nicht so schwer.

im grunde funktioniert auch schon alles (ob foto oder eigentlich eher blitz) aber man will sich ja stetig verbessern.

Mach ich auch gerade. Mit altem Laserpointer, Fototransistor und Uno.

ich habe die Lichtschranke von eltima. die schaltet auch direkt einen Blitz. mit dem Arduino habe ich aber eine Zeitverzögerung mit drin.

Uhh, Profiequipment ...

phthalo:
Ich möchte, dass die Unterbrechung einer Lichtschranke möglichst schnell erfasst wird.

Definiere mal: Wie schnell ist "schnell" bei Dir?

phthalo:
Der entsprechende Eingang am Arduino Mega 2560 wird LOW, wenn das passiert. Der Arduino braucht in dieser Zeit nichts weiter zu tun, als auf LOW zu warten.

Wie erfasse ich diesen LOW-Zustand schneller:
Erstens:
while(true)
{
if (digitalRead(PIN_LICHTSCHRANKE) == LOW) { "tue dies und das"}
}

oder zweitens mittels eines interrup auf diesen Pin?
attachInterrupt(0, "tue dies und das", FALLING);

oder drittens??

Es ist relativ unergiebig, über den Arduino-Code zu diskutieren, wenn die Haupt-Auslöseverzögerung von der Lichtschranke her kommt.

Beispiel "Lichtschranke mit mechanischem Relais": Wenn der Ausgang der Lichtschranke mit einem mechanischen Relais geschaltet wird, ist das langsamste der Schaltvorgang des Relais. Relais können zum Schalten durchaus 0,01s brauchen, also 10 ms bzw. 10000µs.

Lichtschranken mit Transistorausgang sind viel schneller als solche mit Relaisausgang.
Welche Art Ausgang hat Deine Lichtschranke?

Zweiter Punkt ist das Messprinzip einer Lichtschranke: Handelsübliche Lichtschranken arbeiten zwecks Vermeidung von Fehlauslösungen mit "gepulstem Licht". So wie auch die bekannten Infrarot-Fernbedienungen. Der Lichtstrahl ist nicht einfach nur Licht, sondern moduliertes Licht mit einer aufgeprägten Frequenz. Oft im Infrarot und ganz oft mit einer Frequenz von 38 kHz. Egal ob die Lichtschranke dann hellschaltend oder dunkelschaltend betrieben wird, es entsteht immer eine Auslöseverzögerung, die ca. 10 Wellenlängen der Modulation entsprechen.

Hellschaltend: Lichtschranke schaltet, sobald sie 10 Stück 38 kHz Impulse empfangen hat
Dunkelschaltend: Lichtschranke schaltet, sobald sie 10 Stück 38 kHz Impulse ausgeblieben sind
Die theoretisch minimale Auslöseverzögerung handelsüblicher Lichtschranken liegt also bei
10/38 ms = 0,263 ms = 263 µs
In der Praxis ist die Auslöseverzögerung deutlich länger, da die schnellste Elektronik nicht mit Lichtgeschwindigkeit arbeitet, näheres sollte im Datenblatt der Lichtschranke stehen.

Ob Du nun einen Code für den Arduino schreibst, der das Signal der Lichtschranke in 0,002ms (2µs) oder fünfmal langsamer in 0,01ms (10µs) auswertet, macht dann den Kohl doch wirklich nicht mehr fett, oder? Denn es ändert an der Gesamtzeit doch praktisch nichts:
263µs + 2 µs = 265 µs
263µs +10 µs = 273 µs
Unterschied 273/265 = 1,03 = 3% mehr Auslösezeit bei fünfmal langsamerem Arduino-Code.
Bestenfalls, denn die Lichtschranke an sich wird langsamer sein als das theoretisch denkbare Minimum.
Das macht den Kohl auf der Arduino-Programmierseite nicht wirklich fett, oder?

Was soll das werden und wofür soll es sein?

Hallo,

das ist ja eine interessante Ausführung, aber eigentlich bist auf den letzten Absatz doch irrelevant.
Mir ist schon klar, dass die Gesamtzeit sich zusammensetzt aus der Zeit der Elektronik der LS und die Erfassungszeit des Arduino.
Die LS ist aber (wie weiter unten auch schon steht) gegeben und da es sich um ein LS-System handelt, welches speziell für die Erfassung von hohen Geschwindigkeiten konzipiert wurde, wird die schon ok sein und v.a. wird sie auch nicht mehr verändert.
Mir geht es wie in der Frage formulier wurde einzig darum, wie mit dem Arduino die zweite der beiden Zeitkomponenten möglichst gering gehalten werden kann.
Und wie geschrieben, bin ich nicht nur daran interessiert zu erfahren, welche Vorgehensweise bei der Programmierung optimal ist sondern auch, warum sie es ist (Taktzyklen, etc.)
Im übrigen bedeutet "möglichst schnell" genau das, was es aussagt. Da muss ich keine Zeitangaben machen (immer bezogen auf den Arduino, denn das LS-System ist ja gegeben).

phthalo:
Die LS ist aber (wie weiter unten auch schon steht) gegeben und da es sich um ein LS-System handelt, welches speziell für die Erfassung von hohen Geschwindigkeiten konzipiert wurde, wird die schon ok sein und v.a. wird sie auch nicht mehr verändert.

Amen.

phthalo:
Mir geht es wie in der Frage formulier wurde einzig darum, wie mit dem Arduino die zweite der beiden Zeitkomponenten möglichst gering gehalten werden kann.
Und wie geschrieben, bin ich nicht nur daran interessiert zu erfahren, welche Vorgehensweise bei der Programmierung optimal ist sondern auch, warum sie es ist (Taktzyklen, etc.)

Die gesamte Arduino-Software ist nicht auf optimal schnelle Verarbeitung und minimale Latenzzeiten ausgelegt, sondern auf einfache Programmierung durch Hobbyisten.

Wenn Du zur Programmierung trotzdem die Arduino-Software verwenden möchtest, bekommst Du die schnellste und latenzärmste Verarbeitung sicher hin mit

  • Arduino-Software nicht aktivieren, also nicht eine setup() und loop() programmieren, sondern eine main()
  • Verarbeitung in einer Schleife ("while(true)"), aber NICHT mit digitalRead, sondern mit direkter Port-Programmierung

Begründung:
Das Arduino-Setup im Sketch aktiviert im Hintergrund Interrupts für timer0, um damit die micros() und millis() Zeitzähler zu bedienen. Jeder Interrupt benötigt einen Overhead von ca. 60 Taktzyklen und wenn ein timer0 Interrupt gerade dann auftreten würde, wenn Dein Ereignis eintritt, würdest Du mindestens diese 60 Takte Latenz drinhaben, bevor Dein Code zum Zuge kommt. Deshalb nicht das Arduino-Setup verwenden.

Auch bei allen anderen Interrupts, also den von Dir selbstgeschriebenen, tritt eine Latenz von ca. 60 Taktzyklen auf. Eine "enge loop" kann dagegen viel schneller laufen als nur einmal in 60 Mikrosekunden. Deshalb keinen Interrupt programmieren.

Auch bei digitalRead, einer Komfortfunktion der Arduino-Software, beträgt der Overhead ca. 65 Taktzyklen oder so. Eine Schleife kann nie schneller laufen als das, was in der Schleife insgesamt ausgeführt wird. Einen Eingang kann man mit direkter Portprogrammierung in 2 statt 65 Taktzyklen abfragen, also deshalb lieber direkt die Ports programmieren als digitalRead verwenden.

Wie schnell das am Ende tatsächlich wird, müßtest Du Dir mal auf einem 2-Kanal Oszilloskop ansehen: Auf den einen Kanal (Lichtschranke) triggern und auf dem zweiten Kanal (Arduino-Ausgang) nachsehen, wieviel später sich das Signal ändert.

Timer0 kann man aber auch so deaktivieren, ohne auf setup()/main() zu verzichten. Entweder die 3 CS Bits auf 0 setzen. Dann läuft er erst gar nicht. Dann geht aber auch PWM an den zwei Pins nicht mehr. Oder besser einfah das TIMSK0 Register auf 0 setzen um den Interrupt zu deaktivieren.

Wenn darum geht Zeiten zu messen, ist der schnellste Weg einen Zeitstempel zu erhalten über einen Timer im Input Capture Modus. Weil das komplett automatisch in Hardware läuft. Damit hat man theoretisch Systemtakt-Auflösung. Die Auswertung läuft natürlich wieder über einen Interrupt, was einen Overhead erzeugt und das Schalten eventuell nachfolgender Hardware verzögert, aber der Zeitstempel selbst ist genau.