Erkenntnisse und Tipps

Arduino im Reisemobil – Teil 4

Dies ist unser erstes Arduino-Projekt und wir fassen hier einige Erkenntnisse zusammen. Vielleicht hilft es anderen Einsteigern, zumal sich beim Einsatz eines Arduino im Wohnmobil die Herausforderungen vermutlich ähneln.

Inhaltsverzeichnis der Arduino-Projektseiten

1 Zeitfresser

Folgende Aufgaben haben deutlich mehr Zeit benötigt als ursprünglich gedacht:

  • Das Zeichnen der Fahrzeugansichten mit Einarbeitung in Inkscape
  • Das Zeichnen der Bildschirmgrafiken mit Einarbeitung in GIMP
  • Änderung der Bildschirmgrafiken
    Während der Entwicklung sind Änderungen an den Bildschirmgrafiken häufiger als erwartet (Optimierungen, neue Funktionen etc.). Eine Änderung betrifft oft mehrere oder alle Bildschirme (z.B. Änderung an Hauptmenü-Buttons). Vor dem Exportieren der einzelnen Bildschirme müssen jeweils die richtigen Ebenengruppen in GIMP manuell sichtbar/unsichtbar geklickt werden. Insgesamt sind es weit über 100 Ebenen. Dieser Vorgang ist in GIMP nicht automatisierbar und bei manueller Ausführung zeitraubend/fehleranfällig.
  • Es wurde kein passendes Halbleiter-Relais am Markt gefunden. Die Erstellung einer eigenen Platine und Einarbeitung in KiCad wurde zu einem eigenen kleinen Projekt.
  • Die Suche nach einem passenden Gehäuse hat »gefühlt« zwei volle Tage gedauert. Viele Gehäuse waren etwas zu klein, die nächste Größe zu groß, aus Kunststoff, hässlich, nicht von oben zu öffnen, 4teilig oder hatten keine vernünftige Möglichkeit das Gehäuse im Fahrzeug zu befestigen. Das ausgewählte Gehäuse schien anfangs überdimensioniert, ist jedoch genau richtig!

2 Stromverbrauch reduzieren

Das System soll keinen zusätzlichen Strom verbrauchen. Dafür muss der Stromverbrauch minimiert und durch neue Steuerungsfunktionen (z.B. Kühlschrank-Timer) mindestens der Eigenverbrauch eingespart werden.

Der Arduino wird 99% der Zeit im Ruhezustand (Sleep) verbringen. In dieser Zeit soll der Verbrauch möglichst gering sein. Unten beschriebene Maßnahmen senken den Strom auf ca. 9 mA / 5 V. Gemessen wurde an einem Mega von Elegoo mit dem Testaufbau.

Mit dem o.g. DC-DC-Wandler (8-40V → 5V/5A) kommen wir auf unter 5 mA / 24 V. Der Eigenverbrauch gleicht sich aus, wenn durch die Steuerung der Kühlschrank nur 5 Minuten pro Tag weniger läuft.

Nachfolgend die umgesetzten Maßnahmen:

SLEEP_MODE_PWR_DOWN
Der Arduino Mega kann verschiedene Ruhezustände einnehmen. Das Projekt erlaubt den energiesparendsten Schlafzustand SLEEP_MODE_PWR_DOWN. Der Arduino wacht nur auf, um alle 5 Minuten die Sensoren auszulesen oder wenn ein Display eingeschaltet wird.

Ersparnis: ca. 30 mA

USB-Chip
Der USB-Chip (16U2-MU) dient der Kommunikation mit dem PC und wird im normalen Betrieb nicht benötigt. Verbindet man seinen RESET mit GND legt es den USB-Chip lahm und reduziert den Strom um ca. 11 mA. Verbindet man RESET erst nach dem Einschalten des Arduino mit GND (z.B. über digitalen Port), sind es nochmal 2-3 mA weniger.

RESET und GND findet man am ICSP Header des 16U2-MU beim USB-Anschluss. Wir verbinden RESET mit dem Steuerausgang für die Stromversorgung des Displays, um keinen digitalen Port dafür zu verschwenden. Das spart die 2-3 mA bei ausgeschaltetem Display, also in über 99% der Zeit.

Ersparnis: ca. 14 mA

