Warte Sequenz optimieren Arduino

Gast #5925086
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
#5925265
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 ");
#5925287
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 ");
Gast #5926432
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
#5926439
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.
#5926557
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.
Moderator (Firma: Titel) Persönliche Seite #5926620
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.
Gast #5926628
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?
Gast #5926656
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.
Moderator (Firma: Titel) Persönliche Seite #5926683
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.
#5926685
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.
Gast #5926710
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.
(Firma: @home) #5926744
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
Moderator (Firma: Titel) Persönliche Seite #5926749
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.
(Firma: @home) #5926761
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.
Moderator (Firma: Titel) Persönliche Seite #5926776
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.
#5926791
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
}
#5926837
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
            }
Moderator (Firma: Titel) Persönliche Seite #5926856
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?
(Firma: @home) #5926886
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();
}
#5926887
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.
Gast #5926910
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.
(Firma: @home) #5926938
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
Moderator (Firma: Titel) Persönliche Seite #5927032
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...).
Gast #5927072
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.
#5927342
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.
Gast #5928290
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren