Der Einsatz der Arduino-Genie-Bibliothek


 

Wir haben im vorherigen Kapitel gesehen, dass die Kommunikation zwischen Host-Controller und 4D Display nicht ganz trivial ist und wir uns um alle Einzelheiten der Kommunikation (Filterung von ACK und NAK) selbst kümmern müsen.

Diesen Nachteil können wir umgehen, wenn wir die Arduino-Genie-Bibliothek von 4D Systems nutzen. Sie können sie hier herunterladen, entpacken und den Ordner genieArduino in den "Libraries-Ordner" Ihrer Arduino-Installation verschieben.

Nach dem erneuten Öffnen der Arduino IDE finden Sie jetzt unter "Beispiele" einen Ordner mit dem Namen "genieArduino". Wir wollen aber Schritt für Schritt vorgehen und dazu 2 Beispiele erstellen:

  • Im 1. Beispiel geht es nur um die grundlegenden Schritte, d. h. wir erstellen lediglich drei Objekt auf dem 4D Display und senden ihnen Daten vom Arduino.
  • Im 2. Beispiel werden wir die Position eines Servomotors über einen Regler steuern und die Position wird dabei auf einem Zeigerinstrument angezeigt.

1. Beispiel: Senden zum 4D Display

Wir erstellen zunächst das Programm für das 4D Display. Dazu öffnen wir ein neues Genie-Projekt, wählen das verwendete Display und dieses Mal wollen wir eine Anzeige im Querformat realisieren.

Anschließend platzieren wir zwei Objekte vom Typ "Userled" und eine Anzeige vom Typ "Leddigits". Die Oberfläche sollte dann ungefähr so aussehen:

 

Bis auf die Position und die Grßße können wir alle Angaben belassen und müssen uns auch nicht um irgendwelche Events kümmern, denn wir werden ja nur ans Display senden. Anschließend erfolgt wieder der übliche Ablauf:

  • SD-Karte in den Kartenleser,
  • Progrmm hochladen,
  • SD-Karte ins Display umstecken.

Unsere Anzeige ist jetzt einsatzbareit und wir kümmern uns um das Arduino-Programm.

Wir beginnen mit einem neuen Sketch und als erstes binden wir die genieArduino-Bibliothek ein:

 

Wenn wir den Arduino starten, sollte sich das 4D Display in einem definierten Zustand befinden. Das können wir am besten durch einen kontrollierten Reset erreichen. Wenn wir den Arduino-Adapter nutzen, ist die Reset-Leitung des Displays mit dem IO-Pin D4 vom Arduino verbunden. Wenn Sie Ihre Anzeige über Jumperkabel anschließen können Sie natürlich auch jede andere digitale Leitung nutzen.

Im Programm definiere ich also Pin 4 als RESET-Leitung und in der setup-Funktion führen wir den Reset aus. Dazu legen wir die Leitung kurz auf High-Potenzial und ziehen sie dann wieder auf GND. Im Anschluss warten wir 3 Sekunden als Sicherheit.

Um die Genie-Bibliotheken nutzen zu können, brauchen wir ein Objekt der Klasse Genie, das wir in Zeile 5 erzeugen. In Zeile 14 starten wir wie gewohnt unsere serielle Schnittstelle mit der gewünschten Übertragungsrate. Hier könnten wir maximal 200.000 wählen, diesen Wert müssen wir dann aber auch in der Workshop4 IDE unter "Project/Comm Speed" einstellen. Die 4D Displays sind sogar in der Lage, 600.000 kbit/s zu realisieren, aber der Arduino nicht.

 

In Zeile 15 weisen wir dem Genie-Objekt die serielle Schnittstelle zu und damit ist es einsatzbereit.

Werfen wir einen Blick auf das Hauptprogramm:

 

Zeile 19: Die Zeile erklärt sich fast von selbst: wir setzen den Kontrast (Helligkeit) auf den maximalen Wert. Das ist nötig, weil wir das Display am Schluss langsam ausblenden lassen möchten.

Zeile 20 + 21: Mit der "WriteObject"-Methode senden wir Werte an ein Objekt. Die Konstante "GENIE_OBJ_USER_LED" ist in "genieArduino.h" definiert und identifiziert unsere userled-Objekte. Danach folgt eine ID für die erste LED und der Wert "0" für das Ausschalten. Das Gleiche führen wir in Zeile 21 für die 2. LED durch.

Zeile 24: Wir springen jetzt in eine for-Schleife und zählen von 0 bis 1000 hoch, mit einer Verzögerung von 10 ms (Zeile 25). Den aktuellen Wert schreiben wir wieder mit einem WriteObject-Befehl in das "leddigits"-Objekt.

Zeile 26 bis 30: Erreicht der Zähler den Wert 300 wird die 1. Led eingeschaltet, beim Wert 600 auch die 2. Led. Ich habe bewusst auf Gleichheit geprüft, denn bei einem ">=" würde der Befehl jedes Mal an das Display gesendet, wenn die Bedingung erfüllt ist, was ja nicht sein muss.

Zeile 34 bis 36: Ist der Wert 1000 erreicht und die Schleife beendet, wird das Display langsam ausgeblendet.

 
 

2. Beispiel: Senden umd Empfangen