Spannungsregler
Der Mega verwendet einen linearen Spannungsregler (z.B. AMS1117), was nicht gerade energieeffizient ist.

Wir speisen 5V über den 5V-Pin der Pinleiste von einem DC-DC-Wandler ein und löten den Spannungsregler ab. Er befindet sich direkt neben der Netzteilbuchse.

Ersparnis: ca. 4 mA.

LEDs
Folgende LEDs können entfernt werden, da sie im Betrieb nicht erforderlich sind: L-LED (Pin13), PWR-LED, RTC-Modul PWR-LED

Ersparnis: ca. 9 mA (3 x 3 mA)

Sensoren
Über einen MOSFET-Schalter schaltet der Arduino den Strom der Sensoren im Sleep-Mode (Ruhezustand) ab.

Ersparnis: ca. 6 mA

Nextion Display
Das Nextion-Display verbraucht laut Datenblatt ca. 15 mA im Standby-Mode. Das Display ist dann dunkel, kann jedoch per Berührung eingeschaltet werden.

Wir verwenden einen Taster beim Display, über den der Arduino die Stromversorgung des Displays mittels MOSFET-Schalter einschaltet. So verbraucht das Display keinen Strom in ausgeschaltetem Zustand.

Ersparnis: ca. 30 mA (2 x 15 mA)

DC-DC-Wandler
Ein externer, geschalteter Spannungswandler ersetzt den linearen Spannungsregler. Wir speisen den Strom direkt in die Boardspannung an Pin +5 V ein.

Der o.g. DC-DC-Wandler 8-40 V → 5 V / 5 A hat weniger als 1,5 mA / 24 V Ruhestrom!

3 Real Time Clock (RTC)

Das Echtzeit-Modul basiert auf dem DS3231SN und liefert die Systemzeit.

Viele dieser Module haben eine Batteriehalterung für Knopfzellen, damit bei Stromausfall die Zeit und das Datum weiterlaufen und nicht neu eingestellt werden müssen.

Brandgefahr
Brandgefahr: RTC 3231 mit Batterie (CR2032) UND LadeschaltungManche Module verfügen über eine Ladeschaltung für eine wiederaufladbare Knopfzelle LIR2032 (Akku!). Kommt so ein Modul jedoch mit einer günstigeren CR2032 (Batterie!) oder setzt man versehentlich selbst eine CR2032 ein, kann das zu einem Brand führen. Wird die nicht aufladbare Batterie geladen, bläht sie sich früher oder später auf und kann explodieren. Das Bild rechts zeigt so ein gefährliches Modul, das mit Ladeschaltung und CR2032 geliefert wurde.

Abhilfe: Unterbrechung der Ladeschaltung oder niemals eine Batterie verwenden

Alternative: Mit einem Kondensator puffern (ohne Knopfzelle)

Kondensator
RTC3231 mit KondensatorWir verwenden ein Modul mit Ladeschaltung, haben jedoch den Batteriehalter durch einen Kondensator (1 F / 5.5 V) ersetzt. Die Ladeschaltung hält den Kondensator geladen, der bei Stromausfall für 1-2 Tage die Uhr versorgt. Das reicht völlig aus.

4 DS18B20

Der Temperatursensor DS18B20 wird über den 1-Wire-Bus angeschlossen. Mehrere Sensoren am gleichen Bus werden über ihre Seriennummer adressiert. Beim Tausch eines defekten Sensors muss deshalb die Seriennummer in der Software geändert werden. Das möchte man nicht.

Hängt man jeden DS18B20 an einen eigenen 1-Wire-Bus (je ein digitaler Port), kann er über seinen 1-Wire-Bus adressiert werden und die Seriennummer spielt keine Rolle.

5 Referenzspannung

Spannungen misst der Arduino über das Verhältnis einer bekannten Referenzspannung zu einer unbekannten Spannung. Die Referenz entspricht der Zahl 1023 und über den Messwert (0 – 1023) lässt sich die unbekannte Spannung leicht berechnen.

Problem: Schwankende Referenzspannung
Schwankt jedoch die Referenzspannung, stimmt sie nicht mehr mit ihrem Wert in der Software überein und die gemessene Spannung wird falsch berechnet. Die voreingestellte Referenzspannung ist die Versorgungsspannung (Vcc).

