Ich habe meinen ATTiny 26 mit BASCOM AVR 1.11 programmiert. Ich habe eine SUB, die einen Wert überprüft, 100ms wartet und sich dann selber neu aufruft, bis ein bestimmter Wert erreicht ist (Reziproke). Das sieht dann so aus: Sub Untens() 'Sub Beginn Waitms 100 'Warte 100ms Porta.0 = 1 'Setze den ersten Port auf 1 (5V) Unten = Getadc(7) 'Setzt die Variable Unten auf den Wert If Unten < 900 Then 'Fragt den Wert ab Call Untens() 'Ruft sich selbst noch mal aus Exit Sub 'Beendet sich selbst End If ' Waitms 400 'Warte 400ms Porta.0 = 0 'Setze ersten Port auf 0 (0V) Fertig = 1 'Setze Variable Fertig auf 1 End Sub ' Das Ganze funktioniert auch, doch wenn die Subrutine länger als 6000ms läuft ca. 60 mal sich selbst aufruft, stürtzt das ganze Programm ab. Ist es möglich, dass der ATTiny 26 mit solch einer Aufgabe überfordert ist und deswegen neu startet? Wie kann ich das Problem umgehen? Mit GoTo? Danke, MfG Ringelkrat PS: Konnte den Soucecode nicht als Dateianhang anhängen, da ich den auf einem anderen PC habe.
Stack overflow. Jeder Aufruf kostet 2 Bytes auf dem Stack. 128 Byte gibt's.
hi bei jedem neuen funktionsaufruf wird die rücksprungadresse auf den stack kopiert, der deshalb immer größer wird, und irgendwann wirst du dir damit das gesamte sram vollgestackt haben. rekursive programme sind bei systemen mit sehr kleinem ram (stack) nicht zu empfehlen! nides
jeder neue Aufruf belastet den Stack - irgendwann ist Schluss. Immer ein Problem bei Rekursionen. Man muss die max. Tiefe begrenzen, sonst kann es aus dem Ruder laufen. Dabei auch Interrupts beachten, die kosten auch nochmal Stack. Ebenso wichtig: wieviele Funktionsaufrufe hast du schon hinter dir, wenn du bei der rekursiven Funktion angelangt bist? Nützlich sind stack-end-marker, da kannst du in der Simulation sehen, ob das stackende erreicht wurde.
Und was mach ich jetzt? Wie soll ich das jetzt lösen? Mit GOTO, oder WHILE?
Wenn ich eine While-Schleife mach, wartet er dann, oder macht er mit dem Programm weiter (was unter der schleife steht)? while (unten < 900) unten = getadc(7) waitms 100 Wend Ringelkrat
das wär schon richtig so... er wartet, bis der adc einen wert größer oder gleich 900 liefert und macht dann erst weiter. und der stack bleibt wie er ist... alternativ könnte man das ganze auch mit nem goto lösen untens: unten = getadc(7) waitms 100 if unten < 900 then goto untens (ob das von der syntax her in ordnung ist kann ich nicht sagen weil ich seit langem kein bascom mehr benutzt hab...)
Also bevor man goto nimmt, müssen schon drei Rechner explodiert sein und 20 Internetforen nicht mehr weiterwissen. Nimm while.
Vielen Dank für die Hilfe und Erläuterung! Ich hab es jetzt mit einer While-Schleife gemacht und es funktioniert sehr gut. MfG Ringelkrat
möchte mal wissen, warum immer so ein Theater mit dem GOTO gemacht wird. Verteufelt bis zum geht nicht mehr, steht in vielen Büchern, und ganz viele plappern es plump nach. Klar, lässt sich eigentlich immer vermeiden, aber WARUM sollte man es vermeiden? Konnte mir noch keiner schlüssig erklären. Sprünge (unbedingte und bedingte) Sprünge kommen in jedem Programm vor, in Hochsprachen mehr oder weniger versteckt, in Assembler unvermeidbar (und sogar nützlich:-) Ich sehe ja ein, dass man nicht kreuz und quer durchs Programm springt, aber was spricht innerhalb einer Funktion dagegen? Und wo ist der Unterschied zwischen switch (test){ case 1: case 2: } oder if (test==1) goto ... else if (test==2)goto ... ? Das 1. hat den offiziellen Segen, mehr Unterschiede erkenne ich nicht.
Wäre "Rekursion" nicht ein treffenderer Titel für das Thema gewesen? "Reziprok" in diesem Zusammenhang lässt mich an Honoria Lucasta, der Dowager Duchess of Denver aus Dorothy L. Sayers vorzüglichen Kriminalromanen denken ...
Das erste ist viel übersichtlicher und zudem weniger Schreibarbeit als das zweite. Es hat schon seinen Sinn, dass goto "verteufelt" wird. Es mag sein, dass es bei embedded-Systemen, wenn man mit C programmiert ganz selten für ein Problem einfach keine elegantere/kleinere/schnellere Lösung als goto gibt. Dann sollte man aber genau wissen, was man tut und wieso es nicht anders geht. Ich halte es allerdings für falsch, einem Anfänger zu goto zu raten, da das gerade bei Beginnern zu einem schrecklichen Programmierstil führen kann, der dann beibehalten wird.
Wirf' den Basic-Compiler weg, denn er ist Schrott. Wenn er kein Schrott wäre, dann hätte der Compiler die Tail-Rekursion erkannt und die Stack-Benutzung weg optimiert. Ordentliche C-Compiler können das, z.B. der gcc... ;-) Es gibt aber auch viele Script-Sprachen, die Tail-Rekursion-Optimierung beherschen. Oder man verwendet gleich eine ordentliche Programmiersprache, z.B. Ocaml oder so. Denn so wie Du Dein Programm geschrieben hast, scheinst Du sehr fortschrittlich (funktional und rekursiv) zu denken. Nutze die Chance und verlasse das Imperative Lager so lange Deine Gedankengänge noch nicht versaut sind. Du scheinst Talent zu haben! Ich meine das übrigens ernst, nur für den Fall dass das jemand in den falschen Hals bekommen sollte!
@crazy horse: Versuch' die Sache mal aus einem anderem Blickwinkel zu betrachten: 1.) Für wen programmierst Du, bzw. wer liest Deinen Code? a.) Ein Computer b.) Ein Mensch (Du selbst zählst auch) 2.) Wer führt Dein Programm aus? a.) Ein Computer b.) Ein Mensch 3.) Bevorzugt der Computer ein bestimmte Variante, oder ist ihm schurz-piep egal? 4.) Wie denkt ein Mensch, wie organisiert und plant er seine Welt? Lebt er so: Schritt 1: Höre auf den Wecker. Schritt 2: Hat der Wecker geglingelt? Schritt 3: Wenn nein, gehe zu Schritt 1. Schritt 4: ... Oder so: - Solange der Wecker nicht klingelt, schlafe.
recht nettes Beispiel, aber programmtechnisch sehe ich auch da keinen Unterschied, denn bei deinem "solange der Wecker nicht klingelt" machst du ja auch nichts anders, als zu horchen, ob der Wecker nun klingelt und dann zurückzuspringen (oder eben nicht). Für Schleifen, gleich welcher Art, nutze ich goto auch nicht, ebensowenig käme ich auf die Idee, eine switch-Anweisung zu ersetzen, einen logischen Unterschied sehe ich aber nicht. Allerdings kommen mir immer wieder mal verschachtelte Schleifen unter, und dann scheint mir goto sehr nützlich. Sagen wir mal 3 Schleifen, Abbruchkriterien für das gesamte Konstrukt können in allen 3 Schleifen entstehen. Wie löst du das? Die äussere Schleife kann ich mit break (was ja auch wieder nur ein verkappter goto ist) verlassen - was mache ich, wenn ich auch aus der 2. oder 3. Schleife heraus das Ganze verlassen will?
variable setzten, in allen schleifen abfragen und wieder break. ist aber auch murks, da hast du vollkommen recht. da würd ich auch eher goto nehmen. mitlerweile wird einem ja leider sogar erzählt, dass man sogar ganz ohne break/continue auskommen soll, wäre ja alles keine 'strukturierte programmierung'* mehr * hiermit schlage ich dieses wort als computer-unwort des jahres vor
> bei deinem "solange der Wecker nicht klingelt" > machst du ja auch nichts anders, als zu horchen, ob der Wecker > nun klingelt und dann zurückzuspringen (oder eben nicht). Also ich schlafe nicht so. Das passiert interruptgesteuert und nicht gepollt.
Schön gesagt, aber wenn Du schläfst dann 'achtet' ja dein Körper auch auf die Umgebungsgeräusche. Sonst würdest du ja vom Klingeln nicht aufwachen. Mit diesem 'achten auf Umgebung' ist auch nur die abfrage eines sensors gemeint. um das ergebnis der abfrage zu interpretieren muss du auch (ggf in eine variable packen) und dann den wert mit einer if oder while bedingung überprüfen. damit heißt es doch auch dass du also ständig deinen umgebungssensor abfragst, oder eine variable, die die schlaf-subroutine unterbricht. wie auch immer, ihr werdet schon sehen, wie roboter besser schlafen werden als menschen.... ^^ Guten Morgen, Ringelkrat
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.