ich habe dieser Tage ein einfaches Thermostat gebaut mit einem Atmega88 und nem DS18B20.
Das Thermostat hat eine Hysterese damit das Aggregat nicht zu oft anspringen muss.
Als Parameter habe ich eine Konstante deklariert und einen Wert zugewiesen:
1
constuint32_thysterese=(15*60*1000);//Hysterese in ms
Beim Trockentest ging noch alles, da habe ich den Wert auf 10000 gesetzt, aber bei Verwendung obiger Zeile kam offenbar ein Wert raus, der nicht 900000 Betrug, da nie geschalten wurde.
Ich benutze als IDE Visual Studio Code mit Platformio und dem Arduino Framework.
Für Konstanten habe ich sonst immer Makros bzw. einfache Präprozessoranweisungen genutzt, aber ich dachte mir wenn man eine Konstante deklariert, dann weiß man wenigstens genau, was die für einen Typ hat, das ist am Ende transparenter und sicherer.
Meine Frage ist jetzt, wieso hat die Zuweisung so nicht funktioniert? Ich würde das gerne verstehen.
... und wenn Du die Compiler-Warnungen eingeschaltet hättest (etwas, was man immer machen sollte, -Wall, mindestens), hätte dir der Compiler hier eine Warnung bezüglich des Integer-Overflows ausgeworfen.
Der Compiler rechnet mit int, wenn man ihm bei numerischen
Konstanten
nichts anderes mitteilt. Auf Deinem AVR-Arduino ist int ein
16-Bit-Datentyp.
Ändere Deine Initialisierung mal zu
const uint32_t hysterese = (15 * 60 * 1000L); //Hysterese in ms
(Das Suffix L weist den Compiler an, mit long zu rechnen. Analog gibt
es auch das Suffix UL, das hat unsigned long zur Folge).
Ah, ok. Also damit hab ich nicht gerechnet. Klar dass ein int beim Atmega 16-bit hat, aber ich ging davon aus, dass der Compiler das ohnehin zur Compilezeit berechnet und dabei, entsprechend der CPU Architektur des PCs, mit 32-bit rechnet.
Alles klar, wieder was gelernt.
... und wenn Du die Compiler-Warnungen eingeschaltet hättest (etwas, was
man immer machen sollte, -Wall, mindestens), hätte dir der Compiler
hier eine Warnung bezüglich des Integer-Overflows ausgeworfen.
Mann muss die Warnungen auch beachten und deren Ursache beheben.
(-Wall ist nicht die Ursache)
Mal eine ganz andere Frage:
Wie kommst du auf eine Hysterese in Zeiteinheiten?
Das Ganze soll ja wohl ein Thermostat werden, also wäre da eine Hysterese in Temperatureinheiten angesagt.
aber ich ging davon aus, dass der Compiler das
ohnehin zur Compilezeit berechnet und dabei, entsprechend der CPU
Architektur des PCs, mit 32-bit rechnet.
Warum sollte der Compiler die Architektur des PC (heute üblicherweise 64-bit) berücksichtigen, wenn doch für ein ganz anderes Target, hier AVR, compiliert wird?
Wenn Du etwas von Sprache X nach Sprache Y übersetzen sollst, spielt es für Dich doch auch keine Rolle, in welchem Land du dich befindest.
constuint32_thysterese=(15*60*1000);//Hysterese in ms
Ich benutze als IDE Visual Studio Code mit Platformio und dem Arduino
Framework.
Weil Du Arduino benutzt, benutz Du also C++ ...
Für Konstanten habe ich sonst immer Makros bzw. einfache
Präprozessoranweisungen genutzt, aber ich dachte mir wenn man eine
Konstante deklariert, dann weiß man wenigstens genau, was die für einen
Typ hat, das ist am Ende transparenter und sicherer.
CPP-Macros kannst Du bei C++ immer vermeiden (weil sie Mist sind).
Mache
1
constexpruint32_thysterese=(15*60*1000);//Hysterese in ms
draus, und Du bekommst auch einen Fehler.
Und schalte in Zukunft Deine Warnungen ein (mindestens -Wall -Wextra ...).
Meine Frage ist jetzt, wieso hat die Zuweisung so nicht funktioniert?
Es ist keine Zuweisung!
Den Unterschied zwischen Zuweisung und Initialisierung ist etwas, was man ganz am Anfang des Lernens von C++ verstehen sollte / muss!
Mal eine ganz andere Frage:
Wie kommst du auf eine Hysterese in Zeiteinheiten?
Das Ganze soll ja wohl ein Thermostat werden, also wäre da eine
Hysterese in Temperatureinheiten angesagt.
W.S.
Weil sich diese Hysterese auf die Schalthäufigkeit bezieht und nicht auf die Temperatur. Das System, das gekühlt werden soll ist recht träge, da spielt es keine Rolle, wenn höchstens alle 15 Min. etwas am Schaltzustand geändert werden kann. Die Temperaturabweichungen sind überschaubar und das Aggregat wird so nicht sinnlos strapaziert.
Warum sollte der Compiler die Architektur des PC (heute üblicherweise
64-bit) berücksichtigen, wenn doch für ein ganz anderes Target, hier
AVR, compiliert wird?
Wenn Du etwas von Sprache X nach Sprache Y übersetzen sollst, spielt es
für Dich doch auch keine Rolle, in welchem Land du dich befindest.
Schon klar, aber Compiler optimieren ja auch ne Menge Dinge weg, von daher ging ich davon aus, da es sich hier um eine Konstante handelt, würde der Compiler aus dieser Initialisierung einfach eine Zuweisung machen.
So dass am Ende einfach:
1
constuint32_thysterese=900000;
daraus wird.
Wie ja nun hinreichend geklärt wurde, war das eine falsche Annahme.
... und wenn Du die Compiler-Warnungen eingeschaltet hättest (etwas, was
man immer machen sollte, -Wall, mindestens), hätte dir der Compiler
hier eine Warnung bezüglich des Integer-Overflows ausgeworfen.
Es geht um Arduino. Das unterdrückt defaultmäßig alle Warnungen, weil sowas für die Arduino-Zielgruppe als zu kompliziert angesehen wird…
Klar dass ein int beim
Atmega 16-bit hat, aber ich ging davon aus, dass der Compiler das
ohnehin zur Compilezeit berechnet und dabei, entsprechend der CPU
Architektur des PCs, mit 32-bit rechnet.
Es wird zur Compilezeit berechnet, allerdings nach genau den selben Regeln wie eine Berechnung zur Laufzeit. Man will ja nicht, dass ein und die selbe Berechnung zur Compilezeit ein anderes Ergebnis hat als wenn sie zur Laufzeit durchgeführt worden wäre.
Schon klar, aber Compiler optimieren ja auch ne Menge Dinge weg, von
daher ging ich davon aus, da es sich hier um eine Konstante handelt,
würde der Compiler aus dieser Initialisierung einfach eine Zuweisung
machen.
So dass am Ende einfach:
const uint32_t hysterese = 900000;
daraus wird.
Das ist nach wie vor keine Zuweisung, sondern eine Initialisierung.
Korrekterweise solltest Du
1
constuint32_thysterese=900000UL;
schreiben, denn 900000 ist kein int, und Du willst eine unsigned-Variable damit initialisieren.