Der verwendete DC-DC-Wandler liefert eine ausreichend konstante Spannung. Muss der DC-DC-Wandler bei einem Defekt getauscht werden, hat der neue Regler vermutlich eine leicht abweichende Spannung und die Software müsste angepasst werden. Eine Abweichung von 0,1 V würde ohne Softwareanpassung bei der Berechnung der Batteriespannung ca. 0,5 V ausmachen. Softwareänderung bzw. falsche Batteriespannung möchte man nicht.

Externe Referenzspannung AREF
An Pin AREF (s. Bild) kann eine externe Referenzspannung eingespeist werden. Diese ist jedoch niedriger als Vcc (sofern mit Vcc versorgt) und schränkt dadurch den messbaren Spannungsbereich ein. Das möchte man auch nicht.

Lösung: Berechnung der Vcc
Spannungsreferenz mit 4,096 V (LM 4040 BIM3-4.1) an einen Analogeingang. Mit dem eingelesenen Wert (z.B. 837) kann die aktuelle Referenzspannung (Vcc = 4,096 V * 1023 / 837) berechnet werden. Über die so ermittelte Vcc (Referenzspannung) können die anderen Spannungen berechnet werden. Spannungsmessungen sind so bis Vcc möglich und stimmen auch, wenn sich Vcc ändert.

Hinweis: Eine genauere Spannungsmessung wird erreicht, indem der Analogeingang 5x hintereinander (1 ms Abstand) ausgelesen und der Mittelwert gebildet wird.

6 Zeitberechnungen

Der Programmablauf basiert auf Zeitberechnungen mit Einschaltzeiten (Display, Sensoren), Abschaltzeiten (Display) oder Zeitabständen (DHT22, DS18B20). Die Funktion millis() liefert Millisekunden für diese Berechnungen. Dabei ist zu beachten:

  • Beim Einschalten bzw. einem Reset des Arduino starten die millis() bei 0
  • Während des Ruhezustands SLEEP_MODE_PWR_DOWN werden die millis() nicht hochgezählt
  • Nach ca. 50 Tagen Dauerbetrieb hat millis() einen Zählerüberlauf und fängt wieder bei 0 an. Bei 99 % Ruhezustand dauert das 5.000 Tage! Ein Zählerüberlauf ist per Software leicht zu handhaben.
  • Die Zeit-Variablen müssen unsigned long sein

Hinweis: Für Zeitberechnungen, bei denen dazwischen ein Ruhezustand eintreten kann, nehmen wir die Zeiten der RTC.

7 Nextion Display

In Foren wird diskutiert, wie sich Probleme bei der Umschaltung der Display-Seiten lösen lassen. Man fragt sich: Initiiert der Arduino die Umschaltung der Display-Seite nachdem ihn das Display über einen Tastendruck informiert hat oder schaltet das Display bei einem Tastendruck selbst um und informiert den Arduino lediglich über die Umschaltung.

Unser Arduino kennt die angezeigte Display-Seite nicht. Er schickt einfach die Messdaten und den Rest regelt das Display unabhängig. Schickt das Display geänderte Einstellungen zum Arduino, spielt die angezeigte Seite auch keine Rolle, da jede Einstellung mit eindeutiger ID gesendet wird. Die Einstellungen werden mit Software auf dem Display geändert und mit SET zum Arduino geschickt.

Es gibt sicherlich Anwendungen, bei denen der Arduino die angezeigte Display-Seite kennen muss. So lange es nicht technisch erforderlich ist, sollten wechselseitige Abhängigkeiten vermieden werden.

8 Aktualisierungsintervall & Antwortzeiten

Eines der Projektziele ist, bei eingeschaltetem Display die Messwerte in möglichst kurzen Zeitabständen zu aktualisieren. Bei den ersten Tests dauerte die Aktualisierung ca. 7 s. Durch Parallelisierung und Verbesserung zeitkritischer Vorgänge sind es nur noch ca. 2 s. Schneller sind die DHT22 Sensoren nicht auslesbar.

Mit folgenden Maßnahmen konnte das erreicht werden:

a) Sensoren schneller auslesen
Der DS18B20 braucht 750 ms vom Start einer Messung bis die Daten bereitstehen. Normalerweise wartet die verwendete Library auf die Daten, so dass der Arduino 750 ms blockiert ist. Da jeder DS18B20 einen eigenen 1-Wire-Bus hat, dauert es 2.250 ms (3x 750 ms).

