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