Derzeit prüft meine Skizze jedes Mal einen Eingabestift in der Hauptschleife. Wenn eine Änderung festgestellt wird, wird eine benutzerdefinierte Funktion aufgerufen, um darauf zu reagieren. Hier ist der Code (auf das Wesentliche reduziert):
int pinValue = LOW;
void pinChanged()
{
//...
}
void setup()
{
pinMode(2, INPUT);
}
void loop()
{
// Read current input
int newValue = digitalRead(2);
// Has the input changed?
if (newValue != pinValue) {
pinValue = newValue;
pinChanged();
}
}
Leider funktioniert dies bei sehr kurzen Änderungen am Eingang (z. B. kurzen Impulsen) nicht immer einwandfrei, insbesondere wenn dieser loop()
etwas langsam läuft.
Gibt es eine Möglichkeit, den Arduino die Eingabeänderung erkennen zu lassen und meine Funktion automatisch aufzurufen?
Antworten:
Sie können dazu externe Interrupts verwenden. Die meisten Arduinos unterstützen dies jedoch nur mit einer begrenzten Anzahl von Pins. Ausführliche Informationen finden Sie in der Dokumentation zu
attachInterrupt()
.Angenommen, Sie verwenden ein Uno, könnten Sie dies folgendermaßen tun:
Dies wird
pinChanged()
immer dann aufgerufen, wenn eine Änderung am externen Interrupt 0 festgestellt wird. Auf der Uno entspricht dies dem GPIO-Pin 2. Die Nummerierung der externen Interrupts unterscheidet sich auf anderen Karten, daher ist es wichtig, die entsprechende Dokumentation zu überprüfen.Diesem Ansatz sind jedoch Grenzen gesetzt. Die benutzerdefinierte
pinChanged()
Funktion wird als Interrupt Service Routine (ISR) verwendet. Das bedeutet, dass der Rest des Codes (alles inloop()
) vorübergehend angehalten wird, während der Aufruf ausgeführt wird. Um zu verhindern, dass wichtige Timings gestört werden, sollten Sie versuchen, ISRs so schnell wie möglich zu machen.Es ist auch wichtig zu beachten, dass während Ihres ISR keine anderen Interrupts ausgeführt werden. Das bedeutet, dass alles, was auf Interrupts angewiesen ist (wie der Kern
delay()
und diemillis()
Funktionen), möglicherweise nicht richtig funktioniert.Wenn Ihr ISR globale Variablen in der Skizze ändern muss, sollten diese normalerweise wie folgt deklariert
volatile
werden:Dies ist wichtig, da der Compiler darauf hingewiesen wird, dass sich der Wert unerwartet ändern kann. Daher sollte darauf geachtet werden, keine veralteten Kopien / Caches zu verwenden.
quelle
pinChanged()
sollte es so kurz wie möglich sein. Daher sollte die minimale Zeit normalerweise die Zeit sein, um diepinChanged()
Funktion selbst auszuführen .volatile
Wenn die globale Variable, wie someNumber, breiter als 1 Byte ist, müssen Sie nicht nur gemeinsam genutzte Globale deklarieren , sondern auch vor dem Pin-Wechsel-Interrupt schützen, der zwischen den Byte-Zugriffen des Programms auftritt. Bei einer Anweisung wie dieser werdensomeNumber +=5;
die niedrigen Bytes und die hohen Bytes mit eingeschlossenem Übertrag hinzugefügt. Diese beiden (für breitere Variablen) dürfen nicht durch einen Interrupt geteilt werden. Das Ausschalten und Wiederherstellen der Interrupts vor bzw. nach der Operation ist ausreichend.Jeder Änderungszustand an einem als Digitaleingang konfigurierten Pin kann zu einem Interrupt führen. Im Gegensatz zu den eindeutigen Vektoren für die Interrupts, die von INT1 oder INT2 verursacht werden, verwendet die Funktion PinChangeInt einen gemeinsamen Vektor und die Interrupt Service Routine (auch bekannt als ISR) für diesen Vektor muss dann bestimmen, welcher Pin geändert wurde.
Glücklicherweise macht PinChangeInt Library dies einfach.
quelle
Für den Fall, dass Sie eine Spannung erkennen möchten, die einen Schwellenwert überschreitet , anstatt nur HOCH oder NIEDRIG zu sein, können Sie den analogen Komparator verwenden. Beispielskizze:
Dies kann nützlich sein für Dinge wie Lichtdetektoren, bei denen Sie möglicherweise eine Änderung von (sagen wir) 1 V auf 2 V an einem Eingang feststellen müssen.
Beispielschaltung:
Sie können auch die Input Capture Unit auf dem Prozessor verwenden, die die genaue Zeit bestimmter Eingänge speichert, indem Sie die aktuelle Zählung von Timer / Counter 1 speichern. Auf diese Weise können Sie den genauen (nahezu genauen) Zeitpunkt des Ereignisses speichern Anstatt die Verzögerung (von wahrscheinlich einigen Mikrosekunden) einzuführen, bevor ein ISR zum Erfassen der aktuellen Zeit verwendet werden kann, trat Interesse auf.
Für zeitkritische Anwendungen kann dies zu einer etwas höheren Genauigkeit führen.
Beispielanwendung: Verwandeln Sie Ihren Arduino in einen Kondensatortester
quelle