Die Library besitzt jedoch eine Methode, die nur den Messvorgang startet. Danach kann das Programm andere Dinge erledigen und 750 ms später die Daten abholen. Um die Einhaltung des Timings muss man sich bei dieser Methode selbst kümmern. So können auch alle DS18B20 parallel gestartet werden.

ds1.setWaitForConversion(false);
ds1.requestTemperatures();

Nach 750 ms:

dstemp[0] = ds1.getTempCByIndex(0);

Die DHT22 können nur alle 2.000 ms ausgelesen werden. Die Messung der DS18B20 startet deshalb 750 ms bevor auch die DHT22 wieder ausgelesen werden können.

b) Übertragungsrate erhöhen
Die Zeitdauer der Datenübertragung zum Display soll verkürzt werden. Theoretisch könnte man die Datenrate erhöhen. Eine höhere Datenrate ist jedoch empfindlicher gegenüber Störungen. Solange mit anderen Optimierungen das Ziel erreicht wird, bleibt die Datenrate bei 9.600 Bit/s.

c) Nextion Display: Datenmenge reduzieren
Alternativ zur Erhöhung der Datenrate kann die Menge der zu übertragenden Daten reduziert werden. Das Nextion Display erwartet die Daten folgendermaßen:

seitenname.objektname.attribut=     (Beispiel: home.t0.txt=“21.1“)

Daraus folgt:

  • Je kürzer »seitenname« und »objektname« gewählt werden, desto weniger Zeichen müssen übertragen werden. Das verkürzt die Übertragungszeit. Die Attribute sind vorgegeben.
  • Wird das gleiche Objekt (z.B. Temperatur Wohnkabine) auf verschiedenen Seiten angezeigt, muss es mehrfach übertragen werden. Das erhöht die Übertragungszeit erheblich. Viele Messwerte sind auf 2 oder 3 Seiten zu sehen.

Vermeidung mehrfacher Übertragungen auf verschiedene Seiten
Man erstellt mit dem Nextion Editor eine Seite, auf die von keiner anderen Seite verlinkt wird. Auf dieser »versteckten« Seite legt man alle Objekte einmal an. Der Name der versteckten Seite ist »d«, wie Daten. »d« ist kurz und spart Übertragungszeit. Beim Übertragen der Sensordaten sendet der Arduino jeden Wert nur genau einmal auf Seite »d«. Seite »d« ist der Zwischenspeicher, aus dem sich alle anderen Seiten bedienen.

Im Nextion Editor kann man auf Seiten sogenannte »Timer« anlegen. Diese Timer werden in einem einstellbaren Intervall aufgerufen und der im Timer enthaltene Code wird ausgeführt.

Jede »sichtbare« Seite erhält einen Timer mit 1 ms, der nach dem Umschalten auf diese Seite nach 1 ms startet. Sein Programmcode kopiert sofort die benötigten Daten von Seite »d« auf die neu angezeigte Seite und stellt den Timer auf 100 ms. Empfängt Seite »d« neue Daten vom Arduino, werden diese spätestens nach 100 ms auf die angezeigte Seite kopiert. Nach der ersten schnellen Aktualisierung (1 ms) ist ein Aktualisierungsintervall von 100 ms mehr als ausreichend. Beim Verlassen der Seite setzt man den Timer wieder auf 1 ms.

Ausschnitt aus dem Programmcode für den Timer auf der Seite »Home«

refresh.tim=100
v0.txt=d.v0.txt
v0.pco=d.v0.pco
v1.txt=d.v1.txt
v1.pco=d.v1.pco
t8.txt=d.t8.txt
h8.txt=d.h8.txt
t9.txt=d.t9.txt
h9.txt=d.h9.txt

d) Übertragung auf 2 Nextion Displays parallelisieren
Sind beide Displays eingeschaltet wird die Datenübertragung quasi parallelisiert. Das reduzierte die Übertragungszeit von 2x 900 ms auf zusammen 1.100 ms.
Dazu werden die Daten in Blöcke gruppiert (Temperaturen DHT22, Temperaturen DS18B20, Luftfeuchten DHT22 …) und jeder Block wird zuerst auf beide Displays geschickt, bevor der nächste Block gesendet wird.

