Das 2. Genie-Projekt (Temperaturmessung mit Arduino)


 

Im 2. Beispiel werden wir eine kleine Temperaturerfassung realisieren. Dabei kommt als Host ein Arduino UNO zum Einsatz, das Prinzip lässt sich aber auf jeden anderen Host-Controller übertragen. Im Grunde haben wir ja sogar schon mit externer Kommunikation gearbeitet, denn das GTX-Tool ist nichts anderes als eine Host-Applikation auf dem PC.

Der Arduino-Hostcontroller

Wir nutzen für die Temperaturmessung einen DS18B20 von Dallas Semiconductor. Dieser Sensor gibt seinen Wert über die digitale One-Wire-Schnittstelle an den Arduino aus. Auf das Programm dazu werde ich nicht detailliert eingehen, weil hier das Touchpanel im Fokus steht.

 

Bevor wir beginnnen, möchte ich noch darauf hinweisen, dass es für den Arduino eine sehr ausgereifte Bibliothek von 4D Systems gibt, die ich im nächsten Kapitel vorstellen werde und die uns den Ablauf erleichtert. Es ist aber von Vorteil, zu wissen, was im Hintergrund abläuft. Das folgende Beispiel soll das allgemeine Verfahren klar machen und Anwendern anderer Mikrocontroller helfen.

Die Kommunikation zwischen dem 4D Display und dem Arduino läuft über das Interface-Board, das auf der einen Seite über das Flachbandkabel mit dem Display und auf der anderen Seite mit den Jumpern am Arduino angeschlossen wird. Noch einfacher geht es mit dem speziellen 4D Systems Arduino Adapter der Ihnen den Einsatz von einzelnen Jumpern erspart, die meist nicht so gut in den Kontakten halten.

Damit würde das Ganze dann so aussehen:

 

Der Adapter ist durchgängig, d. h. Sie können auch weitere Shields auf den Adapter aufstecken. Über Jumper können die entsprechenden Leitungen für die serielle Schnittstelle ausgewählt werden und es stehen 2 Steckplätze "H1" und "H2" zur Verfügung, um das Display selbst und den Programmieradapter aufzustecken.

Mein Aufbau sind dann wie folgt aus:

 

Ganz unten befindet sich ein Arduino UNO, darüber der 4D-Adapter und ganz oben eine I/O-Erweiterung für Sensorelemente. Das 4D Display ist über das Flachbandkabel mit dem Programmieradapter verbunden und von dort geht es zum Adapter. So kann ich die Umsteckerei auf ein Minimum reduzieren.

Der Arduino-Code

Der DS18B20 wird mithilfe einfacher Kommandos über den "One-Wire-Bus" gesteuert. Für die Kommunikation zwischen Arduino und DS18B20 gibt es die "OneWire"-Bibliothek, die uns das Leben etwas einfacher macht.

 

Zunächst brauchen wir einige Variablen für die Adresse des DS18B20, zum Schreiben an das 4D Display und für das Messergebnis.

Im setup-Teil des Sketches initialisieren wir die serielle Schnittstelle und mit der Methode search des OneWire-Objektes suchen wir nach Busteilnehmern, deren ROM-Daten wir im Array adr speichern.

 

In der loop-Schleife des Sketches führen wir maßgeblich zwei Schritte aus, die wir jeweils mit einem Reset ds.reset() und der Auswahl ds.select() beginnen. Der select-Methode übergeben wir dabei als Adresse die vorher ermittelten ROM-Daten. Nach dem Reset und der Auswahl wird der eigentlich Befehl an den Sensor geschrieben. Im obersten Block in Zeile 17 ist das der Befehl 0x44, der eine Wandlung einleitet, die ca. 750 ms dauert. Um nicht in einer Schleife pollen zu müssen, warten wir einfach 1 Sekunde und schicken dann den nächsten Befehl 0xBE (Read Scratchpad). Das Scratchpad ist ein Array mit 9 Werten, von denen wir nur die ersten beiden, nämlich die Temperaturdaten, benötigen. Mit ds.read() lesen wir das Array bei 0 beginnend bis zum Ende oder bis wir wieder einen Reset ausführen.

Wir haben jetzt die Werte des MSB und LSB gespeichert und das Format sieht folgendermaßen aus:

 

Die oberen 4 Bit des MSB sind bei negativen Werten alle "1", bei positiven "0". In der 2. Hälfte des MSB kommt noch einmal ein Vorzeichenbit und dann folgen die Nutzdaten. Das LSB enthält nur Daten, allerdings werden die unteren 4 Bit für die Nachkommastelle verwendet. Wir haben also eine Auflösung von 1/16 Grad oder 0,0625.

