Forum: Compiler & IDEs Ist die obligatorische Endlosschleife am Ende der main Funktion nur Aberglaube?


von Micha (Gast)


Lesenswert?

wahrscheinlich 'ne Frage, bei der die Antwort "nur" von akademischem 
Interesse ist...

Bisher hab ich immer, nach kritiklos übernommener Lehrmeinung, meine 
main mit einer Endlosschleife beendet.

Diese Tage stöber ich in der FAT32 Bibliothek herum, die von Daniel R. 
hier auf mikrocontroller.net eingestellt wurde.
Am Ende der main vom Beispielprogramm (das Ende wird im Ablauf 
tatsächlich erreicht) steht nix Endlosschleife, stattdessen ganz frech 
ein return. Und trotzdem passiert nichts schlimmes: das 
Raum-Zeit-Kontinuum gerät nicht aus den Fugen, das Programm startet 
nicht pausenlos neu, der Atmel verglüht nicht.

Hat mich jetzt ehrlich gesagt sehr überrascht. Ist die Endlosschleife am 
Ende der main Funktion Aberglaube, oder gibts eine sinnhaltige 
Begründung a la "guter Programmierstil"?

von Detlef K. (adenin)


Lesenswert?

1
#include <stdio.h>
2
3
int main()
4
{
5
   printf("Hallo Welt\n");
6
   return 0;
7
}
Damit wird die Endlichkeit des Universums bewiesen. ;)

von Bitflüsterer (Gast)


Lesenswert?

>Am Ende der main vom Beispielprogramm ...

Und welches Beispielprogramm meinst Du?

Bis dahin: main wird in mikrocontroller-Programmen niemals verlassen.

von Bitflüsterer (Gast)


Lesenswert?

Abgesehen davon, könntest Du ja mal einfaches Programm nehmen und im 
Simulator laden und im Einzelschrittbetrieb ausführen. Dann siehst Du, 
was geschieht.

von Yoda (Gast)


Lesenswert?

Viel zu lernen Du noch hast

von Floh (Gast)


Lesenswert?

Was stört dich daran, explizit hinzuschreiben, das das Programm zum 
Schluss warten soll?
Sich darauf verlassen, dass der Compiler das gewollt umsetzt ohne es 
hinzuschreiben fände ich gewagt.

von Falk B. (falk)


Lesenswert?

@ Floh (Gast)

>Sich darauf verlassen, dass der Compiler das gewollt umsetzt ohne es
>hinzuschreiben fände ich gewagt.

Darauf muss man sich nicht blind verlassen, das kann man im Handbuch des 
Compilers nachlesen. Und hier reden wir ja wahrscheinlich vom avr gcc. 
Der geht NACH dem Ende von main() in eine Endlosschleife mit gesperrten 
Interrupts.

von Bitflüsterer (Gast)


Lesenswert?

Dann kann man sich das tatsächlich sparen.

Seit welcher Version ist das eigentlich so?

von Falk B. (falk)


Lesenswert?

Schon ziemlich lange, ich schätze mal locker 10 Jahre.

von Ungläubiger (Gast)


Lesenswert?

Ist es nicht sinnvoller in den absoluten power down mode zu gehen?!

von Bitflüsterer (Gast)


Lesenswert?

Oh. Danke.

von Rolf Magnus (Gast)


Lesenswert?

Ungläubiger schrieb:
> Ist es nicht sinnvoller in den absoluten power down mode zu gehen?!

Sinnvoller ist es eher, das Programm selbst als Endlosschleife zu 
schreiben, so daß es gar nicht erst dazu kommt, daß man sich Gedanken 
darüber machen muß, was man am Ende von main() macht. µC-Programme gehen 
normalerweise eigentlich nicht einfach irgendwann zu Ende, sondern 
laufen bis zum Ende des Universums - oder so lange, bis der Depp von 
Benutzer den Saft abdreht, je nachdem, was zuerst kommt.

von Bitflüsterer (Gast)


Lesenswert?

Naja. Es hat jedenfalls (in der Regel) keinen Sinn, ein 
Mikrocontroller-Programm mit return aus main enden zu lassen, selbst 
wenn der GCC da als Gimmick noch selbst 'ne Schleife einbaut.
Soweit ist das wohl klar, oder?

von Ben (Gast)


Lesenswert?

Nur der Vollständigkeitshalber:
Der gcc macht hier kein Gimmick. Die Endlosschleife ist Teil des 
Startup-Codes und dieser ist Teil der C-Laufzeitumgebung, also meißtens 
der avr libc.

Sollte jemand den Drang verspüren ein eigenes Startup-File zu verwenden 
so muss er selber irgendwo für die Endlosschleife sorgen. Andernfalls 
kommt es wirklich zu undefiniertem Verhalten.

Ich würd zB nicht die Hand ins Feuer legen dass dieses "Feature" beim 
arm-none-eabi-gcc auch enthalten ist. Wie gesagt, Sache des 
Startup-Codes.

von Dr. Sommer (Gast)


Lesenswert?

Ben schrieb:
> Ich würd zB nicht die Hand ins Feuer legen dass dieses "Feature" beim
> arm-none-eabi-gcc auch enthalten ist.
Der enthält gar keinen Startup Code, bzw. nur einen Dummy den keiner 
verwendet.
> Wie gesagt, Sache des Startup-Codes.
Ja, und der wird vom Mikrocontroller-Hersteller geliefert. Der von ST 
für die STM32 enthält keine Endlosschleife, aber ein "bx lr", also 
return. lr wird 0xFFFFFFFF enthalten, und daher:
"A reset sets this register[=LR] to 0xFFFFFFFF. The reset value causes a 
fault condition if the processor uses it when attempting a subroutine 
return."
d.h. der Controller stürzt ab wenn man aus der main() zurückkehrt.

von Peter D. (peda)


Lesenswert?

Micha schrieb:
> Bisher hab ich immer, nach kritiklos übernommener Lehrmeinung, meine
> main mit einer Endlosschleife beendet.

Ein MC-Programm läuft bei mir immer solange, bis ihm der Saft abgedreht 
wird. Die Mainloop tut also ständig ihren Aufgaben und wird nie beendet.
Ich schreibe also weder eine leere Loop noch ein Return ans Ende des 
Main.

Vieleicht ganz am Anfang einer Entwicklung könnte es mal vorgekommen 
sein, daß die Main-Loop noch leer ist und ich erstmal nur die 
Initialisierung teste.

Theoretisch ist ein rekursives Main möglich, aber ich sehe auch darin 
keinen Sinn.

Das Return benötigt außerdem mehr Code, da Main vom Typ int ist, also 
der Returnwert geladen werden muß.

von Takao K. (takao_k) Benutzerseite


Lesenswert?

95% aller Programme verwenden eine Main loop.

Meistens sieht das so aus:
1
void main()
2
{
3
4
// initialisierungen
5
6
 while(1)
7
 {
8
 // etwas machen
9
 }
10
}

Genauso wie die meisten Autos an der Tankstelle aufgetankt werden. Musst 
du zwar nicht machen, ist aber allgemein so ueblich.

Ein typischer Fall von "Das ist halt so"

Sollte es wohl mal ein bayrisches Programmierhandbuch geben.
http://de.wikipedia.org/wiki/Bairische_Dialekte

von Dr. Sommer (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Ich schreibe also weder eine leere Loop
Keine leere Loop? Und was wenn man komplett Interrupt-basiert 
programmiert um verschiedene Dinge gleichzeitig tun zu können? Dann ist 
die mainloop leer, es sei denn man zählt ein asm("WFI") oder 
asm("SLEEP") als "nicht-leer"...

von Takao K. (takao_k) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Peter Dannegger schrieb:
>> Ich schreibe also weder eine leere Loop
> Keine leere Loop? Und was wenn man komplett Interrupt-basiert
> programmiert um verschiedene Dinge gleichzeitig tun zu können? Dann ist
> die mainloop leer, es sei denn man zählt ein asm("WFI") oder
> asm("SLEEP") als "nicht-leer"...

Programmcode gehoert nicht in die Interruptroutine. Also sofort wieder 
verlassen. Es geht zwar, wenn es nur einen Interrupt level gibt, jedoch 
moderne Prozessoren haben u.U. mehrere.

Um verschiedene Dinge gleichzeitig tun zu koennen, wird oft ein "Round 
Robin" Konstrukt in der main loop verwendent.

Komplett Interrupt-basiert? Entweder verwendest du Interrupts, und dann 
wird die Programausfuehrung wohl durch einen Timer kontrolliert 
(Zeitscheiben Verfahren). Oder du verwendest keine Interrupts.

Die meisten professionellen Programme gehen so vor, also es wird ein 
Zeitscheiben Verfahren verwendet.

z.B. 1mSec. als Grundtakt, Interrupt, und dann einfach Zaehler 
verwenden, und Unterprogramme ausfuehren.

von Dr. Sommer (Gast)


Lesenswert?

Takao K. schrieb:
> Programmcode gehoert nicht in die Interruptroutine. Also sofort wieder
> verlassen.
Warum? Sind Interrupts irgendwie böse?
> Es geht zwar, wenn es nur einen Interrupt level gibt, jedoch
> moderne Prozessoren haben u.U. mehrere.
Das ist doch gut, kann man zur Priorisierung nehmen.

> Um verschiedene Dinge gleichzeitig tun zu koennen, wird oft ein "Round
> Robin" Konstrukt in der main loop verwendent.
>
> Komplett Interrupt-basiert? Entweder verwendest du Interrupts, und dann
> wird die Programausfuehrung wohl durch einen Timer kontrolliert
> (Zeitscheiben Verfahren). Oder du verwendest keine Interrupts.
Timer nur wenn man Delays braucht. Ansonsten halt bei Interrupts auf das 
geschehene Ereignis reagieren, eine Aktion ausführen und auf den 
nächsten Interrupt warten.
> Die meisten professionellen Programme gehen so vor, also es wird ein
> Zeitscheiben Verfahren verwendet.
Asynchrone, also event-basierte Programmierung gilt schon länger als 
schick, das heißt in Event-Handlern - also ISR's - auf das Ereignis 
reagieren und dort etwas tun. Die mainloop tut dann nichts als warten.

von Takao K. (takao_k) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Takao K. schrieb:
>> Programmcode gehoert nicht in die Interruptroutine. Also sofort wieder
>> verlassen.
> Warum? Sind Interrupts irgendwie böse?

Ja, diese vebrauchen sehr viel Zeit, insbesondere, wenn die Granulierung 
zu fein ist.

>> Es geht zwar, wenn es nur einen Interrupt level gibt, jedoch
>> moderne Prozessoren haben u.U. mehrere.
> Das ist doch gut, kann man zur Priorisierung nehmen.
>

Es gibt schon Anwendungen, die Interrupts unbedingt erfordern, z.B. IR 
Daten auslesen wenn sich ein Pin aendert.

Oder um auf USB zu reagieren. Dies ist dann oft schon vorprogrammiert.

PIC32 kann z.B. auch DMA

>> Um verschiedene Dinge gleichzeitig tun zu koennen, wird oft ein "Round
>> Robin" Konstrukt in der main loop verwendent.
>>
>> Komplett Interrupt-basiert? Entweder verwendest du Interrupts, und dann
>> wird die Programausfuehrung wohl durch einen Timer kontrolliert
>> (Zeitscheiben Verfahren). Oder du verwendest keine Interrupts.
> Timer nur wenn man Delays braucht. Ansonsten halt bei Interrupts auf das
> geschehene Ereignis reagieren, eine Aktion ausführen und auf den
> nächsten Interrupt warten.

Eine blinkende LED ist schon sinnvoll um zu sehen ob das Programm noch 
einwandfrei abgearbeitet wird. Also vewende ich immer einen Timer 
interrupt, meistens zwischen 1 KHz und 10 KHz.

>> Die meisten professionellen Programme gehen so vor, also es wird ein
>> Zeitscheiben Verfahren verwendet.
> Asynchrone, also event-basierte Programmierung gilt schon länger als
> schick, das heißt in Event-Handlern - also ISR's - auf das Ereignis
> reagieren und dort etwas tun. Die mainloop tut dann nichts als warten.

Ja schon richtig aber es ist besser, nur ein Flag zu setzen, oder eine 
Nachricht zu generieren, und den Interrupt sofort wieder zu verlassen.

Insbesondere wenn mehrere Interrupts moeglich sind, wird die 
Programmierung sonst langsam und kompliziert.

Also nur die interrupt Flags abfragen, und falls eins gesetzt ist, 
sofort verlassen.

Damit kann auch die Prioritaet geloest werden:

Zum einen durch die Reihenfolge der Abarbeitung der Nachrichten. Und zum 
anderen kann ein kritischer Interrupt eigentlich immer sofort 
stattfinden. So einen oder zwei kann man schon direkt abarbeiten, also 
in der ISR, wenn z.B. nur Daten fuer die serielle Schnittstelle 
nachgeladen werden sollen.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Takao K. schrieb:
> Dr. Sommer schrieb:
>> Takao K. schrieb:
>>> Programmcode gehoert nicht in die Interruptroutine. Also sofort wieder
>>> verlassen.
>> Warum? Sind Interrupts irgendwie böse?
>
> Ja, diese vebrauchen sehr viel Zeit, insbesondere, wenn die Granulierung
> zu fein ist.

Du bist du mir mit deinen Aussagen etwas zu sehr auf der 
ultra-Konservativen Seite.

Lies lieber erst mal eine zeitlang mit, dann weißt du auch gegen wen du 
argumentierst. Die Leute hier, die haben nämlich Ahnung von dem was sie 
tun. Die machen das schon 'ein paar' Jährchen lang. Beruflich.

> Ja schon richtig aber es ist besser, nur ein Flag zu setzen, oder eine
> Nachricht zu generieren, und den Interrupt sofort wieder zu verlassen.

In einer ISR wird getan, was zu tun ist. Und ja, das kann auch bedeuten 
eine (kurze) Bearbeitung eines Sachverhaltes in die ISR zu setzen.

Wenn es länger dauert, dann wird ein Jobflag bemüht.
Die Aussage "alles wird immer und unbedingt immer in einer ISR gemacht" 
ist genauso falsch wie "man darf gar nichts in einer ISR machen ausser 
ein Flag zu setzen". Man entscheidet im Einzelfall, welche Strategie 
implementiert wird.

> Insbesondere wenn mehrere Interrupts moeglich sind, wird die
> Programmierung sonst langsam und kompliziert.

Quatsch.
Überhaupt nichts wird deswegen komplizierter, wenn man einen Multiplex 
in eine Timer-ISR setzt oder in einer Timer-ISR eine Software Uhr 
hochzählt. Auch wird nichts kompliziert, wenn man in der Receive ISR des 
UART das Zeichen holt und in einen Ringbuffer stellt. Genauso wie 
umgekehrt nichts komplliziert wird, wenn man die Ausgabe auf die UART 
erst mal in einen Buffer stellt und dann Uart Transmit Interrupt 
getrieben die Zeichen über die UART rausbläst. Und es gibt noch 
Millionen anderer Beispiele, in denen die Berabeitung eines Ereignisses 
sinnvollerweise komplett in der ISR abgehandelt wird.

Wenn man diese Dinge anders macht, dann wird es kompliziert.

: Bearbeitet durch User
von Humpfdidumpf (Gast)


Lesenswert?

@ Dr. Sommer

> Keine leere Loop? Und was wenn man komplett Interrupt-basiert
> programmiert um verschiedene Dinge gleichzeitig tun zu können? Dann ist
> die mainloop leer, es sei denn man zählt ein asm("WFI") oder
> asm("SLEEP") als "nicht-leer"...

Also nur weil man Interrupts verwendet, kann man doch trotzdem alles in 
das Loop im Main hineinschreiben? Was spricht da dagegen?

Ich mach das immer so:
ich setze mir in der ISR nur ein Flag und arbeite im loop in der Main 
alle Flags "ab". Ist keins mehr übrig, wird idle() gemacht. Dazu gibts 
einen Timer, das alle 100ms oder so den Prozessor aus dem Idle holt, für 
den kleinen Rest der gepollt werden will.
Ich dachte immer, das loop im main wäre genau dazu gut? Oder macht man 
das so nicht? Wäre echt interessant, wie das andere lösen!
Bei mir funktionerts bisher ganz gut, auch mit 10 "Tasks". Besser wäre 
natürlich ein RTOS mit echtem Multitasking.

Zu den Interrupts:
Die verbrauchen schon Zeit, diese steht aber im Datenblatt: "Interrupt 
Latency". Das liegt so im Bereich von 10-20Takten glaube ich, je nach 
Ziel. Relevant ist es nur dann, wenn man die Interrupts in hoher 
Frequenz hat, z.B. alle 10µs.
Die verlorene Zeit kann man leicht woanders einsparen, z.B. wenn man den 
DMA verwendet. Das spart auch eine Menge Interrutps.

von Klaus (Gast)


Lesenswert?

Humpfdidumpf schrieb:
> ich setze mir in der ISR nur ein Flag und arbeite im loop in der Main
> alle Flags "ab".

Dann brauchst du eigentlich garkeine Interrupts sondern kannst die 
Interruptflags direkt in der main loop abarbeiten.

MfG Klaus

von old man (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Asynchrone, also event-basierte Programmierung gilt schon länger als
> schick, das heißt in Event-Handlern - also ISR's - auf das Ereignis
> reagieren und dort etwas tun. Die mainloop tut dann nichts als warten.

Besser und kürzer kann man den aktuellen Schwachsinn nicht formulieren. 
"Gilt als schick". Allein diese Aussage sagt schon alles. Normaler 
Verstand wird durch Herdentrieb ersetzt. Nichts gegen JavaScript z.B. im 
Browser. Wenn aber mittlerweile so eine Halbsprache in Form von nodejs, 
und dazu noch eventgetrieben, auf dem Server zum Einsatz kommt und 
gefeiert wird, dann kann man PHP und Konsorten als Hochsicherheitstrakt 
bezeichnen.

Interrupts auf einem Controller sollte man schon mit Bedacht einsetzen 
und auch auf das nötige Beschränken. Ich stelle mir gerade vor wie 
jemand im Interrupt auf ein eingehendes Ethernetpacket reagiert und eine 
Webseite ausliefern will.... Wenn dann noch ein paar zeitkritische 
Interrupts nötig sind um z.B. nur einen popeligen DS18S20 abzufragen 
geht der Eiertanz los. Soll das dann auch aus dem Ethernethandler 
bedient werden? Mann oh Mann, hoffentlich kriege ich sowas nicht mit dem 
nächsten Auto angedreht.

von Rolf Magnus (Gast)


Lesenswert?

Takao K. schrieb:
> 95% aller Programme verwenden eine Main loop.

Und was machen die anderen 5%? Mir ist noch nie ein µC-Programm über den 
Weg gelaufen, das sich beendet. Ich wüßte auch keinen Anwendungsfall 
dafür.

Dr. Sommer schrieb:
> Takao K. schrieb:
>> Programmcode gehoert nicht in die Interruptroutine. Also sofort wieder
>> verlassen.
> Warum? Sind Interrupts irgendwie böse?

Man sollte sie zumindest möglichst kurz halten und am besten keine 
non-inline-Funktionen aufrufen. In einer UART-Rx-ISR das empfangene 
Zeichen in einen Puffer eintragen oder in einer Timer-ISR eine Uhr 
hochzählen ist noch ok, aber viel mehr würde ich da nicht machen. Die 
eigentliche Arbeit gehört ins Hauptprogramm oder bei einem RTOS in 
Tasks.

>> Komplett Interrupt-basiert? Entweder verwendest du Interrupts, und dann
>> wird die Programausfuehrung wohl durch einen Timer kontrolliert
>> (Zeitscheiben Verfahren). Oder du verwendest keine Interrupts.
> Timer nur wenn man Delays braucht. Ansonsten halt bei Interrupts auf das
> geschehene Ereignis reagieren, eine Aktion ausführen und auf den
> nächsten Interrupt warten.

Bei sehr einfachen Programmen könnte man sich das vorstellen.

> Asynchrone, also event-basierte Programmierung gilt schon länger als
> schick, das heißt in Event-Handlern - also ISR's - auf das Ereignis
> reagieren und dort etwas tun. Die mainloop tut dann nichts als warten.

Die ISRs "handlen" keine Events, sondern generieren sie. In der 
Main-Loop laufen dann alle Events zusammen, und da werden sie dann 
"gehanlet". Das ist genau das selbe Konzept wie bei GUI-Anwendungen auf 
dem PC.

von Humpfdidumpf (Gast)


Lesenswert?

@Klaus
das habe ich auch schon versucht, das geht auch. Es hat aber so sein 
Tücken, hauptsächlich wegen der Stromsparmodi und dem Echtzeitzeugs.

Wenn man das so macht, kann man Idle oder Sleep nicht gut verwenden, 
weil eine zeitnahe Abarbeitung der Flags nicht funktioniert- man hat 
immer das Delay bis zum nächsten "Systemtick". Alles reagiert im 
Endeffekt mit dem Systemtick verzögert. Man kann natürlich den Tick 
kürzer machen, das kostet aber Strom.
Und dann sind da noch die zeitkritischen Sachen, z.B. Buffer ausleeren 
und ähnliches, das in der ISR gemacht wird. Hat man keine ISR, muss das 
main loop schnell genug durchlaufen.

Verwendet man jetzt Interrupts, reagiert das System schnell und braucht 
wenig Energie. Die Kombination hats für mich gebracht.

Sicher gibt es aber elegantere Lösungen.
Allgemeingültige Lösungen gibt es ja sowieso nie...
Kann jemand dazu ein gutes Buch empfehlen?

von Peter D. (peda)


Lesenswert?

Dr. Sommer schrieb:
> Keine leere Loop? Und was wenn man komplett Interrupt-basiert
> programmiert um verschiedene Dinge gleichzeitig tun zu können? Dann ist
> die mainloop leer

Dann machst Du Dir den Vorteil der Interrupts ja wieder kaputt.
Interrupts können das Main unterbrechen, aber wenn das Main leer ist, 
muß wieder jeder auf den anderen warten, bis der fertig ist.
D.h. Du kannst Dir die Interrupts gleich schenken und im Main nur die 
Flags pollen. Und das ist sogar schneller, da Du keine Registerrettungs 
und Restore Arie veranstalten mußt.
Jede Mainroutine kann die Scratchpadregister einfach benutzen, ohne 
Push/Pop. Der Interrupt weiß aber nicht, daß das Main leer ist, er muß 
alles erst sichern.

In der Praxis sieht man eine leere Mainloop daher nur bei Anfängern, die 
nur einfache Aufgaben programmieren.
Bei komplexeren Anwendungen hat der Verzicht auf einen Ausführungslevel 
nur Nachteile.

von Michael A. (micha54)


Lesenswert?

Rolf Magnus schrieb:
> Die ISRs "handlen" keine Events, sondern generieren sie. In der
> Main-Loop laufen dann alle Events zusammen, und da werden sie dann
> "gehanlet". Das ist genau das selbe Konzept wie bei GUI-Anwendungen auf
> dem PC.

Hallo,

also ISRs generieren keine events, sie setzen bestenfalls Flags.

Eventhandler warten auf Events ohne die CPU zu benühen, also ohne 
Polling.

Gruß,
Michael

von Rolf Magnus (Gast)


Lesenswert?

Michael Appelt schrieb:
> Rolf Magnus schrieb:
>> Die ISRs "handlen" keine Events, sondern generieren sie. In der
>> Main-Loop laufen dann alle Events zusammen, und da werden sie dann
>> "gehanlet". Das ist genau das selbe Konzept wie bei GUI-Anwendungen auf
>> dem PC.
>
> Hallo,
>
> also ISRs generieren keine events, sie setzen bestenfalls Flags.

Das kommt sicher drauf an, wie man "Event" definiert. Ein von der ISR 
gesetztes Flag ist letztendlich auch nur eine sehr einfache Form eines 
Events. In komplexeren Fällen sind es dann eigene Objekte, die in einer 
Queue zwischengespeichert werden und ggf. noch zusätzliche Informationen 
enthalten.

> Eventhandler warten auf Events ohne die CPU zu benühen, also ohne
> Polling.

Eventhandler können blockierend sein oder auch nicht, je nach 
Anwendungsfall. Und auch die Mainloop auf dem AVR kann ohne CPU-Last 
warten, wenn man den sleep-Mode benutzt.

von Takao K. (takao_k) Benutzerseite


Lesenswert?

Karl Heinz schrieb:

> Lies lieber erst mal eine zeitlang mit, dann weißt du auch gegen wen du
> argumentierst. Die Leute hier, die haben nämlich Ahnung von dem was sie
> tun. Die machen das schon 'ein paar' Jährchen lang. Beruflich.
>

Ja mach ich.

> In einer ISR wird getan, was zu tun ist. Und ja, das kann auch bedeuten
> eine (kurze) Bearbeitung eines Sachverhaltes in die ISR zu setzen.
>
> Wenn es länger dauert, dann wird ein Jobflag bemüht.
> Die Aussage "alles wird immer und unbedingt immer in einer ISR gemacht"
> ist genauso falsch wie "man darf gar nichts in einer ISR machen ausser
> ein Flag zu setzen". Man entscheidet im Einzelfall, welche Strategie
> implementiert wird.
>

Ist schon richtig. Hab ich ja nicht gesagt "Man darf nichts in einer ISR 
machen". Nach einiger Zeit bewerte ich Programme als besser wartbar, 
wenn die ISR/ ISRs klein gehalten werden. So ca. 200 Programme.

>> Insbesondere wenn mehrere Interrupts moeglich sind, wird die
>> Programmierung sonst langsam und kompliziert.
>
> Quatsch.
> Überhaupt nichts wird deswegen komplizierter, wenn man einen Multiplex
> in eine Timer-ISR setzt oder in einer Timer-ISR eine Software Uhr
> hochzählt.

Wenn der Programmierer qualifiziert ist, kann es schon in Ordnung sein.

Hatte ich aber bereits in der ISR und seit einiger Zeit mache ich es 
nicht mehr.

Zugegebenermassen habe ich mich auch veraendert, also z.B. Assembler 
aufgegeben, und den Sprung von 8bit zu 32bit gemacht. Wenn ich 
Assemblerprogrammierung miteinbeziehe programmiere ich seit Ende 1990er 
Jahre.

Allzu dramatisch ist es garnicht mit ISR, also in den meisten Faellen, 
insofern der Programmierer einigermassen qualifiziert ist, kann es wohl 
weitgehend egal sein, vielleicht nur eine Frage des Programmierstils.

Ohne den Programmcode zu sehen, moechte ich es nicht bewerten im Sinne 
"Darf man nicht oder sollte man nicht machen".

von Karl H. (kbuchegg)


Lesenswert?

Michael Appelt schrieb:

> also ISRs generieren keine events, sie setzen bestenfalls Flags.

Mit dieser Verallgemeinerung bin ich nicht einverstanden.
So ist das Quatsch.

Denn ich werde beispielsweise die Timer-ISR, die eine LED-Matrix 
multiplext ganz sicher nicht mittels Jobflag und Behandlung in der 
Main-Loop machen.

Die Antwort lautet immer noch:
Es hängt davon ab. Wenn die notwendige Behandlung kurz ist und nicht 
viel Zeit verbraucht oder wenn sie unbedingt schnellstmöglich erfolgen 
muss, dann mache ich die Behandlung des Ereignisses direkt in der ISR. 
Genauso, wenn ich die Zeit habe. Es ist nämlich recht sinnlos eine 
Timergetriebene blinkende LED mittels Job-Flag in der Mainloop behandeln 
zu lassen. Selbst wenn die Behandlung etwas länger dauert (ich rede 
immer noch von Sekundenbruchteilen), es aber im Gesamtsystem absolut 
nicht zeitkritisch ist, dann gebe ich dem einfacheren Code ebenfalls den 
Vorzug, als einer vollgestopften Main-Loop.

von Karl H. (kbuchegg)


Lesenswert?

Takao K. schrieb:

>> Quatsch.
>> Überhaupt nichts wird deswegen komplizierter, wenn man einen Multiplex
>> in eine Timer-ISR setzt oder in einer Timer-ISR eine Software Uhr
>> hochzählt.
>
> Wenn der Programmierer qualifiziert ist, kann es schon in Ordnung sein.

Nein, nicht wenn der Programmierer "qualifiziert" ist.

Ein einer Led-Matrix ist es wichtig, dass das Multiplexing regelmässig 
und zuverlässig erfolgt. Bis auf absolute Notfälle (Kernkrfatwerk wegen 
Kernschmelze runterfahren), hat das Priorität vor allem anderen. Das 
wird komplett in der ISR durchgezogen, denn der Multiplex kann nicht 
darauf warten, dass dann endlich mal der Messwert vom ADC umgerechnet, 
aufbereitet und per UART auf den Weg gebracht wurde.

In so einem Fall fangen die Probleme genau dann an, wenn du die 
komplette Multiplex-Funktionalität NICHT in der ISR hast. Während es 
anders rum (also Multiplexing komplett in der ISR) trivial ist.

Selbiges mit einer Software-Uhr. Es ist wichtig, dass das Weiterzählen 
einer Uhr nicht unterbrochen wird und zuverlässig erfolgt. Sonst 
verliert man in der Uhr zeit und die Uhrzeit stimmt nicht mehr.

Selbiges bei der Generierung von Servo-Signalen. Die Puls müssen 
zuverlässig rausgehen. Wenn sie sich mal um ein paar µs verzögern (weil 
vorher noch die Multiplex ISR fertig abgearbeitet wird), dann ist das 
wesentlich weniger schlimm, als wenn die Servos 30° Ruckler machen, weil 
per UART unbedingt eine Statusmeldung ausgegeben werden muss oder gerade 
eine komplexe Bahnberechnung läuft und deshalb die Pulsgenerierung 
steht, weil die Main-Loop damit beschäftigt ist und erst eine halbe 
Sekunde später wieder zur Abfrage des Jobflags kommt.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rolf Magnus schrieb:
> Mir ist noch nie ein µC-Programm über den Weg gelaufen, das sich
> beendet.

In dem Fall ging es doch um ein Beispielprogramm.  Das Ding hat
nach dem Ende des Beispiels einfach nichts mehr, was es noch tun
könnte.

Hab' ich auch schon gemacht.  Neustart halt nur mit dem Reset-Knopf.
Ist natürlich zugegebenermaßen selten (ich würde 0,05 % statt 5 %
dafür ansetzen).

von Dr. Sommer (Gast)


Lesenswert?

Bei dem was hier abgeht darf man Nachts gar nicht schlafen gehen...

Ich versteh euch alle nicht. Ob ein "langer Task" jetzt seine Zeit in 
der main() oder in der ISR verbraucht, wo ist der Unterschied? Richtige™ 
Controller können nicht umsonst verschachtelte und priorisierte 
Interrupts, da kann man die timingkritische Abhandlung vom LED-Blinker 
oder AKW-Abschalter oder wasauchimmer in einen Hoch-Prioritären 
Timer-Interrupt etc stecken. Wenn man in ISR's nur Flags setzt kann man 
sich die ISR auch gleich sparen und in der main() einfach das 
entsprechende Interrupt-Flag der Peripherie-Einheit auslesen - wozu das 
Flag "in Software" nochmal duplizieren?

Peter Dannegger schrieb:
> Jede Mainroutine kann die Scratchpadregister einfach benutzen, ohne
> Push/Pop. Der Interrupt weiß aber nicht, daß das Main leer ist, er muß
> alles erst sichern.
Beim AVR sind ISR-Entries's vielleicht langsam, aber beim Cortex-M z.B. 
sinds 12 Takte inkl. automatischem Push...

Rolf Magnus schrieb:
> Die ISRs "handlen" keine Events, sondern generieren sie.
Man kann auch den Interrupt an sich als Event betrachten, und die ISR 
als Event-Handler... Solche asynchrone/Event/Callback-gesteuerte 
Programmierung ist sehr beliebt da sie jederzeit sofortige Reaktionen 
auf Evens ermöglicht (da die Behandlung im Callback geschieht) und nicht 
erst auf ein Freiwerden der mainloop gewartet werden muss (falls die 
grad mit was langem beschäftigt ist).

old man schrieb:
> Besser und kürzer kann man den aktuellen Schwachsinn nicht formulieren.
Dieser aktuelle Schwachsinn wird seit Dekaden so gemacht. z.B. am PC - 
keiner mag Programme, die bei einer I/O-Operation (wie read) blockieren 
und nicht bedienbar sind, wenn das Programm auch asynchron auf die 
Fertigstellung warten und währenddessen weiterlaufen könnte.
> Interrupts auf einem Controller sollte man schon mit Bedacht einsetzen
> und auch auf das nötige Beschränken. Ich stelle mir gerade vor wie
> jemand im Interrupt auf ein eingehendes Ethernetpacket reagiert und eine
> Webseite ausliefern will.... Wenn dann noch ein paar zeitkritische
> Interrupts nötig sind um z.B. nur einen popeligen DS18S20 abzufragen
> geht der Eiertanz los. Soll das dann auch aus dem Ethernethandler
> bedient werden?
Wer Ethernet an nem AVR ohne Interrupt-Prios macht ist halt selber 
schuld. Ansonsten die Verarztung vom DS18S20 in einen Höher-prioritäten 
Interrupt stecken.

old man schrieb:
> Mann oh Mann, hoffentlich kriege ich sowas nicht mit dem
> nächsten Auto angedreht.
Keine Sorge, da ist nur klicki-bunti-grafische Programmierung verbaut...

von Y2 (Gast)


Lesenswert?

Dr. Sommer schrieb:
>> Wie gesagt, Sache des Startup-Codes.
> Ja, und der wird vom Mikrocontroller-Hersteller geliefert. Der von ST

Um nochmal zum Thema zurückzukommen. Diese Aussage ist absoluter 
Schwachsinn. Der Startupcode gehört zu den Teilen um den ich mich als 
Programmierer schon noch selbst kümmern sollte. Und wenn ich ein 
Beispiel oder Default vom MC-Hersteller oder dem Hersteller der IDE oder 
sonstwas verwende, was da passiert sollte man schon wissen. Wenn man das 
gemacht hat erübrigt sich die Frage von ganz oben eigentlich von selbst.

Dr. Sommer schrieb:
> Dieser aktuelle Schwachsinn wird seit Dekaden so gemacht. z.B. am PC -
> keiner mag Programme, die bei einer I/O-Operation (wie read) blockieren
> und nicht bedienbar sind, wenn das Programm auch asynchron auf die
> Fertigstellung warten und währenddessen weiterlaufen könnte.

Was hat das eine mit dem anderen zu tun? Es gibt auch Möglichkeiten mit 
synchronen IOs zu arbeiten und trotzdem nicht zu blockieren. Dass eine 
heutige GUI eventgetrieben ist brauchst du sicherlich keinen mehr 
erläutern. Darum ging es aber nicht. Der Einsatz von RTOS-Systemen auf 
einem MC oder der Multithreadprogrammierung auf dem PC ist unter anderem 
auch entstanden weil große Projekte die extensiv asynchron arbeiten 
irgendwann unwartbar werden. Für den entsprechenden Zweck das richtige 
Modell zu wählen ist die Kunst des Softwarearchitekten. Sich danach zu 
richten was gerade schick ist zeugt nicht von Intelligenz und darum ging 
es mir. Leider wird gerade mit nodejs wieder so eine neue Kuh durchs 
Dorf getrieben die wiedermal verspricht das allein selig machende zu 
sein.

Dr. Sommer schrieb:
> Man kann auch den Interrupt an sich als Event betrachten, und die ISR
> als Event-Handler... Solche asynchrone/Event/Callback-gesteuerte
> Programmierung ist sehr beliebt
                      |
Womit wir wieder beim Herdentrieb wären...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Y2 schrieb:
> Der Startupcode gehört zu den Teilen um den ich mich als Programmierer
> schon noch selbst kümmern sollte.

Ansichtssache.  Es gibt Umgebungen (AVR-GCC / avr-libc bspw.), bei
denen ist der mitgelieferte Startup-Code ausreichend gut ausgefeilt,
dass er problemlos 99,99 % aller Anwendungen abdeckt.

Wenn du eine PC-Applikation schreibst (egal welches OS), führst du dir
dann auch erst den Startup-Code des Compiler-Herstellers zu Gemüte?

von Dr. Sommer (Gast)


Lesenswert?

Y2 schrieb:
> Um nochmal zum Thema zurückzukommen. Diese Aussage ist absoluter
> Schwachsinn. Der Startupcode gehört zu den Teilen um den ich mich als
> Programmierer schon noch selbst kümmern sollte.
Ah. Wenn das so ist. Ich würde mal behaupten die meisten C-Programmierer 
hier im Forum haben noch nie was von Startupcode oder Linkerscript 
gehört... Und die Leute die bei uns an der HS aus den ETechnik oder 
Informatik-Studiengängen rauskommen auch nicht. Die freuen sich einfach 
wenn alle globalen Variablen initialisiert sind und die main() 
aufgerufen wird. Was will man da auch selber noch machen? Erstmal die 
ganzen Compiler&Linker Interna lernen, nur um globale Variablen mit 
seinem eigenen Code initialisieren zu können? Das kann man sich auch 
sparen.
> Was hat das eine mit dem anderen zu tun? Es gibt auch Möglichkeiten mit
> synchronen IOs zu arbeiten und trotzdem nicht zu blockieren.
Interessant. Wie? Multithreading? Dann hat man die Asynchronität nur auf 
die Thread-Interkommunikation verschoben.
> Der Einsatz von RTOS-Systemen auf
> einem MC oder der Multithreadprogrammierung auf dem PC ist unter anderem
> auch entstanden weil große Projekte die extensiv asynchron arbeiten
> irgendwann unwartbar werden.
Kommt drauf an, wenn man ordentlich strukturiert und richtige 
Statemachines plant geht das.
> Für den entsprechenden Zweck das richtige
> Modell zu wählen ist die Kunst des Softwarearchitekten. Sich danach zu
> richten was gerade schick ist zeugt nicht von Intelligenz und darum ging
> es mir.
Kategorisch das abzulehnen was scheinbar großen Erfolg hat ist auch 
nicht unbedingt geschickt. Mikrocontroller-Programmierer haben ja auch 
eine grundsätzliche Aversion gegen OOP und C++ (weil das im 
ET-Studiengang nicht gelehrt wird) obwohl das in anderen Bereichen 
riesigen Erfolg hat - auch nicht besonders schlau. Mit Intelligenz hat 
das aber alles nichts zu tun - aber lieber erstmal beleidigen um sich 
seiner eigenen zu versichern, gell?
> Leider wird gerade mit nodejs wieder so eine neue Kuh durchs
> Dorf getrieben die wiedermal verspricht das allein selig machende zu
> sein.
Was hat das alles mit nodejs zu tun? Klar gibt es auch sinnlose 
IT-Moden, aber es gibt auch sinnvolle, sonst wärn wir alle noch bei 
Binärcodes und Lochstreifen.
> Womit wir wieder beim Herdentrieb wären...
Wir bewundern dich, intelligenter individueller Event-Verweigerer.

von Peter D. (peda)


Lesenswert?

Y2 schrieb:
> Der Startupcode gehört zu den Teilen um den ich mich als
> Programmierer schon noch selbst kümmern sollte.

Warum sollte ich?

Ich gehe davon aus, daß der Compiler schon alles richtig macht und hatte 
noch nie Probleme damit. Ich wähle einfach das Target aus und gut is.

Ich hab noch nen alten Keil C51 von 1995, da mußte man in der 
startup.asm die Größe des externen RAM eintragen, wenn man ihn genullt 
haben wollte. Heutige Versionen dürften das automatisch machen.

von Klaus F. (kfalser)


Lesenswert?

Dr. Sommer schrieb:
>> Der Einsatz von RTOS-Systemen auf
>> einem MC oder der Multithreadprogrammierung auf dem PC ist unter anderem
>> auch entstanden weil große Projekte die extensiv asynchron arbeiten
>> irgendwann unwartbar werden.
> Kommt drauf an, wenn man ordentlich strukturiert und richtige
> Statemachines plant geht das.
...
> Mikrocontroller-Programmierer haben ja auch
> eine grundsätzliche Aversion gegen OOP und C++ (weil das im
> ET-Studiengang nicht gelehrt wird) obwohl das in anderen Bereichen
> riesigen Erfolg hat - auch nicht besonders schlau.

Irgendwie passt diese Logik für mich nicht zusammen.
Auf den Einsatz von RTOS auf MC verzichten, aber OOP favorisieren.
Für mich bringt ein RTOS mehr Ordnung in eine MC-System als OOP, weil 
funktionelle Zusammenhänge und Abläufe beeinander bleiben.
Ich erkenne die Vorteile von OOP an, aber nicht unbedingt im 
Zusammenhang mit MCs.

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Klaus Falser schrieb:
> Für mich bringt ein RTOS mehr Ordnung in eine MC-System als OOP, weil
> funktionelle Zusammenhänge und Abläufe beeinander bleiben.
In die Abläufe, ja, kann sein. Aber eigentlich ging es im ganzen Thread 
gar nicht um RTOS. Wenn man fragt ob man komplett in Interrupts oder 
auch in der main() arbeitet ist "RTOS" nicht die einzige Antwort.
> Ich erkenne die Vorteile von OOP an, aber nicht unbedingt im
> Zusammenhang mit MCs.
Gerade da passt OOP doch wunderbar, man hat sogar real existierende 
Hardware-Objekte die man als OOP-Objekte auffassen kann. zB ein Pin, ein 
ADC, ein UART. Warum die nicht als Klasse implementieren?
1
void doIt (Pin p, Uart u) {
2
  p.setHigh ();
3
  u.send ("blubb");
4
  p.setLow ();
5
}
6
7
int main () {
8
  doIt (PA7, UART0);
9
  doIt (PA2, UART1);
10
}
ist doch sehr praktisch und intuitiv.

von W.S. (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Ansichtssache.  Es gibt Umgebungen (AVR-GCC / avr-libc bspw.), bei
> denen ist der mitgelieferte Startup-Code ausreichend gut ausgefeilt,
> dass er problemlos 99,99 % aller Anwendungen abdeckt.
>
> Wenn du eine PC-Applikation schreibst (egal welches OS), führst du dir
> dann auch erst den Startup-Code des Compiler-Herstellers zu Gemüte?


Jörg, du schreibst Mist und willst provozieren.

Mag sein, daß die AVR-Startupcodes gut genug sind, aber die 
Startupcodes, die üblicherweise bei allen bekannten ARM- und Cortex- 
Toolchaines dabei sind und/oder von den Herstellern geliefert werden, 
sind Bockmist.

Warum?
Weil sie z.B. auf unabgedeckte Interrupts oder Faults mit einem B. 
enden. Darum! Oberdrauf kommt noch, daß main zumeist per BX aufgerufen 
wird.

Was also passiert bei einem vor Ort werkelnden µC, wenn da mal ne 
Störung reinrauscht? Er rennt in den Stopp und das auch noch im 
privilegierten Modus, wo es außer dem Reset keinen Ausweg gibt.

Solch einen blödsinnigen Startupcode MUSS man durch was eigenes 
ersetzen, wenn man Scherereien aus dem Weg gehen will. Ich mache das 
schon seit langem so, daß solche Faults einfach ein globales Fehlerflag 
setzen und einen Warmstart auslösen. Dann kann der µC wenigstens 
reagieren und seine Arbeit wieder aufnehmen. In vielen Situationen ist 
das lebenswichtig.

Und deine Ammerkung zum PC-Geschäft paßt nun mal garnicht. Jeder weiß, 
daß eine App auf'm PC eben irgendwann beendet wird und allenfalls einen 
Returncode zurückgibt - deswegen das  int main(...), was auf einem µC 
sinnlos ist, da es kein Zurück zum BS gibt. Du weißt das doch alles, 
warum schreibst du dann sowas?

W.S.

von W.S. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> int main () {
>   doIt (PA7, UART0);
>   doIt (PA2, UART1);
> }

Und jetzt erklärst du bitte noch, wo das Objektorientierte bei deinem 
hier zitierten Beispiel ist, gelle?

Ich geb dir mal nen Tip:

main(...)
...
 PA7.doTheBlubb;


W.S.

von Dr. Sommer (Gast)


Lesenswert?

W.S. schrieb:
> Warum?
> Weil sie z.B. auf unabgedeckte Interrupts oder Faults mit einem B.
> enden.
Was ist ein unabgedeckter Interrupt? Der Startupcode von ST für STM32 
z.B. wird vermutlich von 99% der STM32-User hier im Forum verwendet, und 
scheint auch zu funktionieren. Was machst du falsch, dass der bei dir 
immer abstürzt? Verkehrtes Linkerscript verwendet?
> Darum! Oberdrauf kommt noch, daß main zumeist per BX aufgerufen
> wird.
Ja und? Wenn der Linker nicht total verwirrt ist, hat er das unterste 
Bit des "main"-Symbols entsprechend gesetzt s.d. "BX" ganz wunderbar 
funktioniert. Wo ist das Problem?

W.S. schrieb:
> Was also passiert bei einem vor Ort werkelnden µC, wenn da mal ne
> Störung reinrauscht?
Was für eine Störung? Was genau soll die bewirken?
> Er rennt in den Stopp und das auch noch im
> privilegierten Modus, wo es außer dem Reset keinen Ausweg gibt.
Was soll das für ein mystischer Stopp sein?

W.S. schrieb:
> Solch einen blödsinnigen Startupcode MUSS man durch was eigenes
> ersetzen, wenn man Scherereien aus dem Weg gehen will.
Oder wenn man als Guru angesehen werden will, weil man Schlangenöl 
"verkauft".
> Ich mache das
> schon seit langem so, daß solche Faults einfach ein globales Fehlerflag
> setzen und einen Warmstart auslösen.
Wie schaffst du das denn im Startup-Code? Meinst du die Fault-Interrupts 
- die gehören doch nicht in den Startup, sondern in den normalen Code. 
Und da kann man machen was man will. Dazu braucht man überhaupt keinen 
angepassten Startup-Code.
> Dann kann der µC wenigstens
> reagieren und seine Arbeit wieder aufnehmen. In vielen Situationen ist
> das lebenswichtig.
Ja, wenn man so schlecht programmiert hat dass man ständig Faults 
produziert! Zum Faults abfangen muss man am Startup-Code gar nichts 
machen.

Kann das sein dass du einfach nur gerne Orakel spielst und irgendwelche 
haaresträubenden hanebüchenen Behauptungen aufstellst, und damit obskure 
Programmier"techniken"/praktiken rechtfertigst und dann klugscheißt dass 
du das so toll kannst? Naja, jeder braucht seine Bestätigung.

W.S. schrieb:
> Und jetzt erklärst du bitte noch, wo das Objektorientierte bei deinem
> hier zitierten Beispiel ist, gelle?
Gerne. Die "UART" oder "Pin"-Peripherie-einheit wird durch eine 
UART/Pin-Klasse repräsentiert und gekapselt. Um einer Funktion 
mitzuteilen, welche UART-Peripherieeinheit man will, muss man nur die 
entsprechende Instanz der UART-Klasse übergeben. Bei diversen 
unobjektorientierten Hardware-API's müsste man gleich eine ganze Reihe 
an Pointern/Konstanten übergeben, da nur die alle zusammen die 
Peripherieeinheit repräsentieren; bei ordentlicher Kapselung entspricht 
eine Peripherieeinheit ("Uart Nr. 0") genau einer "Uart"-Instanz 
("UART0").
> Ich geb dir mal nen Tip:
>
> main(...)
> ...
>  PA7.doTheBlubb;
Ja, das passiert wenn man keine Ahnung von OOP hat aber mal was mit 
Klassen machen will. Wie unschwer zu erkennen war sollte mein 
Mikro-Beispielcode den Pin solange auf 1 ziehen wie die Übertragung 
stattfand. Das ist sozusagen ein "Algorithmus", der sowohl Pin als auch 
Uart benutzt. Der hat weder speziell was mit dem UART noch speziell was 
mit dem Pin zutun - daher wäre es äußerst komisch, wenn die Funktion 
doIt eine Funktion der Pin-Klasse wäre (wie bei deinem Code), oder wenn 
sie Funktion der Uart-Klasse wäre. Was hat die Pin-Klasse auch mit dem 
Uart zu tun? Was hat die Pin-Klasse mit dem Blubb zu tun? Nichts. 
Sauberes OOP-Design besagt hier, dass die Pin-Klasse nur die 
Funktionalität zur Verfügung stellt, die ein Hardware-Pin kann: Auf 0 
setzen, auf 1 setzen, Eingang abfragen, vielleicht noch elektrische 
Parameter wie Pull-Up/Down setzen. Aber nichts mit Blubb über UART 
senden.

Bei OOP kann man durchaus globale ("freie") Funktionen verwenden; aber 
in meinem Fall sind die Parameter das interessante.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Jörg, du schreibst Mist und willst provozieren.

Mensch, du solltest doch nicht immer in den Spiegel gucken, wenn du
postest. :-)

von kopfkratzer (Gast)


Lesenswert?

kopfkratz
Also "obligatorisch" ist die main loop keineswegs, man kann sie z.B. mit 
dem Leerlaufprozeß von Betriebssystemen vergleichen.
Aber üblicherweise läuft bei einer µC Applikation in der main die 
Ablaufsteuerung, ob nun als Statemachine mittels switch case oder indem 
auf einen Tastendruck, Datenaufkommen o.ä. gewartet/reagiert wird.
Es gibt sicherlich Abläufe die ausschießlich via IRQ erledigt werden 
können, z.B. im ADC IRQ einen Poti automatisch abfragen und dann via 
globaler volatile Variable den gemessenen Wert immer wieder an eine PWM 
im Timer-IRQ zu übergeben.
Nur kostet eine Endlosschleife nix, denn wenn der Compiler merkt das da 
nix passiert und ansonsten alles Paletti ist kann der das dann auch 
wegoptimieren.
Man gewinnt also nichts kann aber viele Probleme erzeugen wenn man die 
"obligatorische" Endlosschleife wegläßt.

von Dr. Sommer (Gast)


Lesenswert?

kopfkratzer schrieb:
> Nur kostet eine Endlosschleife nix, denn wenn der Compiler merkt das da
> nix passiert und ansonsten alles Paletti ist kann der das dann auch
> wegoptimieren.
Na die Endlosschleife wegoptimieren wäre nicht so geschickt, weil dann 
doch wieder die main() zurückkehrt... Eine Endlosscheife ist aber sonst 
recht billig, ja, typischerweise 1 Instruktion...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

kopfkratzer schrieb:

> Nur kostet eine Endlosschleife nix, denn wenn der Compiler merkt das da
> nix passiert und ansonsten alles Paletti ist kann der das dann auch
> wegoptimieren.

Nein, kann er nicht, denn dadurch erhält man (aus C-Sicht) ein anderes 
Programm.

von W.S. (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Mensch, du solltest doch nicht immer in den Spiegel gucken, wenn du
> postest. :-)

Ha, der war gut..
Aber was soll ich machen bei den heutigen Hochglanz-Displays?
Ich werde aber beim nächsten Mal intensiver an DICH denken.

Dr. Sommer schrieb:
> Was ist ein unabgedeckter Interrupt?
Ah, du wolltest dich mal wieder hervortun.
Aber ich bin ja nett und erklär's dir: Sowas ist ein Interrupt, der vom 
Nutzprogramm nicht benutzt wird. Dazu zählen auch die meisten CPU-Faults 
- oder kennst du jemanden, der einen Handler für nen Prefetch-Fault oder 
nen Datafault in sein Programm schreibt? Und echte Störungen von außen 
gibt's auch öfter als du denkst. Man kann sowas ignorieren - meistens. 
Aber wer seinen Job gründlich macht, denkt auch darüber nach und 
schreibt sich einen besseren Startupcode als den Defaultcode vom 
Hersteller.

Ach ja, den Unterschied zwischen einem BX und einem BLX kennst du 
offenbar auch nicht. Wir waren ja hier beim Thema Endlosschleife am End 
von main. Rate mal, wohin die Reise geht, wenn jemand main beendet und 
main per BX angesprungen wurde.

W.S.

von Dr. Sommer (Gast)


Lesenswert?

W.S. schrieb:
> Ah, du wolltest dich mal wieder hervortun.
Du bist das beste Vorbild dafür.
> Aber ich bin ja nett und erklär's dir: Sowas ist ein Interrupt, der vom
> Nutzprogramm nicht benutzt wird.
Also ein ganz ordinärer Interrupt+ISR, nur dass der Default-Handler-Code 
verwendet wird. Und dass dieser Default-Handler typischerweise gar 
nichts macht und einfach nur sofort zurück kehrt.
> Dazu zählen auch die meisten CPU-Faults
> - oder kennst du jemanden, der einen Handler für nen Prefetch-Fault oder
> nen Datafault in sein Programm schreibt?
Du scheinbar, um in so einem Fall einen Reset auszulösen. Ist ja schön, 
den zu überschreiben - aber das hat immer noch NICHTS mit dem 
Startup-Code zu tun. Nur weil man eine Fault-Handler-ISR schreibt muss 
man noch lange keinen eigenen Startup Code schreiben.

> Und echte Störungen von außen
> gibt's auch öfter als du denkst. Man kann sowas ignorieren - meistens.
> Aber wer seinen Job gründlich macht, denkt auch darüber nach und
> schreibt sich einen besseren Startupcode als den Defaultcode vom
> Hersteller.
Was haben die Störungen mit dem Startup-Code zu tun? Wenn du damit 
meinst, die Fault-Handler zu behandeln - siehe oben. Und woher weißt du 
dass eine Störung so freundlich ist einen Faulthandler auszulösen, und 
nicht einfach ein Bit im Register kippt? Wenn du mit "Störsicherheit" 
kommst musst du noch ganz andere Maßnahmen ergreifen als nur eigene 
Faulthandler zu schreiben. z.B. einen Prozessor verwenden der für sowas 
gemacht ist.

Wenn ich einen Code sehe der in seinen Fault-Handlern einfach einen 
Reset auslöst würde ich mal sagen der Autor hat seinen Job nicht 
ordentlich gemacht, da er wohl Fehler in seinem Code hat die er aber zu 
finden nicht in der Lage war, und daher einfach im Fault-Handler einen 
Reset auslöst. Ich würde im Handler, wenns denn sein muss, ein
1
asm volatile ("bkpt"); while (1);
schreiben, damit ich im Fehlerfall JTAG anklemmen und debuggen kann. 
Abstürze sind nämlich meistens, wer hätte es gedacht, Resultat von 
Programmierfehlern.
> Ach ja, den Unterschied zwischen einem BX und einem BLX kennst du
> offenbar auch nicht.
Doch. Ich hatte nur darauf getippt dass du "BX" vs. "B" meintest. Weiß 
man ja nicht so genau was in deinem Kopf vorgeht.
> Wir waren ja hier beim Thema Endlosschleife am End
> von main. Rate mal, wohin die Reise geht, wenn jemand main beendet und
> main per BX angesprungen wurde.
Wie ich hier ( Beitrag "Re: Ist die obligatorische Endlosschleife am Ende der main Funktion nur Aberglaube?" ) 
schon erläutert habe, stürzt der Controller ab - bei Verwendung von "BX" 
statt "BLX" halt nicht nach Rückkehr aus der main(), sondern bei der 
Rückkehr aus der main - ein großer Unterschied?!

Wenn du natürlich unbedingt aus der main() zurückkehren willst, musst du 
wohl im Startupcode nach dem "BLX main" irgendwas einfügen. Man kann 
aber auch einfach ein while(1); ans Ende der main() packen und mit "BX" 
in die main() springen - davon wirds auch nicht weniger "stabil". Ganz 
davon abgesehen verwendet z.B. der Startuptcode von ST tatsächlich das:
1
  bl  main
2
  bx  lr
Recht sinnlos, das ist das selbe wie "b main".

Bis jetzt kam jedenfalls kein sinnvoller Grund von dir, eigenen Startup 
Code zu schreiben. Fault-Handler kann man, oh wunder, auch in den 
"normalen" Anwendungscode packen.

Wenn du Spaß daran hast auf vage unbegründbare Vermutungen hin 
irgendwelche "Stabilitätsmaßnahmen" an einem Code vorzunehmen und deinen 
eigenen Startup-Code zu produzieren um zu demonstrieren dass du es 
"besser" als die Hersteller kannst, ist das ja schön - aber verwirr 
nicht die armen Mitleser hier die die Interna des ARM nicht so gut 
kennen um deinen Unfug als solchen nicht sofort erkennen zu können.

von low power (Gast)


Lesenswert?

Es geht ohne die obligatorische Endlosschleife und auch ohne Compiler 
Ergänzung:
Beitrag "Re: MSP430 F2013 Problem bei Interrupt von P2"

von Dr. Sommer (Gast)


Lesenswert?

low power schrieb:
> Es geht ohne die obligatorische Endlosschleife und auch ohne Compiler
> Ergänzung:
Dann zeig mal bitte wie das zB am ARM-GCC für Cortex-M3 geht. Und woher 
weißt du dass bei dem dort verwendeten MSP430-Compiler keine 
Endlosschleife im Startupcode ist?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Und woher weißt du dass bei dem dort verwendeten MSP430-Compiler
> keine Endlosschleife im Startupcode ist?

Vielleicht weil das Programm in main ankommt? :o)

von Dr. Sommer (Gast)


Lesenswert?

Johann L. schrieb:
> Vielleicht weil das Programm in main ankommt? :o)
NACH Aufruf&Rückkehr der main() natürlich, Nasendreher :-P