e) Einschalten des Nextion Displays
Nach dem Einschalten eines Displays würde es ca. 2.900 ms dauern bis alle aktuellen Messwerte eingetroffen sind. 2.000 ms um die Sensoren auszulesen und 900 ms für die Übertragung. Das dauert zu lang!

Deshalb werden sofort nach dem Einschalten des Displays die Werte der letzten Messung übertragen, die höchstens 5 Minuten alt ist. Diese erste komplette Datenübertragung dauert 900 ms. Die zuerst gesendeten Werte treffen jedoch schon nach ein paar Millisekunden ein. Daher überträgt der Arduino die auf der Startseite angezeigten Werte zuerst.

Weiterhin sind die Daten bei der Übertragung so sortiert, dass die Zahlen auf der Startseite in einer für das Auge angenehmen Reihenfolge erscheinen. Dies ist gerade beim Einschalten relevant, da sich die Werte auf einer leeren Fläche aufbauen und somit die Reihenfolge optisch wahrnehmbarer ist.

Durch die Maßnahmen ist die gefühlte Einschaltverzögerung deutlich unter 1 s, obwohl dem Display 280 ms zum Booten gegeben werden, bevor der Arduino erste Daten schickt.

Etwa 3 s nach dem Einschalten werden aktuelle Messwerte angezeigt, was durch das Einschalten der MAN-Scheinwerfer auf »Home« signalisiert wird.

9 Timing der Software

Derzeit sieht das Timing für ein Aktualisierungsintervall der Displays etwa so aus:

0           Datenübertragung starten
900 / 1100  Datenübertragung fertig (1 / 2 Displays)
warten…
1250        DS18B20 initialisieren
warten…
2000        alle Sensoren auslesen
0           Datenübertragung starten

10 Übertragungsfehler vom Nextion Display zum Arduino

Vom Display zum Arduino werden die Einstellungen (Timer, Systemzeit, Display Abschaltzeit etc.) und Keep Alive Pakete übertragen. Jede Interaktion am Display sendet ein »ka« (Keep Alive). Der Arduino schaltet ein Display ab, wenn länger als die eingestellte Abschaltverzögerung kein »Keep Alive« von diesem Display empfangen wurde.

Verlorene Zeichen
Bei der Übertragung vom Display zum Arduino gehen manchmal 1-2 Zeichen eines Befehls verloren. Zeitlich fällt das mit dem Auslesen der Sensoren zusammen. Vermutlich schaltet eine Sensor-Library den Interrupt ab, um das Timing zum Auslesen einhalten zu können. Es wurde eine pragmatische Lösung gewählt, bei der die Befehle nach einigen Millisekunden einfach noch einmal geschickt werden. Der Abstand ist so gewählt, dass mindestens ein Befehl korrekt übermittelt wird. Unvollständige Befehle werden verworfen, die doppelte Ausführung eines Befehls ist kein Problem, da nur Einstellungen übertragen werden.

11 Temperaturabhängige zweistufige Lüftersteuerung mit 12 V und 24 V

Das Möbel, in das der Kühlschrank eingebaut ist, hat einen zusätzlichen Lüfter an der Frontseite. Bisher schaltete dieser Lüfter mit dem Kühlschrankkompressor ein und aus. Das geht besser, wie Messung M4: Möbeltemperatur zeigt.

Zweistufige Lüftersteuerung über Temperaturdifferenz mit Hysterese

Jetzt steuert der Arduino den Lüfter anhand der Temperaturdifferenz zwischen der Warmluft im Kühlschrankmöbel und der zur Verfügung stehenden Kaltluft. Der Lüfter hat einen Spannungsbereich von 12-28 V. Durch das Umschalten der Lüfterspannung zwischen 12 V und 24 V läßt sich eine Lüftersteuerung mit 2 Lüfterstufen realisieren. Die Lüftersteuerung kommt so ohne PWM (Pulsweitenmodulation) aus.

Stufe 1 (12 V): leiser, geringere Kühlleistung, reduzierter Stromverbrauch
Stufe 2 (24 V): lauter, bessere Kühlleistung, höherer Stromverbrauch