Der Einfachheit halber werden wir in diesem Beispiel die Nachkommawerte nicht nutzen und auch nur mit positiven Werten arbeiten, weil ich hier im Büro keine Frostwerte erwarte und man ja die Änderung auch noch sehen soll. Aus diesem Grund können wir die Daten in einem Byte zusammenfassen.

 

Zunächst schieben wir das MSB um 4 Stellen nach links und das LSB um 4 Stellen nach rechts und addieren die Werte, dann in der Variablen tempData. Wir haben jetzt die mittleren beiden Nibbel in einem Byte zusammengefasst und erhalten so ganzzahlige Temperaturen mit einer Auflösung von 1 °C. Für die Demonstration der Übertragung soll das reichen.

Schließlich müssen wir die Messwerte noch an das Display senden, dazu nutzen wir eine eigene Funktion, auf die wir später noch näher eingehen werden.

Oberfläche auf dem 4D Display

Für unsere Temperaturanzeige nutzen wir zum einen das Thermometer-Objekt (wer hätte das gedacht!), aber wir wollen den Wert auch noch konkret ausgeben und dazu nutzen wir eine LED-Anzeige. Außerdem erweitern wir unser Display um einen Button, der nicht wirklich notwendig ist, aber damit werden wir die Kommunikation im umgekehrten Fall also vom 4D Display zum Arduino testen. Mit ihm starten und stoppen wir die Messung. Wir bauen diese Funktionalität schon einmal in die Oberfläche ein und ergänzen den notwendigen Code im Arduino-Programm dann später.

Das Ganze sieht jetzt wie folgt aus:

 

Zu den einzelnen Objekten. Beginnen wir mit dem Thermometer:

 

Die Eigenschaften sind im Grunde selbsterklärend, mit Max und Min wählen wir den Startpunkt und die maximale Anzeige. Hier wählen wir 50 und 0. Offset ist nicht ganz so selbsterklärend, damit bestimmen wir die Breite der Thermometersäule. Mit Small Step und Step definieren wir das Raster der Messskala und dann können wir im Bereich "Value" noch ein kleines Symbol definieren, das die Höhe der Anzeige verdeutlicht. Dazu wähle ich ein kleines gelbes Dreieck. Es wäre auch noch ein Setpoint möglich, den wir aber zumindest in diesem Beispiel nicht nutzen werden.

Nun zur Digitalanzeige. Sie ist vom Typ LED Digits. Die Eigenschaften sind:

 

Hier interessieren uns nur die Anzahl der Nachkommastellen Decimals und die Anzahl der angezeigten Stellen Digits. Wir setzen sie auf 0 und 3.

 

Der Button ist ein 4D Button-Objekt und vom Typ Button01 (runder Knopf mit Leuchtkranz). Es ist kein Taster, deshalb ist die Momentary-Eigenschaft auf "No" gesetzt und der Style ist rot.

Jetzt fehlen uns noch die Events:

  • Button: Der Button sendet ein Ereignis an den Arduino, deshalb wählen wir als Handler "ReportMessage" für sein OnChanged-Event.
  • Thermometer: Das Thermometer bekommt seinen Wert vom Arduino, deshalb brauchen wir hier keinen Event-Handler
  • LED-Anzeige:Hier gilt das Gleiche wie beim Thermometer-Objekt.
 

Damit wären wir auf der Displayseite fertig. Mit der SD-Karte im PC drücke ich auf Build und speichere die Grafikdaten auf der Karte ab. Danach trenne ich das Display vom USB-Anschluss, füge die Karte in den Slot, starte das Display neu und stelle fest, das alles an seinem Platz ist. Der Button scheint auch zu funktionieren, denn er wechselt beim Drücken sein Aussehen.

Probelauf im GTX

Bei einer geteilten Applikation ist es in jedem Fall sinnvoll, alle Teile für sich allein zu testen. Das werden wir auf jeden Fall für das 4D Display durchführen. Dabei interessieren uns die Fragen:

  1. Wie sieht die Report-Message, die wir nach Drücken des Buttons erhalten, ganz konkret aus?
  2. Empfängt die LED-Anzeige die Daten richtig?
  3. Empfängt das Thermometer-Objekt die Daten und werden diese richtig dargestellt?

