Hallo,
Martin Teuer schrieb:> unsigned long statusMessageTimer = 0;
Dann setze eben den Startwert so, daß die Bedingung beim Eintritt in
loop() erfüllt ist.
unsigned long statusMessageTimer = millis() + 30 Sekunden;
Gruß aus Berlin
Michael
in der Mainloop sollte da reichen.
Den Trick mit dem warten auf Millis und dem möglichen Überlauf alle paar
Wochen muss man natürlich beachten, oder man nutzt simpel delay() wenn's
auf die 30s nicht so ankommt.
Martin Teuer schrieb:> "doing" wird aber nur alle 30s durchgeführt und nicht beim ersten> durchlauf
Schreibs als Funktion und rufe sie zuerst direkt auf.
Fällt der Rückgabewert von millis() zufälligerweise auf den Wert 0, wird
nicht gewartet und sofort die Routine ausgeführt.
Da der Rückgabewert 32Bit hat, dürfte das sehr selten passieren.
Aber wenn jemand auf die tolle Idee kommt, den Code für einen 100ms
Zyklus zu nutzen , steigt die Wahrscheinlichkeit natürlich an.
Dann wundert man sich, dass das System nach 30Tagen abstürzt oder
unerklärliche Dinge tut...
Besser wäre es in setup() den ersten Durchlauf aufzurufen und die
zyklischen im Loop.
Dann ohne das Konstrukt '|| statusMessageTimer == 0'.
Oder man baut eine Zustandsmaschine mit extra Variable.
>Dann setze eben den Startwert so, daß die Bedingung beim Eintritt in>loop() erfüllt ist.
Logisch.
>unsigned long statusMessageTimer = millis() + 30 Sekunden;
Besser:
unsigned long statusMessageTimer = millis() - 30 Sekunden;
Noch besser:
unsigned long MilliSecTick = millis() - MILLISEC_TICK_INTERVAL;
Martin Teuer schrieb:> "doing" wird aber nur alle 30s durchgeführt und nicht beim ersten> durchlauf...Was mache ich falsch??
Man könnte ja die Funktion einfach auch in setup() einmalig aufrufen . .
.
Falk B. schrieb:> Man könnte ja die Funktion einfach auch in setup() einmalig aufrufen . .
Ich glaub das ist Geschmackssache, lässt sich drüber streiten ob das
schön ist :-)
Wie wäre es mit sowas, da könnte man dann auch weitere "timeouts"
hinzufügen.
Und as Problem mit dem Überlauf bei Tag 49 fällt auch weg.
Das 'if (last_ms != ms)' in der Update Funktion kann man auch weglassen.
Macht vermutlich an der Performance nicht so viel aus.
Ich würde den SOftwaretimer ggf noch in eine Klasse oder eine Template
kapseln.
BeBe schrieb:> Das 'if (last_ms != ms)' in der Update Funktion kann man auch weglassen.> Macht vermutlich an der Performance nicht so viel aus.
Jetzt wo du es sagst :-D seh ich es auch.
BeBe schrieb:> Ich würde den SOftwaretimer ggf noch in eine Klasse oder eine Template> kapseln.
Ja könnte man als Klasse machen, ich hab es aus meinen C Sourcen
herauskopiert.
Eigentlich sollte das kein Problem sein.
Wie bereits gesagt, lagere, alles was Du zyklisch vorhast in eine
Funktion aus. Z.B. in HauReinOnkelOtto().
Dann sieht Dein Programm folgendermaßen aus:
In setup(), nachdem die Initialisierung abgeschlossen ist einmalig
HauReinOnkelOtto() aufrufen. Nicht vergessen die Referenzzeiten in die
Ausgangsstellung bringen.
Später, in der Hauptschleife:
Frage die Zeitreferenz ab;
Endzeit erreicht?
Ja: HauReinOnkelOtto();
Zeit in Ausgangsstellung bringen;
Den anderen Kram machen, der so anliegt.
Hauptschleife Ende
Ja, so kann man es machen und ist in keinster Weise falsch.
Aber ehrlich, Arduino ist C++11.
Ich würde hier wirklich ein class oder template Konzept nutzen.
Es gibt hunderte von Varianten im Netz. Z.B.
https://www.arduino.cc/reference/en/libraries/simpletimer/
Preprocessor Makros sollten wirklich nur da genutzt werden,
wo es keine bessere Möglichkeit gibt.
Function Macros nutze ich nur bei Androhung von Gewalt oder wenn ich
eine Sauerei mit \_\_FILE\_\_ und \_\_LINE\_\_ benötige...
Martin Teuer schrieb:> "doing" wird aber nur alle 30s durchgeführt und nicht beim ersten> durchlauf...Was mache ich falsch??
Du gehst davon aus, dass der Timer beim ersten Aufruf der if-Abfrage
noch auf 0 steht. Bis dahin wird er aber schon etwas weiter sein.
Zwischen dem Start des Timers und dem Ausführen der loop() Funktion
passiert je nach Projekt noch einiges mehr, was du in deinem eigenen
Quelltext nicht sehen kannst.
BeBe schrieb:> Aber ehrlich, Arduino ist C++11.
Nicht nur.
Der Core ist größtenteils in C und etwas ASM
Das Macro sollte auch in C funktionieren.
BeBe schrieb:> Ich würde hier wirklich ein class oder template Konzept nutzen.
Ja!
Kann man durchaus tun.
(habe ich auch noch im Köcher)
Wird aber nicht sparsamer, in Sachen RAM/FLASH
1
// Wieder eine Variation des BlinkWithoutDelay
2
3
#include<CombieTimer.h>
4
5
Combie::Timer::Pulsatorpuls(1000);// liefert alle 1000 ms einmal true sonst false
6
7
8
9
voidsetup()
10
{
11
pinMode(LED_BUILTIN,OUTPUT);
12
// puls.start(); // ohne start() beginnt puls mit Pause, sonst mit Impuls
EAF schrieb:> BeBe schrieb:>> Ich würde hier wirklich ein class oder template Konzept nutzen.> Ja! Kann man durchaus tun. (habe ich auch noch im Köcher)> Wird aber nicht sparsamer, in Sachen RAM/FLASH
Das ist aber nicht der springende Punkt.
Es ist normalerweise nicht unbedingt sparsamer aber normalerweise auch
nicht größer! (Alles in Macros geht auch in Templates.)
Dafür hat man besseres Diagnose/Warnungen, Typprüfung in IDEs
kontextsensitive Hilfen, besseres Debugging und anderes.
Aber Du kennst beide Seiten (C und C++), das brauch ich Dir nicht zu
sagen.
Es ging mit um Mitleser, die später an Makro Code verzweifeln könnten.
Klaus H. schrieb:> EAF schrieb:>> BeBe schrieb:>>> Ich würde hier wirklich ein class oder template Konzept nutzen.>> Ja! Kann man durchaus tun. (habe ich auch noch im Köcher)>> Wird aber nicht sparsamer, in Sachen RAM/FLASH>> Das ist aber nicht der springende Punkt.> Es ist normalerweise nicht unbedingt sparsamer aber normalerweise auch> nicht größer! (Alles in Macros geht auch in Templates.)> Dafür hat man besseres Diagnose/Warnungen, Typprüfung in IDEs> kontextsensitive Hilfen, besseres Debugging und anderes.
Minus M. schrieb:> Habe ich mir gerade angesehen, kann aber nicht wirklich erkennen, warum> dort 64 Bit Intervalle genutzt werden.
Weil millis() einen 64 Bit Integer liefert.
Minus M. schrieb:> Habe ich mir gerade angesehen, kann aber nicht wirklich erkennen, warum> dort 64 Bit Intervalle genutzt werden.
Nicht nur das!
Sie enthält einen massiven Fehler!
1
boolSimpleTimer::isReady(){
2
return_start+_interval<=millis();
3
}
Angenommen, millis() steht ganz kurz vor dem Überlauf, _start wird
gleich millis() gesetzt und interval ist hinreichend groß.
Jetzt ist die 64Bit Summe aus _start + _interval größer als der 32Bit
Wertebereich von millis().
Resultat:
Die Methode wird niemals wieder ein true liefern.
Die Chancen stehen also recht gut, dass das Gerät nach 49 Tagen einen
Reset benötigt.
wennst deinen "previousMillis" statt mit 0 schon einfach alt genug
initialisiert, ist deine Bedingung beim ersten Lauf schon true
const unsigned long statusMessageInterval = 1000*30* 1; // 30s
unsigned long statusMessageTimer = 0 - statusMessageInterval;
LostInMusic schrieb:> Zuweisung eines negativen Werts an eine "unsigned"-Variable?
unsigned long statusMessageTimer = 0UL - statusMessageInterval;
Macht die Sache geringfügig offensichtlicher, da der Unsigned Unterlauf
durchaus vom Standard abgedeckt wird.
Was mich da eher stört:
Der Urknall, in der Welt eines µC, ist der PowerOn.
Dort gibt es eigentlich noch gar keine vergangenen Zeitpunkte. Von daher
scheint es mir unnatürlich einen Zeitpunkt in die Vergangenheit zu
setzen.
Ist das nicht eher ein dirty Hack?
EAF schrieb:> Ist das nicht eher ein dirty Hack?
IMHO nein. Die Situation ist die gleiche wie in 49 Tagen nach dem
millis() rollover:
millis ist wieder knapp über 0,
statusMessageInterval ist sehr groß.
Oliver S. schrieb:> Man muss nicht alles selber machen:> https://github.com/sstaub/Ticker
Da hast du Wahr!
Aber auch da findet sich ein Haar in der Suppe.
Die Klasse macht zu viel.
Sie hat dadurch recht viele Eigenschaften(Variablen).
Zudem:
1
uint32_tTicker::elapsed(){
2
if(resolution==MILLIS)returnmillis()-lastTime;
3
elsereturnmicros()-lastTime;
Hier sieht man dem Methodenaufruf nicht an, ob man einen Wert in Milli-
oder Mikrosekunden zurück erhält.
Das ist abhängig von der Instanziierung, und die ist ganz woanders.
Das Verhalten zieht sich wie ein roter Faden durch die ganze Klasse.
Das ist nicht so schön......
Aber natürlich, nutzbar wird das schon sein.
noiasca schrieb:> IMHO nein. Die Situation ist die gleiche wie in 49 Tagen nach dem> millis() rollover
Ja, sie ist ähnlich.
So ähnlich, dass es funktionieren wird.
Aber schön ist das nicht, aus meiner Sicht.
Ins Besondere, wenn es auch anders geht.
EAF schrieb:> Die Klasse macht zu viel.
Nachdem die Source öffentlich ist und sehr klein und
übersichtlich, dürfte es ein Leichtes sein sie so zu strippen
dass sie auch dir klein genug ist.
Wenn man Glück hat macht das sogar der Compiler durch Weglassen
unbenutzer Funktionen bzw. Methoden.
mitlesa schrieb:> Nachdem die Source öffentlich ist und sehr klein und> übersichtlich, dürfte es ein Leichtes sein sie so zu strippen> dass sie auch dir klein genug ist.
Ja!
Steht aber im Widerspruch zu:
Oliver S. schrieb:> Man muss nicht alles selber machen
Zudem bin ich mit solchen "Dingen" schon bestens ausgestattet.
Zwei Varianten gabs hier schon zu sehen, aber gerne auch noch eine
Dritte(ein Ausschnitt):
EAF schrieb:> Aber schön ist das nicht, aus meiner Sicht.
Schönheit ist ja sehr was individuelles.
c unsigned overflow ist "defined behavior" daher kann man das schon
nutzen.
Die Variable startet bei mir mit
statusMessageTimer = 4294964296
Die Subtraktionsvarianten bringen jedenfalls den Variableninhalte bzw
Millis() in eine Kombination, wie sie auch zur Laufzeit auftreten
können.
Die Additionsvarianten funktionieren im konkreten Beispiel auch. Eine
Kombination millis() = 0 und statusMessageTimer = 3000 wird aber zur
Laufzeit nicht vorkommen. Daher finde ich das nicht besser.
Mit millis() initialisieren sehe ich keinen Grund, kostet auch etwas
Flash und daher kann man das auch dem Compiler überlassen.
Das 0UL ... wenn man mag. Bei mir hat der Compiler aber auch richtig
4294964296 eingesetzt.
1
// https://www.mikrocontroller.net/topic/523549
2
voidsetup(){
3
Serial.begin(115200);
4
}
5
6
constunsignedlongstatusMessageInterval=1000*3*1;
7
8
//unsigned long statusMessageTimer = millis() + statusMessageInterval; // Michael U. (amiga) 19.08.2021 09:07 1932/226
noiasca schrieb:> Das 0UL ... wenn man mag. Bei mir hat der Compiler aber auch richtig> 4294964296 eingesetzt.
Ja, das macht er richtig.
Das UL hat dort eher dokumentierenden Charakter.
Hier fände ich das noch viel wichtiger!
Martin Teuer schrieb:> const unsigned long statusMessageInterval = 1000*30* 1; // 30s
Denn die Berechnung steht (ohne UL) mit den Werten schon ganz kurz vorm
Überlauf.
const unsigned long statusMessageInterval = 1000*40* 1; // 40s
klappt schon nicht mehr wirklich
> warning: integer overflow in expression of type 'int'
Besser:
const unsigned long statusMessageInterval = 1000UL 30 1; // 30s
---
Aber davon abgesehen, ich wüsste nicht wie ich den Hack dokumentieren
sollte, wenn ich ihn bei mir anwenden wollte....(ohne mich zu schämen)
OK, das war jetzt arg subjektiv.
Wie auch immer, es ist ein freies Land, mit freier Fahrt, wo jeder das
machen kann, was er gerne tut.
Die Grenzen werden einem schon aufgezeigt, oder eben auch nicht.
Ich für mich weiß nur, dass man sich an solche Hacks gewöhnt. Dann auch
mal gerne zum Prinzip erhöht.
Ich arbeite immer mit 1 Variable dann brauch ich mir das ganze nicht
antun.
Neu_millis = millis() + Zeit_ich_will '(in Millis)
If millis() > Neu_millis then
mach_was_du_machen_sollst
Neu_millis = millis() + Zeit_ich_will.
end if
Fertig.
Beim Start setzt ich neu_millis auf den passenden Wert und das wars.
Wenn ich den Überlauf abfangen will brauche ich nur den Max_wert zu
überprüfen und den Wert passend zu setzen. Ist eine Zeile mehr.
Wieso macht ihr da so ein Aufwand.
Schlaumaier schrieb:> Wenn ich den Überlauf abfangen will
Du hast da 3 (potentielle) Überläufe!
Für jeden eine Extrawurst backen...
Schlaumaier schrieb:> Ist eine Zeile mehr.
Dann zeige das doch mal....
Schlaumaier schrieb:> brauche ich nur den Max_wert zu> überprüfen und den Wert passend zu setzen.
Ich sehe keinen Max_wert.
Und bei unseren Geschichten muss man den Überlauf überhaupt nicht
prüfen.
Wozu auch?
Solange das Interval kleiner als 49 Tage ist, kein Problem.
Und 30 Sekunden sind deutlich drunter.
Schlaumaier schrieb:> Wieso macht ihr da so ein Aufwand.
Tja....
Vielleicht, weil man auch bei einem solchen Trivialproblen noch Bockmist
bauen kann?