Terraduino Bugfix

Ich steuere ja mein Terrarium mit einem Eigenbau-Controller, dem TerraDuino. Der hatte immer das Problem, dass er ab und zu ausgefallen ist. Oder in der Früh sind die Lichter nicht angegangen. Sehr zum Frust des Lichts meines Lebens.

Nun hat sich herausgestellt, dass ich einen Bug in meinem Code hatte. Und zwar wegen der millis() Funktion der Arduino Platform. Der Fehler wird u.a. hier ganz gut beschrieben. Im Grunde hatte ich sogar mehrere Probleme:

Ich benutze den Rückgabewert von millis() (der die Millisekunden seit dem letzten reset zurückgibt), um in den verschiedenen Schedulerfunktionen zu schauen, ob sie loslaufen sollen. Dazu merke ich mir den letzten Wert von millis(), bilde dann die Differenz und wenn die grösser als der vorgegebene Timerintervall ist, geht er in die Funktion.

Der erste Fehler war, dass ich den Wert in einem signed long gespeichert habe. millis() gibt aber einen unsigned long Wert zurück. Wie man bei Arduino nachlesen kann, passt in den Wert die Zeit von knapp 50 Tagen, danach kommt es zu einem rollover, d.h. es fängt wieder bei Null an. Aber nicht bei mir. Da meine Variable ein signed long war, sprang er bei mir folglich schon nach der Hälfte der Zeit in den negativen Bereich, anstatt wieder bei Null anzufangen.

Das zum Einen. Dann hatte ich - da mir der Rollover bekannt war - extra eine Abfrage eingebaut und meine Variable auf 0 gesetzt, sobald der Rückgabewert von millis() kleiner als der letzte war. Da die Variable aber mit negativen Werten gefüllt war, hätte es 25 Tage gebraucht, bis er wieder in den positiven Bereich gekommen wäre. Und in der Zeit hat er nicht geschaltet.

Zum anderen war die Variable für den Intervall ein Integer. Auf der Arduinoseite steht sogar recht deutlich, dass man Berechnungen mit dem Rückgabewert von millis() nicht mit Integers machen soll, weil das sonst unvorhersehbare Ergebnisse haben kann. Ich denke in meinem Fall ist er auch ab und zu gecrashed. Da bin ich mir aber nicht sicher, weil ich eigentlich auch den Watchdogtimer verwende, der - wenn der Code hängt - nicht mehr resettet würde und eigentlich zu einem Reboot führen müsste. Tat er aber nicht. Entweder sind die Lichter nicht angegangen oder sie sind ausgegangen. Und zwar während der Controller noch lief (er hat eine Kontroll-LED, die durch die Software eingeschaltet wird, die müsste aus sein, wenn er wirklich tot wäre, war sie aber nie).

Nun, jetzt habe ich also sämtliche an den Timerberechnungen beteiligten Variablen auf unsigned long umgestellt und ich habe die Abfrage, ob der Rollover stattfand, entfernt. Der Gag ist nämlich, dass der Prozessor automatisch ein temporäres Bit an die Variable anhängt, wenn das Rechenergebnis nicht in die Variable passt (siehe Forumthread, den ich oben verlinkt habe). Dadurch kriegt man immer das richtige Ergebnis und muss sich um den Rollover gar nicht kümmern!

Das einzige, was ich noch nicht verstanden habe, warum der Compiler meinen alten Code klaglos compiliert hat, in dem ich eine Berechnung mit einem Integer und einem signed long gemacht habe. Hätte er mich ja drauf hinweisen können.

Gestern abend hab ich den Controller also upgedated, als die Barties schliefen und die Lichter aus waren. Nun wollen wir mal sehen, ob's das wirklich war.

#terrarium

↷ 22.07.2012