Das Senden von Daten ist immer eine recht einfache Angelegenheit, weil wir den Zeitpunkt des Geschehens selbst bestimmen. Anders sieht es beim Empfangen aus, da es sich um asynschrone Ereignisse handelt und wir innerhalb des Arduino-Programms ja auch nicht wissen, um welche Art von Antwort es sich handeln könnte.

Hier kommt der eigentliche Vorteil der genieArduino-Bibliothek zum Tragen. Der Ablauf beim Empfang wird über 3 Maßnahmen realisiert:

1. Aufruf von DoEvents()

Die "DoEvents()-Methode" ermittelt alle empfangenen Ereignisse und segmentiert sie in einer Empfangs-Kette.

2. Erstellen eines Event-Handlers

Wenn beim Aufruf von DoEvents() kein Empfangsereignis ermittelt wurde, passiert nichts weiter. Wurde jedoch eins oder mehrere Ereignisse empfangen, ruft DoEvents automatisch einen EventHandler auf, den wir im Arduino-Programm erstellen müssen. In diesem Event-Handler kümmern wir uns um die Bearbeitung der Ereignisse.

Im Event-Handler rufen wir immer als 1. Methode DequeueEvent() auf. Damit entnehmen wir der Empfangskette ein Ereignis.

3. Zuweisung des Event-Handlers

Wir können den Namen des Event-Handlers frei wählen. Woher weiß die DoEvents-Methode dann aber, welchen Event-Handler sie aufrufen muss? Nun, das weiß sie gar nicht und deshalb müssen wir mit der Methode AttachEventHandler(name_des_Eventhandlers) dem Genie-Objekt die Methode bekanntmachen.

Mit diesem Hintergrundwissen können wir uns an die Erstellung des Programms machen. Wie immer beginnen wir mit der Oberfläche auf dem Display.

Wir erzeugen ein neues Projekt vom Typ ViSi Genie, wählen ein Anzeige im Querformat und platzieren dort eine "Coolgauge"-Komponenten und einen Slider. Da beide Komponenten die Position in Grad anzeigen sollen und der Bereich von -90 bis +90 reicht, ändern wir die Eigenschaften bei der Coolgauge-Komponente entsprechend (MinimumValue und MaximumValue). Intern arbeitet die Komponente allerdings mit Werten von 0 bis 180, die lediglich umgerechnet werden. Auch für den Slider setzen wir die Grenzwerte, da hier keine sichbare Skala verwendet wird, lauten die Werte Minvalue=0 und Maxvalue=180.

Das Ganze sollte jetzt folgendermaßen aussehen:

 

Einen Eventhandler brauchen wir nur für den Slider, der uns allerdings zwei Events anbietet: onChanged und onChanging. Das erste kennen wir bereits, es wird ausgelöst, wenn der Wert einer Komponente geändert wurde. Dieses Ereignis wird allerdings erst dann ausgelöst, wenn der Schieberegler wieder los gelassen wird. Wir wollen aber die Änderung permanent abfragen, also so lange sich der Finger auf dem Regler befindet und verschoben wird. Genau dafür brauchen wir das onChanging-Event. Damit sind wir im 4D Workshop schon wieder fertig und laden das Programm wie gewohnt ins Display.

Weiter zum Arduino-Programm:

 

Hier ändert sich nicht allzu viel gegenüber dem vorherigen Beispiel. Wir binden zusätzlich die Servo-Bibliothek ein, erzeugen ein Servo-Objekt und weisen dieser den Pin 9 zu. Neu sind die Zeilen 20 bis 22. Wir weisen dem genie-Objekt den EventHandler evtHandler zu, den wir noch erstellen müssen und ändern die Value-Eigenschaften der beiden Objekte GENIE_OBJ_SLIDER, index 0 und GENIE_OBJ_GAUGE, index 0 auf 90. Damit nehmen sie beide die Mittelstellung ein.

 

In der main-Loop machen wir nichts weiter, als ständig die Event-Queue abzufragen. Wir erinnern uns: wenn diese Methode feststellt, dass ein Ereignis aufgetreten ist, löst sie unseren EventHandler aus. Den wollen wir jetzt schreiben:

 

Wir erstellen zunächst ein Objekt vom Typ genieFrame, das unser Event verwaltet. Jetzt rufen wir die schon erwähnte DequeueEvent-Methode auf und speichern das Eregbnis in unserem Event-Objekt. In diesem Objekt findet sich eine Datenstruktur vom Typ reportObject, die uns alle notwendigen Informationen liefert:

  • cmd: Code für die Art des Kommandos
  • object: Object-Code für die Art der Komponente
  • index: Index der jeweiligen Komponente
  • data_msb: Höherwertiger Teil des Values
  • data_lsb: Niederwertiger Teil des Values

In einer verschachtelten if-Abfrage ermitteln wir, um welchen Befehl es sich handelt, von welcher Komponente mit welchem Indes er kommt und schließlich, welcher Wert übermitteln wird. Damit wir das MSB und LSB nicht von Hand zuordnen müssen, gibt es noch die Methode genie.getEventData(), die beide Bytes in eine Integer wandelt.

Jetzt schreiben wir den Wert mit der WriteObject-Methode in die Analoganzeige und schließlich zum Servomotor. Das Ergebnis ist genauso, wie wir es geplant hatten.

In Kürze werde ich diese Tutorial erweitern und wir werden uns anschauen, welchen 4DGL-Code das Programm erzeugt hat und somit ein wenig hinter die Kulissen schauen.