von low power (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Und woher
> weißt du dass bei dem dort verwendeten MSP430-Compiler keine
> Endlosschleife im Startupcode ist?

Der MSP430 restauriert mit verlassen der ISR das SR. Dort ist der LPM 
verzeichnet. Der LPM wird wieder eingenommen ohne das Code aus dem 
Hauptprogramm ausgeführt wird. Da brauchts keine Endlosschleife.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Johann L. schrieb:
>> Vielleicht weil das Programm in main ankommt? :o)
> NACH Aufruf&Rückkehr der main() natürlich, Nasendreher :-P

Das Prinzip hab ich schon verstanden; ist wie bei Windows: Zum Beenden 
muss man auf "Start" gehen".

von Dr. Sommer (Gast)


Lesenswert?

low power schrieb:
> Der MSP430 restauriert mit verlassen der ISR das SR. Dort ist der LPM
> verzeichnet. Der LPM wird wieder eingenommen ohne das Code aus dem
> Hauptprogramm ausgeführt wird. Da brauchts keine Endlosschleife.
Ach das, ja, geschickt das dafür zu nutzen. Cortex-M3 kann das 
prinzipiell auch, aber durch diverse Events kann der Core 
"versehentlich" doch mal aus dem WFI zurückkehren - also braucht man 
doch eine Schleife...

