Hi,
Ich habe angefangen mit dem Arduino zu spielen und einen Sensor der 5
Sekunden Braucht um keine Ahnung was zu machen. Dafür hab ich für den
Seriellen Monitor eine art Warte Sequenz geschrieben.:
1
Serial.println("Bitte warten");
2
delay(500);
3
Serial.print(".");
4
delay(500);
5
Serial.print(".");
6
delay(500);
7
Serial.println(".");
8
delay(500);
9
Serial.print(".");
10
delay(500);
11
Serial.print(".");
12
delay(500);
13
Serial.println(".");
14
delay(500);
15
Serial.print(".");
16
delay(500);
17
Serial.print(".");
18
delay(500);
19
Serial.println(".");
20
21
Serial.println("Startklar ;D ");
Das sind 3 punkte die fortlaufen. Das finde ich persönlich aber nicht so
elegant. Kennt ihr da etwas besseres?
Mfg
c-hater schrieb:> Wenn das wirklich so sein sollte, ist Arduino noch viel kaputter, als> ich je zu befürchten wagte...
Keine Sorge. Arduino gibt das selbe aus, als wenn es in ASM geschrieben
worden wäre. Zehn Punkte und ein Komma.
Timmo H. schrieb:> Als wenn die Zeilenumbrüche zur Übersicht beitragen würden...aber nungut
Tun sie natürlich nicht. Aber du wolltest doch ein
funktions-äquivalentes Programm abliefern. ;-)
Timmo H. schrieb:> delay(500);
das delay() kann gegen einen non-blocking variante ausgetauscht werden,
dann kann in der zeit was anderes bearbeitet werden oder gegen eine
idle/sleep variante mit timer wake-up.
mt
Timmo H. schrieb:> Aber natürlich, fragt sich nur ob in dem Einsatzfall ein Benefit dabei> heraus kommt.
So sicher nicht.
Schwachfug kann nur durch groesseren ersetzt werden.
leo
Timmo H. schrieb:> Da hast du natürlich recht, aber man muss ja mal zu Denken anregen :-D
Genau ;-)
Dann kann man ja noch aufpassen, ob man mit Zeilenumbruch beginnt (ah
schon korrigiert) und wie lang man wartet.
leo
Stefanus F. schrieb:> pollo M. schrieb:>> das delay() kann gegen einen non-blocking variante ausgetauscht werden>> Bei Arduino ist delay() bereits nicht blockierend. Delay ruf yield() auf> und das wiederum wird von einigen Cores genutzt, zum Beispiel um den> ESP8266 am "leben" zu erhalten.
Dumm nur, daß das 99,9% der Arduino-User weder wissen noch anwenden.
Falk B. schrieb:> Dumm nur, daß das 99,9% der Arduino-User weder wissen noch anwenden.
Glaube ich nicht. Gerade beim ESP8266 kommt man ziemlich schnell darauf
während der Entwicklung.
Hallo,
yield ist aber kein Freibrief sich die loop mit delay zu blockieren.
Dann kommt der Nächste und kloppt sich yield mit delay zu. Was hat er
dann gewonnen? Man muss einfach sauber programmieren.
Die Aussage das delay nicht blockierend arbeitet ist auch falsch. Nur
weil zwischendurch yield aufgerufen wird arbeitet delay dennoch
blockierend. Die while ist erst beendet wenn die Wartezeit um ist.
Gegenfrage. Was machen Programmierer ohne Arduino Framework im
klassischen Stil? Die haben kein yield. Die müssen einfach sauber
programmieren. Dann gibts auch keinen Unterschied zu mit Arduino
Framework.
Veit D. schrieb:> arbeitet delay dennoch blockierend.
Natürlich blockiert delay() Rechenzeit. Wenn delay(500) für 100ms
unterbrochen wird, dann verzögert sich dessen Ausführung um die
Unterbrechungsdauer und "von aussen" gesehen dauert das delay(500) dann
600ms.
Falk B. schrieb:> Dumm nur, daß das 99,9% der Arduino-User weder wissen noch anwenden.
Ja, leider. Und deshalb ist der µC zu langsam. Dabei gibt es doch tolle
Tutorials zum Thema "Hauptschleife mit millis()".
Wenn ich in einem Programm ein delay() ausserhalb irgendwelcher
Initialisierungsroutinen sehe, dann geht bei mir eine rote
Warnlampe an. Diese Rechenzeitverschewndung ist ganz oft die Ursache für
anderweitige Probleme.
Lothar M. schrieb:> Wenn delay(500) für 100ms> unterbrochen wird, dann verzögert sich dessen Ausführung um die> Unterbrechungsdauer und "von aussen" gesehen dauert das delay(500) dann> 600ms.
Aua!
Bitte nicht verwechseln, mit dem Delay in der AVR C Library
Siehe:
https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.cFalk B. schrieb:> Dumm nur, daß das 99,9% der Arduino-User weder wissen noch anwenden.
Dummschwätzer!
Arduino Bashing, Menschen herabwürdigen, scheint dir Befriedigung zu
verschaffen.
Warum?
Arduino Fanboy D. schrieb:> Falk B. schrieb:>> Dumm nur, daß das 99,9% der Arduino-User weder wissen noch anwenden.> Dummschwätzer!
Realist!
> Arduino Bashing, Menschen herabwürdigen, scheint dir Befriedigung zu> verschaffen.
Wahre Worte sind nicht schön, schöne Worte sind nicht wahr.
Laotse
Alles klar...
Klassisches Arduino Bashing, unterstürzt von einem Moderator, welcher
seine Wissenslücken öffentlich präsentiert!
Das könnte man auch differenzierter sehen.
Die Anfänger welche im Arduino Umfeld einschlagen sind Anfänger.
Und Anfänger wissen nichts. Sonst wären sie keine Anfänger.
Ja, sie müssen die delay() Hürde überwinden.
Das klappt auch meist ohne große Schmerzen.
Wenn du natürlich deine eigene Arroganz/Kompetenz als Messlatte an
Anfänger anlegst, sind natürlich 99,9% aller Menschen Idioten.
Und der bornierteste (Falk B) von allen sieht sich jeden Morgen im
Spiegel.
Arduino Fanboy D. schrieb:> Bitte nicht verwechseln, mit dem Delay in der AVR C Library
Ja, tatsächlich.
Also wird schonmal nicht unnötig zusätzlich verzögert, weil einer sich
die Arbeit mit dem Zeitvergleich gemacht hat. Gut soweit.
Verbleibt halt noch das Hauptproblem, dass trotzdem die restliche
Rechenzeit verbraten wird, weil in der yield() Funktion beim AVR eben
nichts aufgerufen oder ausgeführt wird.
Arduino Fanboy D. schrieb:> Klassisches Arduino Bashing, unterstürzt von einem Moderator
Ja, hast du nicht auch schon mal was nicht gewusst? Und bist deswegen
gleich des Bashings bezichigt worden? Kurios.
Veit D. schrieb:> Hallo,>> bin auch von den Aussagen von Lothar und Falk irritiert.
Ich bin irritiert, daß du irritiert bist. Was ist denn an der Aussage
nicht zu verstehen?
Beitrag "Re: Warte Sequenz optimieren Arduino"
Die mag einigen Zeitgenossen nicht gefallen, stimmt aber größtenteils.
Nur weil eine Aussage nicht schön ist, ist sie noch lange nicht falsch.
Und ja, das liegt in hohem Maße daran, daß die große Masse der
Arduino-Anwender Programmieranfänger sind, die es nicht besser wissen.
Teilweise aber auch daran, daß sie die diversen Hinweise und Beispiele,
die es ja auch auf der Arduino-Homepage gibt, gekonnt ignorieren und
einfach drauflosmurksen. Mal Ruhe reinbringen und was lernen ist das
uncool.
Man kann schon im Arduino-Universum gute Programme, leistungsfähige
Programme schreiben, wenn man weiß was man tut. Darum ging es aber gar
nicht.
Lothar M. schrieb:> Arduino Fanboy D. schrieb:>> Klassisches Arduino Bashing, unterstürzt von einem Moderator> Ja, hast du nicht auch schon mal was nicht gewusst? Und bist deswegen> gleich des Bashings bezichigt worden? Kurios.
Hier zitierst du ihn, und stimmst zu:
Lothar M. schrieb:> Falk B. schrieb:>> Dumm nur, daß das 99,9% der Arduino-User weder wissen noch anwenden.> Ja, leider. Und deshalb ist der µC zu langsam. Dabei gibt es doch tolle> Tutorials zum Thema "Hauptschleife mit millis()".
Das ist es, was ich als "Unterstützung eines Arduino Bashers" bezeichne.
Dich als Mensch betrachtet, ist es mir recht egal, was du von Arduino
und seinen Usern hältst.
Aber betrachte ich die Moderator Rolle, dann halte ich das für gründlich
daneben.
Gründlich.
Und dass du das jetzt auch noch öffentlich aktiv verteidigst, ist ein
Armutszeugnis.
Kein Hauch von Einsicht.
Lothar M. schrieb:> Verbleibt halt noch das Hauptproblem, dass trotzdem die restliche> Rechenzeit verbraten wird, weil in der yield() Funktion beim AVR eben> nichts aufgerufen oder ausgeführt wird.
Wenn man einen Arduino verwendet, welcher in yield() nichts tut.
Kann man sich yield() selber definieren. Man ist frei, in der Hinsicht.
1
voidyield()
2
{
3
// tuwas
4
}
5
6
voidsetup()
7
{
8
}
9
10
voidloop()
11
{
12
delay(1000);
13
}
Arduino ist kein Multitasking System!
Ermöglicht einem aber z.B. über yield() Nebenläufigkeiten zu
implementieren.
Ob man das als Fehler betrachtet, oder als Feature, spielt sich im Kopf
ab.
Falk B. schrieb:> stimmt aber größtenteils
So, dann wären wir bei über 50%
Das ist schon was anderes, als 99,9%
Damit hast du dich selbst der Präsentation von falschen
Tatsachenbehauptungen überführt.
Diffamierung, Verleumdung...
Aus Wikipedia
1
Wer wider besseres Wissen in Beziehung auf einen anderen eine unwahre
2
Tatsache behauptet oder verbreitet, welche denselben verächtlich zu
3
machen oder in der öffentlichen Meinung herabzuwürdigen oder dessen
4
Kredit zu gefährden geeignet ist, wird mit Freiheitsstrafe bis zu
5
zwei Jahren oder mit Geldstrafe und, wenn die Tat öffentlich, in
6
einer Versammlung oder durch Verbreiten von Schriften (§ 11 Abs. 3)
7
begangen ist, mit Freiheitsstrafe bis zu fünf Jahren oder mit
Veit D. schrieb:> Die while ist erst beendet wenn die Wartezeit um ist.
ja Ok, so kann man das auch sehen. In diesem Fall war das allerdings
auch der beabsichtigte Effekt.
Stefanus F. schrieb:> Bei Arduino ist delay() bereits nicht blockierend. Delay ruf yield() auf
... hier wird wieder mal alles verwurstelt, mit dem yield() argument
oder einer beliebigen isr() könnte dann immer behauptet werden
non-blocking.
selbst deadlooks sind dann non-blocking, da ja noch isr() lustig weiter
laufen.
für mich ist diese argumentation sinnfrei!
man sollte vielleicht unterscheiden können zwischen application/user
level und anderen nebenläufigen abstraction levels.
schon mal mit asyncio beschäftigt?!
mt
Arduino Fanboy D. schrieb:> mit Freiheitsstrafe bis zu fünf Jahren oder mit Geldstrafe bestraft.
Jetzt lass bitte einfach mal stecken.
Arduino Fanboy D. schrieb:> Wenn man einen Arduino verwendet, welcher in yield() nichts tut.> Kann man sich yield() selber definieren. Man ist frei, in der Hinsicht.
Korrekt. Ich warte dann mal auf den ersten, der (weil es ja in der
Hauptschleife auch so gut geklappt und er es deshalb so gelernt hat)
sowas schreibt:
1
voidyield()
2
{
3
// tuwas
4
delay(1000);// und dann warte eine Sekunde
5
}
6
7
voidsetup()
8
{
9
}
10
11
voidloop()
12
{
13
delay(1000);
14
}
Stefanus F. schrieb:> dann habe ich "zufällig" etwas vorbereitet:> http://stefanfrings.de/multitasking_arduino/index.html
Ich wollte jetzt das Wort "Zustandsautomat" nicht ausdrücklich
hinschreiben, aber danke dafür, dass du einen zeigst.
So richtig schön wäre es nun, wenn du da die millis() nicht jedesmal,
sondern nur ein einziges Mal einliest, damit während der Bearbeitung des
Automaten die Systemzeit quasi "stehen bleibt".
Denn weil der millis()-Timer ja während der einzelnen Abfragen
weiterläuft, kann man sich sonst leicht eine Race-Kondition einhandeln,
die dann einmal pro Tag oder auch nur einmal pro Woche zu eigenartigem
Verhalten (sprich Fehlern) führt.
Lothar M. schrieb:> So richtig schön wäre es nun, wenn du da die millis() nicht jedesmal,> sondern nur ein einziges Mal einliest, damit während der Bearbeitung des> Automaten die Systemzeit quasi "stehen bleibt".> Denn weil der millis()-Timer ja während der einzelnen Abfragen> weiterläuft, kann man sich sonst leicht eine Race-Kondition einhandeln,
... verstehe ich nicht!
ich sehe keine möglichkeit für race conditions und das millis() einlesen
ist quasi ein rücksetzen der zeitbedingung und ok.
Apollo M. schrieb:> ich sehe keine möglichkeit für race conditions und das millis() einlesen> ist quasi ein rücksetzen der zeitbedingung und ok.
Mal als Beispiel nur diesen Code angenommen:
1
if(millis()-warteSeit>=100)// wenn 100ms verstrichen sind
2
{
3
status=EIN;
4
}
5
6
// jetzt kommt ein Interrupt, der aufgrund ungeschickter Programmierung 6ms dauert
7
8
if(millis()-warteSeit>=105)// wenn 105ms verstrichen sind
9
{
10
status=AUS;
11
}
12
13
if(status==EIN)
14
{
15
Was_ungeheuer_Wichtiges();
16
}
Dann wird Was_ungeheuer_Wichtiges() nicht ausgeführt, obwohl der
status zwischendurch EIN war. Das ist eine Race-Condition.
Wenn millis() nur einmal eingelesen wird, dann wird status für einen
Programmzyklus aktiv, weil die Zeit akt_millis auf der alten
Systemzeit auf "100ms" stehen geblieben ist:
1
akt_millis=millis();
2
if(akt_millis-warteSeit>=100)// wenn 100ms verstrichen sind
3
{
4
status=EIN;
5
}
6
7
// jetzt kommt ein Interrupt, der aufgrund ungeschickter Programmierung 6ms dauert
8
9
if(akt_millis-warteSeit>=105)// wenn 105ms verstrichen sind
Apollo M. schrieb:> dein beispiel habe ich jetzt kappiert!
Ein konstruiertes Beispiel.
Denn der kritisierte Automat von Stefanus F. (Firma: Äppel) (stefanus)
zeigt das Verhalten nicht.
Ist also ein Strohmann Argument.
Peter D. schrieb:> Ein Interrupt kommt nicht nur an der Stelle, die Du willst, er könnte> auch hier kommen:
Korrekt, dann dann haben wir aber eher ein Problem der Rechenleistung
allgemein.
Und in diesem (natürlich!) konstruierten Beispiel könnte es ja so
aussehen:
1
// angenommen, jetzt ist millis()-warteSeit == 99
2
// jetzt kommt ein Interrupt, der aufgrund ungeschickter Programmierung 6ms dauert
3
// d.h. jetzt ist millis()-warteSeit == 105
4
akt_millis=millis();
5
if(akt_millis-warteSeit>=100)// wenn 100ms verstrichen sind
6
{
7
status=EIN;
8
Bereite_was_ungeheuer_Wichtiges_vor();
9
}
10
11
if(akt_millis-warteSeit>=105)// wenn 105ms verstrichen sind
12
{
13
status=AUS;
14
Raeume_was_ungeheuer_Wichtiges_auf();
15
}
16
17
if(status==EIN)
18
{
19
Was_ungeheuer_Wichtiges();
20
}
Dann wäre aufgrund der fehlenden Rechenleistung das "ungeheuer_Wichtige"
wenigstens samt Vor- und Nachbereitung ausgefallen.
Arduino Fanboy D. schrieb:> Denn der kritisierte Automat von Stefanus F. (Firma: Äppel) (stefanus)> zeigt das Verhalten nicht.
Nein, er zeigt das Verhalten wahrscheinlich nicht, weil er einen solchen
Fehler glücklicherweise über den umrahmenden Automaten abgefangen hat.
> Ein konstruiertes Beispiel.> Ist also ein Strohmann Argument.
Trotzdem ist das mehrfache Einlesen der Systemzeit innerhalb eines
Zustandsautomaten ungünstig. Oder etwa nicht? Und ist es dann im
Gegenteil sogar ratsam?
Lothar M. schrieb:> Oder etwa nicht? Und ist es dann im> Gegenteil sogar ratsam?
in dem zusammenhang könnte vielleicht noch atomic access/region
eingeworfen werden.
das "ratsam" hängt vom konkreten kontext ab ...
... hier mal eine ergänzung/prinzip wie die "tasks" unterschiedliche
priority bzw. preocessing time bekommen könnten.
void loop()
{
while (!(millis() % 20)) thread_rot(); //highest prio
while (!(millis() % 50)) thread_gelb();
while (!(millis() % 100)) thread_gruen();
}
Lothar M. schrieb:> Korrekt, dann dann haben wir aber eher ein Problem der Rechenleistung> allgemein.
Ich wollte auch nur zeigen, daß man verdammt vorsichtig damit sein muß:
"Race-Condition umgangen.".
Eh ich sowas behaupte, mache ich lieber einen atomic Block.
Ich hatte mal als Kommentar geschrieben "don't touch the following order
!". Ist beim Reviewer gar nicht gut angekommen.
Apollo M. schrieb:> ... hier mal eine ergänzung/prinzip wie die "tasks" unterschiedliche> priority bzw. preocessing time bekommen könnten.
Nicht ohne derbe Jitter wenn millis() durch den Überlauf geht.
Also nicht empfehlenswert.
Auch ist eine Division, auf einem AVR, eine recht teure Operation.
Apollo M. schrieb:> das "ratsam" hängt vom konkreten kontext ab ...
Hier stimme ich dir ausdrücklich zu...
Es ist irritierend, einen komplexen Zusammenhang auf ein Ja/Nein
reduziert und dann noch mit einer Fangfrage garniert zu sehen.
Arduino Fanboy D. schrieb:> Nicht ohne derbe Jitter wenn millis() durch den Überlauf geht.
... bist du heute wieder pingelig/anstrengend, es ging nur ums prinzip!
millis() würde ich immer durch einen eigenen taskPrioTmr ersetzen mit
geringerer auflösung.
Arduino Fanboy D. schrieb:> Auch ist eine Division, auf einem AVR, eine recht teure Operation.
dagegen gibt es was nettes
aus
while (!(millis() % 20ul)) thread_rot(); //highest prio
wird
while (!(millis() & 19ul)) thread_rot(); //highest prio
Apollo M. schrieb:> aus> while (!(millis() % 20)) thread_rot(); //highest prio> wird> while (!(millis() & 19)) thread_rot(); //highest prio
19 geht doch auch nicht ohne Rest in einen unsigned long. Das müssten
dann schon 16 oder 32 sein, dass es beim Überlauf nicht jittert...
Arduino Fanboy D. schrieb:> Auch ist eine Division, auf einem AVR, eine recht teure Operation.
Kann man so generell nicht sagen. Ein paar float Divisionen zur Ausgabe
an den langsamen Menschen sitzt der AVR auf der linken Pobacke ab.
Lothar M. schrieb:> 19 geht doch auch nicht ohne Rest in einen unsigned long. Das müssten> dann schon 16 oder 32 sein, dass es beim Überlauf nicht jittert...
schon klar, jitter hatte ich dazu nicht angedacht, sondern eher die
transformation % zu &, was je nach compiler auch code size/speed
optimization bedeuten kann.
Apollo M. schrieb:> dagegen gibt es was nettes>> aus> while (!(millis() % 20ul)) thread_rot(); //highest prio> wird> while (!(millis() & 19ul)) thread_rot(); //highest prio
Interessant. Du meinst also, nur weil das bei 2er-Potenzen funktioniert,
geht das bei allen Zahlen.
leo
leo schrieb:>> aus>> while (!(millis() % 20ul)) thread_rot(); //highest prio>> wird>> while (!(millis() & 19ul)) thread_rot(); //highest prio
sorry, ich ziehe das beispiel zurück und gelobe besserung bzgl. besser
doch erst nachdenken und dann ...
Der Zustandsautomat in meinem Beispiel ruft die Funktion millis() bei
jedem Aufruf genau 1x auf. Wer da anderer Meinung war, hat
möglicherweise die "break" Kommandos übersehen.
Stefanus F. schrieb:> Der Zustandsautomat in meinem Beispiel ruft die Funktion millis() bei> jedem Aufruf genau 1x auf.
Ja, schon.
Aber der geneigte Anfänger sieht ganz klar die simple Regel:
"Jedes Mal, wenn ich die Zeit abfrage, rufe ich millis() auf."
Und wendet sie fürderhin so an.
Er erkennt nicht, dass hinter diesen Aufrufen in diesem Zusammenhang
tatsächlich tiefergehende Überlegungen stecken.
Apollo M. schrieb:> ... hier mal eine ergänzung/prinzip wie die "tasks" unterschiedliche> priority bzw. preocessing time bekommen könnten.
Dieses Beispiel krankt auch noch daran, dass die Zykluszeit der Schleife
unbedingt kleiner als 1ms sein muss(!), weil sonst einfach
Taskdurchläufe "übersehen" werden könnten (Abtasttheorem usf...).
Lothar M. schrieb:> Er erkennt nicht, dass hinter diesen Aufrufen in diesem Zusammenhang> tatsächlich tiefergehende Überlegungen stecken.
Wenn du in einer Anfänger-Anleitung alle Überlegungen durchkaust, die
eventuell relevant sein könnten, dann ist es keine Anfänger-Anleitung
mehr, sondern ein Studium.
Immer schön die Kirche im Dorf lassen.
Hallo,
will das jetzt nicht nochmal aufwärmen. Deswegen gehe ich auf das Delay
nicht nochmal ein. Ich denke hierzu ist alles gesagt.
Die Frage ob man millis als Systemzeit einmal pro Durchlauf aufruft oder
immer wenn man diese Zeit benötigt hängt davon ab was das gesamte
Programm machen soll bzw. macht. Pauschal würde ich unterteilen wie
folgt. Wenn die Hauptschleife sehr schnell ist, dann reicht einmal pro
Durchlauf. Wenn die Hauptschleife eher langsam ist, weil irgendwelche
Displays per Soft-SPI beackert werden oder ähnliche Dinge die dann in
Summe paar ms beanspruchen können, dann kommt es an wie genau die
Intervalle eingehalten werden sollen. Für paar Blink LEDs wiederum
völlig egal. Für Displayaktualisierungen ebenfalls völlig egal. Wenn es
auf 1-2ms Genauigkeit ankommt muss man eben millis direkt "vor Ort"
abfragen. Also pauschal würde ich mich da nicht festlegen. Den
Unterschied wann das Eine oder das Andere sieht man jedoch auch erst mit
einer gewissen Programmiererfahrung. Das heißt für den Anfänger spielt
das keine Rolle. Hauptsache er kann millis nutzen und blockiert seinen
Ablauf nicht. Der Rest baut darauf auf.
Wie immer wird es in der Praxis noch Tausende Fälle geben für die ein
oder andere abweichende Entscheidung. Festnageln kann man das sicherlich
nicht.
Ich finde ich millis jedenfalls sehr praktisch.
Lothar M. schrieb:> Aber der geneigte Anfänger sieht ganz klar die simple Regel:
Das ist nicht das, was der Anfänger sieht, sondern das was du auf den
Anfänger projektionierst.
So, wie es auch ein Diaprojektor tut.
Vielleicht hast du dieses mal recht, aber sicherlich nicht immer.
Bitte gib dem Exoten ein Chance.