Arduino Bibliotheken

Inhalt

  • Installieren einer Bibliothek (engl. library)

Code-Bibliotheken in Arduino

Für eine Vielzahl von Anwendungen existieren Code-Bibliotheken, die man leicht in seinen Programmcode einbinden kann, um es unkompliziert um seine Funktionalität zu erweitern. Die Arduino-IDE hat bereits eine ganze Reihe von Bibliotheken für unterschiedliche Zwecke mit integriert.

Sehr viele Sensoren, Aktoren oder andere Bauteile werden gleich mit einer Bibliothek zur Verfügung gestellt, damit man sich bei der Implementierung seiner Anwendung auf das wesentliche konzentrieren kann.

Einbinden von Bibliotheken

Bei der Einbindung von Bibliotheken muss zwischen zwei Typen von Bibliotheken unterschieden werden: Interne Bibliotheken (die gleich von der Arduino-IDE zur Verfügung gestellt werden oder in speziellen Ordnern liegen, die Arduino kennt) und externe Bibliotheken, die irgendwo im Dateisystem liegen können. Die Arduino-IDE verfügt außerdem über einen Library-Manager, mit dem Bibliotheksinstallationen automatisiert durchgeführt werden können.

Bibliotheken werden ganz am Anfang des Programmcodes mit einem #include  Ausdruck eingebunden. Nach dem #include  folgt der Name der Header-Datei der Bibliothek. (In der Headerdatei befindet sich eine für den Compiler wichtige „Beschreibung der Funktionalität“ der Bibliothek, ohne die das Programm nachher nicht kompiliert werden kann)

Die Einbindung von internen und externen Bibliotheken unterscheidet sich dahingehend, dass die Header-Dateien von internen in <>  Klammern stehen, die von externen in ""  Anführungszeichen.

Interne Bibliotheken müssen entweder im selben Ordner wie die Arduino-Sketch-Datei abgelegt werden, oder in einem für Bibliotheken vorgesehenen Ordner am Computer (mehr Infos dazu hier).

Installation einer Arduino Library

Ausführliche Informationen zur Installation von Arduino-Libraries finden sich auf der Arduino Webseite.

Debouncing

Inhalt

  • Das Contatc-Bounce-Problem bei Buttons
  • Debouncing mittels Bibliothek

Einführung

Bauelemente, die Schaltkreise physisch schließen und öffnen (Taster, Schalter, Relais, Encoder, …) sind oft vom Problem des Bouncings betroffen. Dabei wird der elektrische Kontakt oft nicht sofort vollständig geöffnet oder geschlossen, sodass Sensoren manchmal mehrere Schaltvorgänge in einem sehr kurzem Zeitraum detektieren.

Contact Bounce (Quelle: Wikipedia)

Dieses Verhalten ist unerwünscht, weshalb hard- oder softwareseitig Maßnahmen getroffen werden um ein mehrfaches auslösen zu verhindern.

Die Bounce2-Bibliothek

Die Bounce2 Bibliothek bietet zwei Strategien um mit dem Bouncing-Phänomen umzugehen. Beide warten einen bestimmten Zeitraum um den Effekt des Bouncings zu ignorieren.

Das Wiki der Bibliothek beschreibt die Möglichkeiten:

Stable Interval

Nach der Beendigung des Bouncings muss der Zustand eine definierte Zeitdauer stabil gewesen sein, um abgeschlossen zu sein:

Bildquelle: Bounce2 Wiki
Lock-Out Interval

Durch Editieren der Header-Datei der Bibliothek kann ein weiterer Modus aktiviert werden. Durch ein Einfügen von #define BOUNCE_LOCK_OUT am Anfang der Bounce.h-Datei wird die Lock-out-Methode aktiviert. Diese reagiert sehr schnell. Nachteilig ist, dass der auftretende Noise bei zu kurzer Definition des zeitlichen Intervals nicht ausgelöscht wird.

Bildquelle: Bounce2 Wiki

Beispiel: Anwendung von Bounce2

