Forum: Mikrocontroller und Digitale Elektronik Warte Sequenz optimieren Arduino


von Puhliz (Gast)


Lesenswert?

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

von Walter T. (nicolas)


Lesenswert?

Das Word, das Du suchst, heißt "Backspace character".

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Puhliz schrieb:

> Das sind 3 punkte die fortlaufen.

Wenn das wirklich so sein sollte, ist Arduino noch viel kaputter, als 
ich je zu befürchten wagte...

von void (Gast)


Lesenswert?

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.

von Jack V. (jackv)


Lesenswert?

Ist vielleicht ’ne einfache Schleife gesucht? Würde die vielen Zeilen 
jedenfalls auf drei reduzieren ….

von Timmo H. (masterfx)


Lesenswert?

1
Serial.println("Bitte warten");
2
for(int i = 0; i < 10; i++){
3
  delay(500);
4
  Serial.print(".");
5
}
6
Serial.println("\nStartklar ;D ");

: Bearbeitet durch User
von void (Gast)


Lesenswert?

@ Timmo H.:
Du hast die Zeilenumbrüche übersehen.

von Christian M. (Gast)


Lesenswert?

Das prntln kommt nach jedem 3. Punkt!

Gruss Chregu

von Timmo H. (masterfx)


Lesenswert?

void schrieb:
> @ Timmo H.:
> Du hast die Zeilenumbrüche übersehen.
Als wenn die Zeilenumbrüche zur Übersicht beitragen würden...aber nungut
1
Serial.println("Bitte warten");
2
for(int i = 1; i < 10; i++){
3
  delay(500);
4
  if(!(i % 3))
5
    Serial.println(".");
6
  else
7
    Serial.print(".");
8
}
9
Serial.println("\nStartklar ;D ");

: Bearbeitet durch User
von void (Gast)


Lesenswert?

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. ;-)

von Timmo H. (masterfx)


Lesenswert?

Ja stimmt. Und nun sparen wir noch ein paar Zeilen
1
Serial.println("Bitte warten");
2
for(int i = 1; i < 10; i++){
3
  delay(500);
4
  (i % 3) ? Serial.print("."): Serial.println(".");
5
}
6
Serial.println("\nStartklar ;D ");

: Bearbeitet durch User
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

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

von Timmo H. (masterfx)


Lesenswert?

Aber natürlich, fragt sich nur ob in dem Einsatzfall ein Benefit dabei 
heraus kommt. delay triggert zumindest den Watchdog beim ESP
1
Serial.println("Bitte warten");
2
int time1 = millis();
3
for(int i = 1; i < 10; i++){
4
  if(millis() - time1 > 500){
5
    (i % 3) ? Serial.print("."): Serial.println(".");
6
    time1 = millis();
7
  }
8
}
9
Serial.println("\nStartklar ;D ");

: Bearbeitet durch User
von leo (Gast)


Lesenswert?

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

von Timmo H. (masterfx)


Lesenswert?

Ohne Kontext gehts halt nicht besser.

von leo (Gast)


Lesenswert?

Timmo H. schrieb:
> Ohne Kontext gehts halt nicht besser.

Probier bitte deinen Code mal aus. Da wird nix verzoegern.

leo

von Timmo H. (masterfx)


Lesenswert?

Da hast du natürlich recht, aber man muss ja mal zu Denken anregen :-D
1
Serial.println("Bitte warten");
2
int fucking_startTime = millis();
3
int time1 = fucking_startTime;
4
int i = 1;
5
while(millis() - fucking_startTime < 10000){
6
  if(millis() - time1 > 500){
7
    (i % 3) ? Serial.print("."): Serial.println(".");
8
    i++;
9
    time1 = millis();
10
  }
11
}
12
Serial.println("\nStartklar ;D ");

: Bearbeitet durch User
von leo (Gast)


Lesenswert?

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

von Veit D. (devil-elec)


Lesenswert?

Hallo,

es gibt allerdings einen Kardinalsfehler mit dem Datentyp.
Was liefert millis zurück?
Die Antwort ist gleich die Lösung.  :-)