von Axel S. (a-za-z0-9)


Lesenswert?

Die ganze Diskussion ist für ... das Tier das die Mäuse fängt.

Auf einem µC gibt es schlicht nichts, wohin main() zurückkehren könnte. 
Deswegen ist eine main() Funktion, die beendet werden kann, auch voll- 
kommen sinnfrei.

Jedes sinnvolle µC-Programm hat also die Endlosschleife in main() auf 
die eine oder andere Weise schon drin. Abgesehen von irgendwelchen 
Test-Codeschnipseln vielleicht, wo man dann eine Endlosschleife explizit 
hinschreiben würde.


XL

von Bronco (Gast)


Lesenswert?

Also eine Sache interessiert mich (als STM32-Newbie) jetzt aber doch:

W.S. schrieb:
> Was also passiert bei einem vor Ort werkelnden µC, wenn da mal ne
> Störung reinrauscht? Er rennt in den Stopp und das auch noch im
> privilegierten Modus, wo es außer dem Reset keinen Ausweg gibt.

Aber der Watchdog würde schon noch zuschlagen, oder?

von Dr. Sommer (Gast)


Lesenswert?

Axel Schwenke schrieb:
> Die ganze Diskussion ist für ... das Tier das die Mäuse fängt.
>
> Auf einem µC gibt es schlicht nichts, wohin main() zurückkehren könnte.
Wie jetzt schon länger diskutiert - doch, es gibt den Startupcode.
> Deswegen ist eine main() Funktion, die beendet werden kann, auch voll-
> kommen sinnfrei.
Das hängt vom Startupcode ab.
> Jedes sinnvolle µC-Programm hat also die Endlosschleife in main() auf
> die eine oder andere Weise schon drin. Abgesehen von irgendwelchen
> Test-Codeschnipseln vielleicht, wo man dann eine Endlosschleife explizit
> hinschreiben würde.
Oder komplett Interrupt-basierten Programmen.