Folgender Code basiert auf dem Beispiel Taster als Schalter, ist aber um die Bounce-Bibliothek erweitert. (Er setzt voraus, dass sie die Bibliothek auch installiert haben).

Code-Analyse

Zunächst wird mit #include <Bounce2.h>  die installierte Bounce2-Bibliothek eingebunden (stellen Sie sicher, dass sie auch installiert ist) und anschließend die Pin-Nummern in Variablen gespeichert (die Installation von Bibliotheken wird auf der Arduino Website oder auch hier behandelt).

Durch die Zeile Bounce debouncer = Bounce();wird ein Bounce-Objekt namens  debouncer  erstellt. Dieses Objekt wird wie eine Variable verwendet und bekommt später verschiedene Eigenschaften (z.B. welchem Pin es zugewiesen ist).

In setup()  wird zunächst der Input wie üblich erstellt ( pinMode(BUTTON_PIN,INPUT_PULLUP);). Im Anschluss wird dem Bounce-Objekt dieser Pin mittels debouncer.attach(BUTTON_PIN); zugewiesen. Über den Aufruf der Methode debouncer.interval(5);  wird dem Bounce-Objekt eine Wartezeit von 5 ms zugewiesen (in der weiteren Verwendung muss der Taster also 5 ms stabil sein, damit ein Zustandswechsel erkannt wird).

In loop()  wird der Taster mit dem Bounce-Objekt verwendet. Zunächst muss der Zustand des Buttons bei jeder Ausführung des loops mittels debouncer.update(); ausgelesen werden. Über debouncer.read();  wird nun der digitale Input ausgelesen und der Wert in einer Variable gespeichert (es ist keine Angabe des Pins notwendig, da debouncer bereits vorher einen Pin zugewiesen bekommen hat). Die Variable enthält nun den entsprechenden, gefilterten Wert des Tasters.

Weiterführende Links

  • https://en.wikipedia.org/wiki/Switch#Contact_bounce
  • http://playground.arduino.cc/Code/Bounce

Interrupts

Inhalte

  • Interrupts als Trigger um Funktionen sofort aufzurufen

Einführung

Viele Anwendungen sind so konzipiert, dass sie die meiste Zeit eine bestimmte Funktion erfüllen und nur beim Eintritt eines definierten Ereignisses eine bestimmte andere Funktion ausführen müssen (Ein Beispiel hierfür wäre ein Kaffeeautomat, der die meiste Zeit im Leerlauf ist, aber bei einem Münzeinwurf in einen anderen Modus wechselt).

Für manche Anwendungen ist es wichtig, dass sie – egal was sie gerade ausführen – unterbrochen werden können (etwa um einen Not-Stopp einer Anlage ausführen zu können).

Da diese Art von Unterbrechungen oder Wechsel sehr gerne zum Einsatz kommen, haben viele Mikrocontroller eine spezielle Routine hierfür vorgesehen: Interrupts.

Interrupts an Pins

Interrupts sind Funktionen, beim Eintreffen eines bestimmten Ereignisses sofort ausgeführt werden (egal, wo man sich in der Ausführung eines Programms gerade befindet). Das Arduino hat die Eigenschaft, dass die Auslösung eines Interrupts an bestimmte digitale Pins gekoppelt werden können (am Arduino UNO sind dies Pins 2 und 3). Diese Pins werden überwacht und können den Prozessor unterbrechen um eine definierte Methode, die Interrupt Service Routine (ISR), auszuführen. Diese ISRs müssen sehr kurz und schnell ausführbar gehalten werden um den Prozessor nicht zu lange zu blockieren. Dafür sind sie aber auch für Anwendungen mit sehr schnellen Zustandswechsel wie Drehencoder geeignet.

Beispiel 1: Interrupts an digitalen Pins anwenden