von Stefan F. (Gast)


Lesenswert?

Apollo 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.

Siehe 
https://github.com/arduino-org/Arduino/blob/master/hardware/arduino/samd/cores/arduino/delay.c 
und 
https://stackoverflow.com/questions/34497758/what-is-the-secret-of-the-arduino-yieldfunction

von Falk B. (falk)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von Veit D. (devil-elec)


Lesenswert?

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.

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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.

: Bearbeitet durch Moderator
von Einer K. (Gast)


Lesenswert?

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.c

Falk 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?

von Falk B. (falk)


Lesenswert?

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

von Einer K. (Gast)


Lesenswert?

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.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

bin auch von den Aussagen von Lothar und Falk irritiert. Zudem das 
Lothar mit dem blockierend nicht mir erklären muss sondern Stefanus.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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.

: Bearbeitet durch Moderator
von Falk B. (falk)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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
void yield()
2
{
3
  // tuwas
4
}
5
6
void setup() 
7
{
8
}
9
10
void loop() 
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
8
Geldstrafe bestraft.

von Stefan F. (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Arduino ist kein Multitasking System!

Puhliz, falls du dieses Thema (delay/Multitaksing) weiter vertiefen 
möchtest, dann habe ich "zufällig" etwas vorbereitet: 
http://stefanfrings.de/multitasking_arduino/index.html

Lothar M. schrieb:
> Dabei gibt es doch tolle Tutorials zum Thema "Hauptschleife mit millis()".

Och...

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

Arduino Fanboy D. schrieb:

Mein Gott, was hast du nur für ein Problem?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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
void yield()
2
 {
3
   // tuwas
4
   delay(1000); // und dann warte eine Sekunde
5
 }
6
 
7
 void setup()
8
 {
9
 }
10
 
11
 void loop()
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.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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
10
            {
11
                status=AUS;
12
            }
13
            
14
            if (status==EIN)
15
            {
16
                Was_ungeheuer_Wichtiges();
17
            }
Race-Condition umgangen.

: Bearbeitet durch Moderator
von Peter D. (peda)


Lesenswert?

Veit D. schrieb:
> Was machen Programmierer ohne Arduino Framework im
> klassischen Stil?

Die nehmen z.B. einen Scheduler:
1
volatile bool done;
2
3
void print_dot(void)
4
{
5
  Serial.print(".");
6
}
7
8
void print_nl(void)
9
{
10
  Serial.print("\n");
11
}
12
13
void print_st(void)
14
{
15
  schedule_remove(print_dot);
16
  schedule_remove(print_nl);
17
  Serial.println("Startklar ;D ");
18
  done = true;
19
}
20
21
int main(void)
22
{
23
  schedule_init();
24
  Serial.println("Bitte warten");
25
  schedule_add(print_dot, TICKS(0.5), TICKS(0.5));  // function, start time, repeat time
26
  schedule_add(print_nl, TICKS(1.5) + 1, TICKS(1.5));
27
  schedule_add(print_st, TICKS(4.5) + 2, 0);        // 0 = no repeat
28
  while (!done);
29
}

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Lothar M. schrieb:
> Das ist eine
> Race-Condition.

dein beispiel habe ich jetzt kappiert!

von Einer K. (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

Lothar M. schrieb:
> Race-Condition umgangen.

Nö.
Ein Interrupt kommt nicht nur an der Stelle, die Du willst, er könnte 
auch hier kommen:
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
            }
9
10
            if (akt_millis-warteSeit >= 105) // wenn 105ms verstrichen sind
11
            {
12
                status=AUS;
13
            }
14
            
15
            if (status==EIN)
16
            {
17
                Was_ungeheuer_Wichtiges();
18
            }

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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?

: Bearbeitet durch Moderator
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

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 ...

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

... 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();
}

von Peter D. (peda)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

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

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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...

von Peter D. (peda)


Lesenswert?

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.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

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.

von leo (Gast)


Lesenswert?

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

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

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 ...

von Stefan F. (Gast)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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...).

von Stefan F. (Gast)


Lesenswert?

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.

von Veit D. (devil-elec)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.