Tabelle der Temperaturdifferenzen für die Steuerung des Möbellüfters
Die Tabelle zeigt die Bedingungen zum Ein- und Ausschalten der jeweiligen Stufe des Lüfters. Nachts, wenn der Kühlschrank über den Timer abgeschaltet ist, soll der Lüfter eher leiser laufen. Tagsüber soll er schneller kühlen.

    Δt: Warmluft – Kaltluft
tmax: Kühlschranktemperatur, bei deren Überschreitung der Kühlschrank einschaltet, obwohl der Timer = AUS ist

Status
Timer
Status
Kühlschrank
Stufe 1 (12 V)
AUS   |   EIN
Stufe 2 (24 V)
AUS   |   EIN
EIN AUS 1,0°   ≥   Δt   ≥   1,3° 1,5°   ≥   Δt   ≥   2,0°
EIN EIN 1,0°   ≥   Δt   ≥   1,3° 1,2°   ≥   Δt   ≥   1,5°
AUS AUS 0,5°   ≥   Δt   ≥   1,3° 1,5°   ≥   Δt   ≥   2,5°
EIN (tmax) 0,5°   ≥   Δt   ≥   1,3° 1,5°   ≥   Δt   ≥   2,5°

Erläuterungen
Der Status des Timers und der aktuelle Status des Kühlschranks beeinflussen die Schalttemperaturen der Lüfterstufen. Die Prüfung der Bedingungen erfolgt alle 5 Minuten.

Vorteile der Lüftersteuerung per Temperaturdifferenz:

  • Der Lüfter läuft genau dann, wenn gekühlt werden kann/soll, also unabhängig vom Kompressor.
  • Der Lüfter schaltet auch ein, wenn die Kaltluft kühler wird und das Möbel weiter abgekühlt werden kann.
  • Ist die Warmluft im Möbel kühler als die Kaltluft, schaltet der Lüfter nicht ein.

Warum verschiedene Schalttemperaturen?
Nachts (Timer=AUS bzw. EIN(tmax)) soll der Lüfter generell leiser sein und Stufe 2 wird erst bei höherer Δt aktiviert. Dafür soll Nachts das Möbel kühler sein (Δt kleiner), da der Kühlschrank normalerweise nicht läuft (nur wenn Kühlschrank zu warm, also tmax überschritten).

Tagsüber wird bei laufendem Kühlschrank die Stufe 2 früher eingeschaltet, um die zu erwartende Wärme schneller abzuführen.

Die vielen verschiedenen Schaltemperaturen sehen nach Programmieraufwand aus. Es sind jedoch nur 4 Zeilen mehr Programmcode und 2 Zeilen zum Deklarieren von 2 zusätzlichen Variablen.

Spannung für Stufe 1 und Stufe 2
Die Spannung der Stufe 2 entspricht dem Bordnetz der Wohnkabine. Die reduzierte Spannung der Stufe 1 kommt von einem kleinen einstellbaren DC-DC-Buck-Konverter. Über das Poti zum Einstellen der Ausgangsspannung kann die Geschwindigkeit der Stufe 1 vorgegeben werden.

Stufe 1 wurde so eingestellt, dass der Lüfter kaum hörbar ist (Lüfterspannung ca. 13 V). Bei verschiedenen Außentemperaturen wird sich zeigen, ob die Geschwindigkeit der Stufe 1 gut gewählt ist.

Die Software schaltet zuerst die eine Spannung ab und dann die andere ein. Die Ausgänge der beiden Stufen gehen über Dioden zum Lüfterkabel.

12 Speicherbedarf Arduino

Mangels Erfahrungswerten galt eine Hauptsorge dem Speicherbedarf für Programm und Variablen. Das Programm hat ca. 1.400 Zeilen Code und der Compiler zeigt folgende Resultate:

Sketch uses 24262 bytes (9%) of program storage space. Maximum is 253952 bytes.
Global variables use 1452 bytes (17%) of dynamic memory, leaving 6740 bytes for local variables. Maximum is 8192 bytes.

Verwendete Libraries

Arduino.h
avr/sleep.h
Wire.h
RTClib.h (https://github.com/adafruit/RTClib)
DHT.h
Adafruit_Sensor.h
OneWire.h
DallasTemperature.h

Weiter zu Teil 5:  Tools und Links

„Miß alles, was sich messen läßt,
und mach alles meßbar, was sich nicht messen läßt.“
(Archimedes, 287 – 212 v. Chr.)