Folgender Code demonstriert die Einbindung einer ISR und die Verbindung der Routine mit dem digitalen Pin. Beim Anhängen an der Routine an den Pin wird außerdem definiert, welches Ereignis die ISR auslösen soll. Dieses Ereignis bezieht sich auf die Flanke des Pins. Zur Wahl stehen

  • RISING (steigende Flanke)
  • FALLIN (fallende Flanke)
  • CHANGE (also bei steigender oder fallender Flanke) und
  • LOW (ISR wird immer ausgeführt, solange der Pin LOW ist).

Das Programm an sich macht nichts anderes, als einen Pin zu überwachen und bei einem Wechsel des Zustands, die ISR aufzurufen. Diese wiederrum invertiert nur den Zustand einer Variable, die auf den ledPin 13 geschrieben wird.

Code-Analyse

Die Variable int state  wird als volatile  definiert. Dies sollte für alle Variablen gemacht werden, die in einer ISR verändert werden (sie werden hierfür in einem speziellen Speicherbereich abgelegt und können somit auf jeden Fall korrekt upgedatet werden).

Die Methode attachInterrupt(digitalPinToInterrupt(interruptPin), myISR, CHANGE) definiert den Interrupt-Pin, die ISR für diesen Pin und auf welchen Zustand geachtet werden soll:

  • Interrupt-Pin: Hierbei wird empfohlen, dass die Pin-Nummer nicht direkt angegeben wird, sondern stattdessen die Pin-ID über die Methode digitalPinToInterrupt(interruptPin)  herausgefunden wird. Grund hierfür ist, dass bei verschiedenen Arduino Plattformen (neben dem UNO existieren noch weitere) die Prozessoren möglicherweise andere  Bezeichnungen für diese Pins haben. Mit dem Aufruf dieser Methode ist garantiert, dass der Code auch auf anderen Boards wie erwartet läuft.
  • ISR: Der Name der Methode (hier myISR ) wird als Parameter angegeben.
  • Zustand: Durch die Angabe von CHANGE  wird die vorhin angegebene Methode immer dann aufgerufen, wenn der Zustand wechselt (egal ob von LOW zu HIGH oder umgekehrt).

In der loop  Methode geschieht nichts, außer dass der Zustand der Variable state  auf einen Pin geschrieben wird.

Die Methode myISR  ist eine sehr kurz gehalten und erfüllt hier nur die Funktion, dass der Zustand der Variable state  gewechselt wird. Da myISR  durch den Interrupt immer dann aufgerufen wird, wenn sich der Zustand des Interrupt-Pin ändert, ist es nicht notwendig die Funktion irgendwo anders im Code aufzurufen.

PinChangeInterrupts (PCI)

Am Arduino können für die alle Pins (nicht nur 2 und 3 wie beim UNO) mit einem PinChangeInterrupt belegt werden. Diese lösen sowohl bei RISING als auch FALLING aus, allerdings werden die ISRs immer in Gruppen von Pins definiert (d.h. mehrere Pins haben dieselbe Interrupt-Routine). Für manche Anwendungen wie z.B. Drehencoder ist dies egal, für andere muss eventuell weitere Funktionalität eingefügt werden um zwischen den Pins unterscheiden zu können.

Einen guten Überblick über PCIs gibt dieser Artikel.

Zusammenfassung

Interrupts am Arduino bieten die Möglichkeit eine ISR sofort und sehr schnell auszuführen. Mittels der Funktion attachInterrupt  wird die ISR Funktion, der Pin und der Zustandswechsel definiert. Nick Gammon empfiehlt für den Code in der ISR folgendes:

 

  • Code kurz halten
  • delay -Funktion nicht verwenden
  • Keine Serial prints
  • Variablen, die im Hauptcode und der ISR verwendet werden müssen volatile  sein
  • Interrupts sollen nicht ein- und ausgeschalten werden

 

Weiterführende Links

  • https://www.arduino.cc/en/Reference/Volatile
  • https://www.arduino.cc/en/Reference/AttachInterrupt
  • http://gammon.com.au/interrupts
  • http://playground.arduino.cc/Main/PinChangeInterrupt