Bronco schrieb:
> W.S. schrieb:
>> Was also passiert bei einem vor Ort werkelnden µC, wenn da mal ne
>> Störung reinrauscht? Er rennt in den Stopp und das auch noch im
>> privilegierten Modus, wo es außer dem Reset keinen Ausweg gibt.
>
> Aber der Watchdog würde schon noch zuschlagen, oder?
W.S. blubbert einfach irgendeinen Unfug von dem er keine Ahnung hat. Das 
sieht man schon daran, dass er jedes Mal, wenn er wiederlegt wurde, 
nicht mehr antwortet. Es gibt keinen "Stopp". Es gibt wenn schon 
Fault-Handler. Und die kann man im normalen Anwendungsprogramm 
überschreiben.

Die Fault-Handler "gegen Störungen" zu verwenden ist so wie eine Sirene 
in der Bank zu installieren und die mit einem Knopf zu versehen und den 
mit "Bankräuber bitte hier drücken" zu beschriften.

von Dr. Winter (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Die Fault-Handler "gegen Störungen" zu verwenden ist so wie eine Sirene
> in der Bank zu installieren und die mit einem Knopf zu versehen und den
> mit "Bankräuber bitte hier drücken" zu beschriften.

Mach's mal halblang. Du bist doch einer von denjenigen hier die immer 
wieder gegen die intervenieren die tiefer in die Materie einsteigen und 
sich nicht blind auf das verlassen was "man so macht".

Wenn du heute einen größeren Cortex M3 oder M4 etwas auslastest, dann 
hast du in der Regel einen Sack voll fremder Libs dabei. Ob Ethernet, 
Filesysteme, RTOS oder was weiß ich. Damit ist es auch ziemlich 
ausgeschlossen fehlerfreie Programme zu schreiben. Keines dieser 
Programme kann jemals in allen erdenklichen Formen getestet werden. In 
diesem Fall ist es aber sehr häufig sinnvoller, der Controller macht 
einen Reset als in einer Endlosschleife fest zu hängen. Frag doch mal 
bei Arm nach warum sie so einen "Blödsinn" erfunden haben, wenn man ihn 
doch nicht benutzen darf.
Du bist Verfechter von C++ und der Verwendung der libstdc++. Bist du dir 
sicher damit immer die volle Kontrolle über Stack und Heap zu haben? 
Unter allen denkbaren Umständen?

Dr. Sommer schrieb:
> W.S. blubbert einfach irgendeinen Unfug von dem er keine Ahnung hat. Das
> sieht man schon daran, dass er jedes Mal, wenn er wiederlegt wurde,
> nicht mehr antwortet.

Nö, ist ganz einfach: Der Klügere gibt nach! Es gibt Leute die müssen 
ihre Meinung mit allen Mitteln als die einzig richtige verbreiten. Lass 
mich raten. Angestellt an einer UNI? Spätestens wenn man das schnallt 
ist die Zeit gekommen die Diskussion zu beenden.

von Dr. Sommer (Gast)


Lesenswert?

Dr. Winter schrieb:
> In
> diesem Fall ist es aber sehr häufig sinnvoller, der Controller macht
> einen Reset als in einer Endlosschleife fest zu hängen.
Aha. Das ist aber was ganz anderes. Das ist keine "elektrische Störung" 
oder "kosmische Strahlung", sondern ganz einfach ein Programmierfehler. 
Ja, in so einem Fall kann man einen Reset auslösen.
> Frag doch mal
> bei Arm nach warum sie so einen "Blödsinn" erfunden haben, wenn man ihn
> doch nicht benutzen darf.
Hauptsächlich zum Debuggen, um zu sehen was schief gelaufen ist. Ich 
habe auch nie gesagt dass man die FaultHandler nicht benutzen darf; 
lediglich dass sie keinen sinnvollen Schutz gehen elektrische Störungen 
bieten (Programmfehler würde ich nicht als "störung" rechnen) und 
eigentlich hauptsächlich, dass man den Startupcode dafür nicht 
anfassen muss.
> Du bist Verfechter von C++ und der Verwendung der libstdc++. Bist du dir
> sicher damit immer die volle Kontrolle über Stack und Heap zu haben?
Über den Stack hat man in C(++) grundsätzlich keine Kontrolle, die hat 
der Compiler. Und was hat die C++ stdlib mit dem Heap zu tun? Und warum 
entzieht die einem die "kontrolle über den Heap", was auch immer das 
heißen soll?
>
> Dr. Sommer schrieb:
>> W.S. blubbert einfach irgendeinen Unfug von dem er keine Ahnung hat. Das
>> sieht man schon daran, dass er jedes Mal, wenn er wiederlegt wurde,
>> nicht mehr antwortet.
>
> Nö, ist ganz einfach: Der Klügere gibt nach!
"Der Himmel ist grün-gelb gepunktet! Und jetzt gebe ich nach weil ich 
der Klügere bin."
> Es gibt Leute die müssen
> ihre Meinung mit allen Mitteln als die einzig richtige verbreiten.
ja, und W.S. ist ein Paradebeispiel. Bei jeder (un)denkbaren Gelegenheit 
hält er den Leuten seine unglaublich vermurkste "Lernbetty" unter die 
Nase mit "guckt mal was ich tolles gemacht hab macht es mir genau so 
nach"!
>  Lass
> mich raten. Angestellt an einer UNI? Spätestens wenn man das schnallt
> ist die Zeit gekommen die Diskussion zu beenden.
Weil man als einziger Entwickler in einem Unternehmen nicht hinterfragt 
wird und da beliebigen Unsinn verzapfen kann, oder wie kommst du darauf?

von Axel S. (a-za-z0-9)


Lesenswert?

Dr. Sommer schrieb:
> Axel Schwenke schrieb:
>> Die ganze Diskussion ist für ... das Tier das die Mäuse fängt.
>>
>> Auf einem µC gibt es schlicht nichts, wohin main() zurückkehren könnte.

> Wie jetzt schon länger diskutiert - doch, es gibt den Startupcode.

Albern.

Der Startup-Code ist da aus rein technischen Gründen. Weil jemand oder 
etwas z.B. den Stack initialisieren muß oder die statischen Variablen. 
Aber es gibt genau gar keinen Grund, warum der Startup-Code main() als 
Funktion aufrufen sollte (was dann zumindest technisch eine Rückkehr 
erlauben würde) statt main() einfach anzuspringen oder vom Linker direkt 
hinter das Ende des Startup-Codes linken zu lassen.

Auch sonst tut auf einem µC der Startup-Code nichts von all dem was man 
in einem hosted environment voraussetzen würde, wie z.B. Argumente zu 
übergeben (argc, argv) oder den Returnwert von main() auszuwerten (wie 
auch?). Das Verhalten des C-Laufzeitsystems auf einem µC ist definiert 
von "der Programmablauf startet mit der main() Funktion" bis zum Ende 
von main(). Alles was davor oder danach passiert, ist schlicht 
undefiniert. Und wenn nach dem Ende von main() undefiniertes Verhalten 
folgt, dann darf main() eben nicht enden.


XL

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Natürlich gibt es Anwendungen, die den return-Wert von main auswerten, 
z.B. wenn man Tests laugen lässt.  Typisches Beispiel ist, die Toolchain 
zu testen und Code in einem Simulator laufen zu lassen (zumindest die 
Laufzeit-Tests, für die reinen Compile-Tests braucht's natürlich keinen 
Simulator).  In dem Falle tut man gut daran, wenn die Tools sich 
möglichst standardkonform verhalten.

Den Fall man man als esotherisch ansehen, aber wer von euch will denn 
gerne eine ungesestete Toolchain verwenden? Bzw. eine Toolchain, bei 
deren Testergebnissen man sagt: Ok, 3-5% der ca. 100000 Tests (z.B. 
C-Tests für gcc) gehen durch, der Rest macht irgendwas und ist und 
wurscht?

von mec (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Und was machen die anderen 5%? Mir ist noch nie ein µC-Programm über den
> Weg gelaufen, das sich beendet. Ich wüßte auch keinen Anwendungsfall
> dafür.

Ich hab sowas schon mal geschrieben.
In dieser Anwendung hat sich die Schaltung zum Stromsparen zum Schluß 
einfach selbst den Saft abgedreht. Der letzte Befehl war einfach ein 
sich auf low schaltender Pin der ein Relais ausschaltet. Zum einschalten 
muss dann ein Taster gedrückt werden, der die Stromzufuhr wieder 
herstellt ;)

von Dr. Sommer (Gast)


Lesenswert?

mec schrieb:
> Der letzte Befehl war einfach ein
> sich auf low schaltender Pin der ein Relais ausschaltet. Zum einschalten
> muss dann ein Taster gedrückt werden, der die Stromzufuhr wieder
> herstellt ;)
Und das Relais braucht zur An-Zeiten weniger Strom als der 
Mikrocontroller dauerhaft im tiefsten Sleep-Mode? Und was passiert in 
der Zeit zwischen Pin-Abschalten und Strom aus? Relais sind langsam...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Und das Relais braucht zur An-Zeiten weniger Strom als der
> Mikrocontroller dauerhaft im tiefsten Sleep-Mode?

