Hallo zusammen, ich habe mir das Arduino-Projekt "cosmic_raygun" angesehen und versuche gerade zu verstehen, wie das Programm (siehe Anhang) funktioniert. Zu Beginn wird in der "setup"-Routine dafür gesorgt, dass der Fire/Reload-Button als Eingänge, die LEDs und der Lautsprecher als Ausgänge konfiguriert werden. Außerdem wird mittels analogWrite(speakerGndPin,0) kein Ton ausgegeben. Meine Verständnis-Schwierigkeiten beginnen nun dort, wo das Hauptprogramm "loop" beginnt. Hier wird Zeit (in Millisekunden) seit der Konfiguration auf der seriellen Konsole ausgegeben und die LEDs zum Leuchten gebracht. Nun wird in einer Zustandsmaschine die Variable "myState" abgefragt, die initial mit 0 belegt ist. In diesem Zustand wird überprüft, ob "fireBtn" gedrückt ist. Wenn dem so ist, so wird in "fireTimer" die Zeit (in Millisekunden) seit der Konfiguration festgehalten und myState=1 eingeleitet. 1. Frage: Was passiert in myState==0, wenn der "fireBtn" nicht gedrückt ist? Wird dann dieser Zustand solange gehalten, bis dann tatsächlich mal der "fireBtn" betätgit wurde? In Zustand myState==1 wird nun folgendes überprüft: if (fireTimer+fireTime>millis()){ fire(); } else { myState=2; } 2. Frage: Der "fireTimer" wurde ja in myState==0 geladen, was genau passiert nun an dieser Stelle? Ich habe noch ein paar Fragen, aber vielleicht fangen wir mit den ersten beiden Fragen an. Vielleicht kann mir jemand ein paar Erklärungen mit auf den Weg geben, das wäre echt super. VG, Heinze
Heinze schrieb: > Nun wird in einer Zustandsmaschine die Variable "myState" abgefragt, die > initial mit 0 belegt ist. Nicht 'initial'. Immer dann, wenn myState den Wert 0 hat, wird dieser Zweig genommen. Ob initial oder später spielt keine Rolle. Sobald loop() aufgerufen wird UND myState auf 0 ist, geht es in diesen Zweig. > 1. Frage: Was passiert in myState==0, wenn der "fireBtn" nicht gedrückt > ist? Wird dann dieser Zustand solange gehalten, bis dann tatsächlich mal > der "fireBtn" betätgit wurde? Nachdem es dann keine Zuweisung an myState gibt, behält myState seinen Wert und ja, beim nächsten Aufruf von loop ist myState dann immer noch 0 und es geht wieder in diesen Zweig hinein, in dem dann eben wieder überprüft wird, ob der Fire-Button gedrückt ist. > In Zustand myState==1 wird nun folgendes überprüft: > > if (fireTimer+fireTime>millis()){ > fire(); > } else { > myState=2; > } > > 2. Frage: Der "fireTimer" wurde ja in myState==0 geladen, was genau > passiert nun an dieser Stelle? fireTimer + fireTime ergibt logisch gesehen was? Wenn du das Badewasser aufdrehst und dabei auf ide Uhr schaust und deine Uhr zeigt 16:00 Uhr, was ergeben dann diese 16:00 PLUS zusätzliche 10 Minuten. Das macht dann 16:10. Was könnte wohl der Sinn der Sache sein, wenn du dann laufend auf die Uhr schaust und die tatsächliche Zeit mit diesen 16:10 vergleichst und bei Überschreiten dieser Zeit etwas tust?
Der Aufruf von millis() führt ja zu einer ständig größer werdenden Zeit (in ms), während fireTimer+fireTime konstant bleibt. Kann diese Bedingung denn jemals TRUE werden? Ich glaube hier liegt mein Verständnisproblem. VG, Heinze
Heinze schrieb: > Der Aufruf von millis() führt ja zu einer ständig größer werdenden Zeit > (in ms), während fireTimer+fireTime konstant bleibt. Kann diese > Bedingung denn jemals TRUE werden? Natürlich. Auf deiner Uhr nimmt ja die Zeit auch laufend zu, wenn du mir mal die Annahme gestattest, dass du eine Armbanduhr hast, die nicht nach 60 Sekunden die Sekunden wieder zu 0 setzt und dafür die Minuten um 1 hochzählt. Gehen wir einfach mal davon aus, du hättest eine Armbanduhr die jeden Tag die vergangenen Minuten seit Mitternacht anzeigt. Dann hast du jeden Tag eine Zahl vor dir, die laufend größer wird. Jetzt, in diesem Moment liest du ab: 856 Diesen Wert merkst du dir unter dem Namen 'fireTimer' Jetzt zählst du da noch, sagen wir mal 10 dazu. Die 10 nenne ich jetzt einfach mal 'fireTime' wann also ist fireTimee + fireTime > aktuelle Zeit mal die Zahlenwerte einsetzen 856 + 10 > 856 ganz offensichtlich der Fall, denn 856 + 10 macht 866 Jetzt warten wir ein wenig. Sagen wir mal 1 Minute fireTimer + fireTime > aktuelle Zeit 856 + 10 > 857 ganz offensichtlich immer noch der Fall: die errechneten 866 sind immer noch größer als 857: TRUE Warten wir noch ein wenig. Seit dem Merken von FireTimer sind bereits 8 Minuten vergangen, deine Armbanduhr zeigt jetzt also schon 864 an fireTimer + fireTime > aktuelle Zeit 856 + 10 > 864 Immer noch der Fall. Wir warten weiter. Seit dem Merken des Wertes für fireTimer sind 10 Minuten vergangen (d.h. jetzt muss deine Armbanduhr bereits 866 anzeigen, denn fireTimer wurde ja zum Zeitpunk 856 gemerkt fireTimer + fireTime < aktuelle Zeit 856 + 10 > 866 Holla. Jetzt stimmt die Abfrage nicht mehr. 866 ist nicht mehr größer als 866 -> FALSE (Die Sache ist doch ganz simpel: Wenn es jetzt 14:25 ist und du jetzt die Herdplatte fürs Gulasch einschaltest und das Gulasch 26 Minuten kochen muss, wann ist es dann fertig? Das rechnest du dir aus (14:25 + 00:26) und dann schaust du dauernd auf die Uhr und siehst nach ob die Zeit schon erreicht ist bzw. ob es nicht sogar schon ein bischen später ist. Wenn die Uhr dann irgendwann 14:51 anzeigt, dann ist das Gulasch durch (wobei ein paar Sekunden drüber nichts ausmachen, denn du wirst es nicht schaffen exakt um 14:51:00.00000 auf die Uhr zu schauen. Also fragst du nicht ab ob die Endzeit genau erreicht ist, sondern ob du über die Endzeit drüber bist. Ob du dann um 14:51:00 oder 14:51:01 oder um 14:51:02 bemerkst, dass die Zeit um ist, spielt fürs Gulasch keine große Rolle. Daher fragst du das Ende nicht mit == ab, sondern mit > oder <, je nachdem, wie das dann genau formuliert ist.
Hallo Karl, ich mag deine Art und Weise, Dinge zu beschreiben :-) Jetzt habe ich die Abfrage verstanden. Werde erst einmal versuchen, die entsprechende Hardware zu bauen und mit dem Code herumzuspielen. Weitere Frage folgen bestimmt noch, versprochen! VG, Heinze
Heinze schrieb: > Hallo Karl, > > ich mag deine Art und Weise, Dinge zu beschreiben :-) Ach, du bist doch nur scharf auf mein Gulasch! :-) Im Ernst: Viele Programmierdinge verwenden wir jeden Tag in unserer Umgebung ohne uns dessen bewusst zu sein. Es lohnt sich also, sich selbst bzw. andere bei dem was wir tun, und vor allen Dingen wie sie es tun, zu beobachten. Man kann dabei viel darüber lernen, welche Strategien sich bewährt haben (und es daher wert sind, in algorithmischer Form weiterverwendet zu werden) und welche nicht.
Karl Heinz Buchegger schrieb: > denn du wirst es nicht schaffen exakt > um 14:51:00.00000 auf die Uhr zu schauen. Also fragst du nicht ab ob die > Endzeit genau erreicht ist, sondern ob du über die Endzeit drüber bist. > Ob du dann um 14:51:00 oder 14:51:01 oder um 14:51:02 bemerkst, dass die > Zeit um ist, spielt fürs Gulasch keine große Rolle. Daher fragst du das > Ende nicht mit == ab, sondern mit > oder <, je nachdem, wie das dann > genau formuliert ist. Verdammt Karl-Heinz... jetzt weiß ich endlich, warum mein Gulasch ständig anbrennt! ;-) Im Ernst: Gute Erklärung! Das Beispiel werd' ich mir merken, falls ich mal wieder ein paar Programmier-Novinzen solche Zeitberechnungen erklären muss.
@Heinze: Bei Fließkommazahlen gilt beim Programmieren übrigens eine ähnliche Vorgehensweise. Wegen Ungenauigkeiten beim Rechnen mit Fließkommazahlen (insbesondere Rundungsfehlern bzw. Umrechnungsfehlern von dezimale in binäre Darstellung), sollte man dabei nicht mit "==" vergleichen. Stattdessen vergleicht man ob die Differenz kleiner ist als ein relativ kleiner Wert. Um mal ein Beispiel zu geben: ---- CUT HERE ---- #include <stdio.h> #include <math.h> int main() { float a = 0.1f; float b = 0.2f; float c = 0.3f; if ((c-b) == a) { // das sollte man vermeiden! printf("Das wird nicht aufgeführt...\n"); } if (fabs( (c-b) - a ) < 0.001f) { // das ist besser printf("Das klappt immer.\n"); } return 0; } ---- CUT HERE ---- Die Ausgabe des Programms wird sein "Das klappt immer.". Von "Das wird nicht aufgeführt..." wirst Du wahrscheinlich nichts sehen. Zumindest hat es sich gerade bei mir beim Test auch so Verhalten (wie das zu erwarten ist). Warum ist das so? Laut Mathematik-Unterreicht sollte 0.3-0.2 = 0.1 sein... also sollte (c-b) auch 0.1 sein und da a = 0.1 ist, sollte (c-b) == a "true" ergeben. Das Problem ergibt sich wegen Umrechnung der Zahlen (0.1f, 0.2f und 0.3f) im Programmcode von dezimal (also so wie wir es in der Mathematik schreiben) in die rechnerinterne binäre Darstellung. Dabei treten Ungenauigkeiten auf. Schuld ist hier die Zahlensystem.... Ich lass die Details mal weg (kannst Du unter http://de.wikipedia.org/wiki/IEEE_754 nachlesen, wie das Funktioniert). Du kannst Dir einfach vorstellen, dass statt 0.3f in der Variable c sowas wie 0.29999999999987 drin steht. Und bei den anderen ist das genauso. Das passiert bei fast jeder Umrechnung von Dezimalschreibweise in die Fließkommadarstellung des Rechners... Fazit: Du musst bei Fließkommaberechnungen mit (double und float) immer davon ausgehen, dass nur "ungefähr" die Zahl raus kommt. Die Berechnung ist natürlich schon sehr genau (der Fehler ist irgendwo ganz weit hinten nach dem Komma), aber: eben nicht exakt. Und solche Fehler können sich aufsummieren. Stelle Dir vor Du rechnest: ((c-b)-a) * 10000000. Oder summierst ganz oft "(c-b)-a" auf. Für einfache Berechnungen wirst Du das Problem ignorieren können. Wenn aber mal komisches unerklärliches Verhalten bei Deinem Programm auftritt, erinner dich daran und prüf nach ob es nicht daran liegt... Grüße Stefan
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.