Hallo!!! Kann mir einer sagen ob ich irgendwann mal ein Problem mit dem AVR kriegen werde wenn ich meine Programme so schreibe: void prog1() { prog2(); ... ... } void prog2() { prog3(); ... } void prog3() { prog1(); ... . .. } weil die werden ja schließlich nicht richtig beendet oder?
Ja, du kriegst ziemlich bald einen Stacküberlauf. Mach lieber mal ne Schleife draus.
ja weil dir nach ein paar (m)s der Stack überläuft und dein Speicher alle ist.
Das Problem, das du da vollkommen richtig erkannt hast, ist die endlose Rekursion. Bei jedem Aufruf eines Unterprogramms landet mindestens eine Adresse auf dem Stack, um nach Beendigung des Unterprogramms wieder dort weitermachen zu können, wo vor Eintritt in das Unterprogramm aufgehört wurde. Irgendwann reicht der Speicher nicht mehr für weitere Adressen.
Du kannst ruhig sowas schreiben (obwohl es vollkommen sinnfrei ist). Schlimm wird es erst, wenn Du eines davon im Main aufrufst. Wenn man schon Rekursionen macht, dann nur über eine Funktion. Ansonsten verliert man ruckzuck den Überblick, wo und wann nun die Endebedingung der Rekursion ausgeführt wird. Peter
Da es zum Titel passt: Was macht ein AVR eigentlich wenn er am Ende von main() angekommen ist? Gru´ß Tom
Danke für die schnellen Antworten. Und wenn ich es so schreibe, dann ist es richtig? oder? void prog1() { prog2(); ... ... } int prog2() { if prog3()==1 return 1 else weiter ... } int prog3() { prog1(); ... . return 1 }
Thomas Burkhart schrieb: > Da es zum Titel passt: > > Was macht ein AVR eigentlich wenn er am Ende von main() angekommen ist? Der C-Standard schweigt sich darüber aus, was dann passieren muss. Beim gcc ist es so, dass der Code, der main() aufruft in eine Endlosschleife eintritt sobald main retourniert. Wenn mich nicht alles täuscht, werden dabei Interrupts sogar abgeschaltet.
Anfänger schrieb: > Danke für die schnellen Antworten. Und wenn ich es so schreibe, dann ist > es richtig? oder? Nein. Du hast nach wie vor das Problem, dass sich die Funktionen prog1, prog2 und prog3 wechselseitig 'im Kreis' aufrufen. (tm) Herr Kaiser: Ein Teufelskreis!
> Danke für die schnellen Antworten. Und wenn ich es so schreibe, dann ist > es richtig? oder? ich denke nicht, ist doch auch eine entlosschleife
> Beim gcc ist es so, dass der Code, der main() aufruft in eine > Endlosschleife eintritt. Wenn mich nicht alles täuscht, werden dabei > Interrupts sogar abgeschaltet. Ja, nach main wird _exit aufgerufen. Und die Default-Implementierung von _exit in der AVR-Libc enthält ein cli und eine Endlosschleife.
Peter schrieb:
> ich denke nicht, ist doch auch eine entlosschleife
Ja, aber die werden doch dann richtig beendet. und dann gibt es keinen
speicherüberlauf. Wie ich es verstehe.
Anfänger schrieb: > Danke für die schnellen Antworten. Und wenn ich es so schreibe, dann ist > es richtig? oder? Es ist immer noch vollkommener Schwachfug. Du hast überhaupt nicht darüber nachgedacht, was da passiert. Und Du hast vermutlich auch nicht die geringste Vorstellung, was Du eigentlich willst. Schalte bitte den PC aus, nimm Papier und Bleistift und male einen Programmablaufplan auf. Wenn der dann irgendwas sinnvolles tut, kannst Du den PC wieder einschalten. Peter
> Peter schrieb: > > ich denke nicht, ist doch auch eine entlosschleife > Ja, aber die werden doch dann richtig beendet. und dann gibt es keinen > speicherüberlauf. Wie ich es verstehe. wo wird denn etwas beendet?
Anfänger schrieb: > Ja, aber die werden doch dann richtig beendet. und dann gibt es keinen > speicherüberlauf. Wie ich es verstehe. Quatsch. Alles hinter dem unbedingten Aufruf einer Rekursion ist toter Code. Das Ende wird nie erreicht! Eine Rekursion muß immer eine Abbruchbedingung haben! Deshalb sollten Anfänger erst garkeine Rekursionen schreiben. Peter
Peter Dannegger schrieb: > Es ist immer noch vollkommener Schwachfug. > Du hast überhaupt nicht darüber nachgedacht, was da passiert. > Und Du hast vermutlich auch nicht die geringste Vorstellung, was Du > eigentlich willst. Tut mir leid: doch ich hab ein kleines Programm mit einem TSIC Temperatursensor und einem LCD-Display. Und das sieht halt so aus es funktioniert zwar aber ich hatte halt meine bedenken ob es auf dauer funktioniert. main() initialisierungen while() { menü(); } über das menü kann ich die temperaturanzeige aufrufen. menü { taste1 >> Anzeige(); einstellungen(); anzeige von einstellungen(); } und nach ca. 10 sekunden wechselt mein programm in ein stromsparmodus ohne LCD Anzeige() { 10sek warten; Anzeige ohne lcd(); "if anzeige ohne lcd == 1 dann menü nein dann weiter." } und von der anzeige ohne lcd gelange ich durch drücken von taster1 in das menü(); anzeige ohne lcd { taster1 >> menü(); "return 1;" taster2 >> anzeige(); "return 0;" } Mein programm ist ohne returns. Und das ist ja eine schlechte methode wie man es mir am anfang vom thread erklärt hatte. ich werde es halt mit "return" machen.
es geht nicht darum das keine "returns" vorhanden sind, es geht darum das du auch mal das Ende einer funktion erreichst. (Außer bei main sollte jede funktion auch mal beenden werden!)
Peter Dannegger schrieb: > Eine Rekursion muß immer eine Abbruchbedingung haben! > Deshalb sollten Anfänger erst garkeine Rekursionen schreiben. > Um Rekursion zu verstehen muss man Rekursion verstehen ;-) Aber dann bitte am Computer wo man schön grafisch (bzw. per Text) verfolgen kann was überhaupt passiert. Ich finde grad Anfänger sollten ein paar Rekursionsfunktionen testhalber schreiben und verstehen weil es ein wirklich grundlegendes Konzept ist und man auch verstehen kann was im Hintergrund passiert (bei iterativen Funktionen verschwendet doch keiner nen Gedanken an die Rücksprungadresse bzw.den Stack). Aber wenn man sowas testet dann wie schon erwähnt nicht am µC.
Anfänger schrieb: > und von der anzeige ohne lcd gelange ich durch drücken von taster1 in > das menü(); Ich dachte mir schon, dass es wohl so etwas wie eine Menüsteuerung wird. > > anzeige ohne lcd > { > taster1 >> menü(); > "return 1;" > taster2 >> anzeige(); > "return 0;" > } Nein. das machst du nicht so. Die Funktion "anzeige ohne lcd" liefert einen returncode, der dem Aufrufer mitteilt, wi es weiter geht. Der Aufrufer wertet den Code aus und entscheidet anhand dessen, was er weiter tun will. Das kann natürlich zb auch bedeuten, dass er selbst wieder einen Return Code an seinen Aufrufer übergibt, bis man dann irgendwann wieder in main() in der while Schleife zurück ist.
@Anfänger: Beschreib doch mal was das Programm machen soll. Die Struktur so wie sie ist sieht extrem merkwürdig aus, das geht garantiert besser...
Karl heinz Buchegger schrieb: >> Was macht ein AVR eigentlich wenn er am Ende von main() angekommen ist? > > Der C-Standard schweigt sich darüber aus, was dann passieren muss. Nicht ganz exakt: der Standard sagt, dass mit dem Rückkehrwert von main() die Funktion exit() gerufen wird. Von dieser wird dann implizit erwartet, dass sie in der Lage ist, das Programm auf irgendeine Weise zu beenden. Die Default-Implementierung von exit() erledigt dann die von dir beschriebene Endlosschleife, wobei die Applikation allerdings auch ihr eigenes exit() liefern kann. Streng genommen schreibt der Standard diese Vorgehensweise nur für eine `hosted application' vor, aber in diesem Modus wird der GCC in der Regel auch auf einem Controller betrieben, da er ja auch auf eine Standardbibliothek zurückgreift.
was ist eigentlich mit watchdogtimer? der ist doch dafür da, dass wenn sich der controller aufhängt. dann resetet wird.
cool danke, dann wäre das problem ja gegessen. weil ich eigentlich die heizung von meinem aquarium steuern möchte. will ich das es auch nach einem jahr funktioniert. und die eingestellten werte sind sowieso nachdem reset im eeprom gespeichert. Schönen Tag noch und danke für eure hilfe.
Nachtag: bin ja gespannt wo du in deiner "kaum vorhanden" Struktur den reset vom Watchdog einbaust. Ausdem wenn dein Stack überläuft ist das Verhalten vom Programm nicht mehr definiert, es kann auch passieren das du die armen kleinen Fische kochst.
Man baut ein Haus üblicher Weise nicht so, daß die Türen klemmen und man es nur über den Notausgang verlassen kann. Während der Entwicklung hat der Watchdog grundsätzlich aus zu bleiben, damit man seine Fehler auch sieht. Peter
ich werde jetzt mein menu in eine while-schleife schreiben und von dort aus meine verschiedene funktionen aufrufen. hab ich aus diesem beitrag: Beitrag "Menü (hängt)" und dann muss es doch funktionieren.
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.