Was hat das jetzt mit der Endlosschleife zu tun?  Kaum nennt dir jemand
ein tatsächliches Beispiel, musst du lieber gleich das Prinzip in Frage
stellen, statt es so zu akzeptieren?  Seltsame Logik.

Axel Schwenke schrieb:
> Jedes sinnvolle µC-Programm hat also die Endlosschleife in main()

Wenn du jetzt zurück auf "Los!" gehst, wirst du aber feststellen, dass
der Thread mit einer Referenz auf ein einfaches Demo-Programm begonnen
hat.  Das hat an seinem Ende weiter nichts, was es noch hätte tun
können, eben daher hat es sich regulär beendet.

Dass man das in einer realen Applikation nicht machen würde, darüber
besteht wohl allenthalben völlige Einigkeit.

von Dr. Sommer (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Was hat das jetzt mit der Endlosschleife zu tun?

mec schrieb:
> Der letzte Befehl war einfach ein sich auf low schaltender Pin der ein
> Relais ausschaltet.
Das klingt ein bisschen so als sei dort keine Endlosschleife und als 
würde die main() zuruckkehren

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Herr Doktor (falls man dich überhaupt so anreden darf ...), du redest
komplett dran vorbei.

Du hast nicht mehr über die (bei ihm nicht vorhandene) Endlosschleife
geredet, sondern angefangen, sein grundsätzliches Konzept in Frage zu
stellen ("Ist das Relais denn überhaupt sinnvoll?").

Das nur, weil dir einer ein reales Beispiel genannt hat, bei dem in
einer praktisch realisierten Applikation am Ende von main() eben mal
keine Endlosschleife steht — weil sie sowieso nicht mehr erreicht
worden wäre.

Du kannst nicht ruhig schlafen, wenn du mal nicht recht hast, oder wie
ist das?

von Dr. Sommer (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Herr Doktor (falls man dich überhaupt so anreden darf ...)
Rechtlich leider nicht, aber daher bin ich ja im Internet, da weiß das 
keiner.
> Du hast nicht mehr über die (bei ihm nicht vorhandene) Endlosschleife
> geredet, sondern angefangen, sein grundsätzliches Konzept in Frage zu
> stellen ("Ist das Relais denn überhaupt sinnvoll?").
Ich fragte mich lediglich was passiert zwischen dem Befehl, der den 
Relais-Pin abschaltet, und der Rückkehr aus der main(). Ist der µC 
tatsächlich sofort aus bevor die main() zurückkehrt? Oder ist da noch 
eine mechanisch und vielleicht kapazititv bedingte Latenz die den µC 
noch etwas länger laufen lässt? Weil in dem Fall könnte - in starker 
Abhängigkeit vom Startupcode - der Controller vor dem Strom-Aus noch 
irgendeinen undefinierten Unsinn machen, wie Flash-Speicher löschen oder 
was auch immer.
> Du kannst nicht ruhig schlafen, wenn du mal nicht recht hast, oder wie
> ist das?
Nein. Sonst  glaubt mir ja auch keiner, daher versuch ich es hier.

von Klaus (Gast)


Lesenswert?

Micha schrieb:
> wahrscheinlich 'ne Frage, bei der die Antwort "nur" von
> akademischem
> Interesse ist...
>
> Bisher hab ich immer, nach kritiklos übernommener Lehrmeinung, meine
> main mit einer Endlosschleife beendet.
>

Das hängt ganz allein vom Startup Code ab. Was auf einem uC passiert, 
wenn man aus main() zurückspringt ist unterschiedlich. Die Möglichkeiten 
wären unter anderem: Watchdog-Reset, Soft-Reset, Endlosschleife, Halt... 
Der Startup Code den ich in der Vergangenheit selbst geschrieben habe, 
geht beispielsweise folgendermaßen vor:

a) Aufruf der Destruktoren statischer Objekte
b) Aufruf der registrierten atexit() Funktionen
c) Deaktivieren aller Interrupts und nebenläufiger Ereignisse
d) Wachdog Enable und Start zum Triggern eines Resets
e) Endlosschleife bis Reset erfolgt