Wichtig: GTX ist kein Simulator, sondern eine Testumgebung für 4D Displays, d. h. die Anzeige muss mit der seriellen Schnittstelle verbunden sein. Dann sehen wir den folgenden Bildschirm:

 

Neben dem Testen der Funktionen sehe ich im GTX-Tool auch die seriellen Kommandos, die für die jeweilige Aktion zum Einsatz kommen. Ich wähle einen Wert von 30 für die LED-Anzeige und 20 für das Thermometer.

Wichtig! Die Werte für das Thermometer-Objekt werden nicht absolut dargestellt, sondern als Offset zum Minimalwert. Hätten Sie also einen Temperaturbereich von -20 bis +125 °C und geben den Werten 20 ein, dann erhalten Sie eine Anzeige von 0.
 

Im rechten Fenster kann ich von oben nach unten die Kommandos für die folgenden Aktionen erkennen:

  • Der Button wurde das erste Mal gedrückt, d. h. eingeschaltet: Es wird der Code 07 1E 00 00 01 18 gesendet.
  • Der Button wurde wieder gedrückt und ausgeschaltet: Der Code ist identisch bis auf die beiden letzten Bytes, die 00 zeigt uns das Ausschalten an, die Prüfsumme hat sich dadurch natürlich auch geändert.
  • Jetzt setzen wir die LED-Anzeige auf den Wert "30": 01 0F 00 00 1E 10
  • Und am Schluss kümmern wir uns noch um das Thermometer: 01 12 00 00 14 07 Anstelle des Object-Codes "OF" für die LED-Anzeige finden wir jetzt "12" für Thermometer und anstelle des Wertes "1E" (30) übertragen wir hier "14" (20).

Jetzt können wir unseren Arduino-Code vervollständigen. Zunächst schreiben wir die Funktion zum Senden der Messwerte. Den Funktionsprototypen haben wir schon im ersten Teil des Programmes gesehen.

Wir übergeben der Funktion den Objektcode für das Thermometer bzw. die LED-Anzeige und den Messwert selbst. Noch einmal als Hinweis: es geht hier nicht um eine besonders elegante Lösung, sondern um einen Weg, der die Abläufe verdeutlicht.

In der Funktion selbst übergeben wir die Werte dem Array und berechnen die Prüfsumme. Die setzt sich einfach aus einer Exklusiv-Oder-Verknüpfung aller Datenbytes zusammen. Am Schluss senden wir das Array über die serielle Schnittstelle. Da das 4D Display die Daten im reinen Zahlenformat und nicht als ASCII erwartet, nutzen wir die Serial.write()-Methode.

Sendetechnisch wäre damit schon alles erledigt, doch wir erwarten ja auch eine Antwort vom 4D Display und darauf müssen wir vorbereitet sein. Was das Ganze ein wenig komplizierter macht ist die Tatsache, dass das Display uns ja auch nach einem Empfang Daten zurücksendet: die 0x06 als ACK im Erfolgsfall und die 0x15 als NAK falls ein Fehler aufgetreten ist.

Wenn wir aber nicht genau wissen, wie viele und welche Zeichen sich im Empfangspuffer befinden können, ist der beste Weg, die Anzahl der empfangenen Bytes bei jedem Aufruf von if Serial.available() aufzurufen. Die erhalten wir ja schließlich als Rückgabewert eben dieser Methode.

 

Wir ermitteln also die Anzahl der empfangenen Bytes und speichen sie in der Variablen rxCount. Anschließend lesen wir jedes Byte. Das ist wichtig, damit der Zeiger wieder auf den Anfang des Puffers gestellt wird.

Wir reagieren nicht auf ACK-Daten oder NAK-Daten, sondern ob es sich um eine "ReportMessage" handelt, was wir durch die 0x07 erkennen. Ist das der Fall lesen wir die fünf restlichen Bytes in den Puffer und prüfen dann, ob es sich um das Button-Objekt handelt 0x1E und ob diese eine 0x01 (einschalten) oder 0x00 (ausschalten) sendet. Beim Einschalten wird lediglich das active-Flag gesetzt und die Messungen werden aktiviert, beim Ausschalten wird das active-Flage auf false gesetzt, die Messung und das Senden also deaktiviert, vorher aber noch eine "111" ans Display geschickt, damit wir auch sehen, dass die Messung nicht läuft.

Damit haben wir gesehen, wie die Kommunikation zwischen Host-Controller und 4D-System "zu Fuß" ablaufen würde. Im nächsten Kapitel machen wir uns das Leben einfacher und nutzen die Arduino-Bibliotheken.