Allerdings, in eine reine Endlosschleife zu laufen (Implementierung der 
Faulpelze) wenn man aus main() zurückspringt ist streng genommen nicht 
Standard-konform: Es werden weder statische Objekte zerstört noch 
atexit() Funktionen aufgerufen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Unsinn machen, wie Flash-Speicher löschen oder was auch immer.

Wenn du dir schon mal so angesehen hast, welchen Aufwand man treiben
muss, um den Flash zu programmieren, dann gewinnst du eher im Lotto,
als dass sich da versehentlich ein Byte umprogrammieren würde. ;-)

Aber gut, prinzipiell ist der Einwand natürlich berechtigt: man sollte
sich wenigstens Gedanken gemacht haben, was mit der in den
Stützkondensatoren gespeicherten Energie noch passieren kann, nachdem
die eigentliche Versorgung abgeschaltet ist.  Aber wer macht sich diese
Gedanken eigentlich für den normalen Ausschaltvorgang mit einem
mechanischen Schalter?  Ob wirklich alle Leute den Brownout-Reset
aktivieren, damit der Controller in einen definierten Reset fährt,
sobald die Spannung an den Stützkondensatoren unter den Wert für einen
definierten Betrieb abrutscht? ;-)

von Dr. Sommer (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Wenn du dir schon mal so angesehen hast, welchen Aufwand man treiben
> muss, um den Flash zu programmieren, dann gewinnst du eher im Lotto,
> als dass sich da versehentlich ein Byte umprogrammieren würde. ;-)
Hoffentlich gilt das auch für alle anderen angeschlossenen 
Speicherbausteine, FET's, etc... Mir persönlich wäre etwas unwohl dabei 
wenn mein Controller regelmäßig (beim Ausschalten) etwas undefiniertes 
macht, und das nur um die eine Instruktion für die Endlosschleife zu 
sparen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Mir persönlich wäre etwas unwohl dabei wenn mein Controller regelmäßig
> (beim Ausschalten) etwas undefiniertes macht

Etwas undefiniertes wird er nur bei sehr schlechten Frameworks machen.
Wie oben bereits geschrieben, falls es ein AVR war und die avr-libc,
dann ist die Endlosschleife garantiert, denn dort wird ganz
C-standardgemäß danach nach main() noch exit() gerufen.  Man könnte auch
argumentieren, dass dort die explizite (leere) Endlosschleife pure
Platzverschwendung ist, so wie der Test bei:
1
  if (p != 0) free(p);

Aber siehe oben: hast du dann auch den Brownout-Reset aktiviert?  Denn
beim Runterfahren der Spannung macht unterhalb der garantierten
Grenze der Kern dann irgendwann tatsächlich etwas undefiniertes, da
beispielsweise der Flash nicht mehr korrekt ausgelesen werden kann,
die Gatter der CPU aber nach wie vor noch ein wenig weiterwerkeln.

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
Noch kein Account? Hier anmelden.