Hallo ist es möglich, das beim Ausführen eines Interrupts ein goto auf eine Stelle im main ausgeführt werden kann? Gruß Richi
ich versteht zwar nicht was du machen willst, aber lasse es lieber bleiben mit dem goto - das ist nur in sehr seltenen Fällig notwendig.
Technisch bestimmt... Praktisch fällt mir da gerade kein sinnvoller Grund ein...
nein Prinzipiell gibt es die Möglichkeit, in C mit setjmp (z.B. in main()) einen Zustand einzufrieren, zu dem (von einem Punkt darunter in der Aufrufebene) wieder mit longjmp() zurückgesprungen wird. Aber das ist ohnehin kriminell, und wird sicher nicht klappen, wenn das longjmp() in einem Interrupt aufgerufen wird.
> ist es möglich, das beim Ausführen eines Interrupts ein goto auf eine > Stelle im main ausgeführt werden kann? Du möchtest also, daß deine Hauptroutine irgendwo an einer unbekannten Stelle unterbrochen und dann wo ganz anders fortgesetzt wird? Wie solte das auch nur halbwegs sauber funktionieren, und vor allem: Wozu?
Mein Ziel: Wird ein bestimmter Taster(INT0) aktiviert, rappelt der Interrupt los und das soll Programm wieder an eine bestimmte Stelle anfangen. Es ist sozusagen ein Resettaster, nur dass nicht von vorne sondern in der Mitte mit der ausführung des Programms begonnen wird. Noch ein Tipp: Ich arbeite in C Gruß Richi
Hinspringen mag ja noch klappen, aber wie zurueck an die richtige Stelle kommen? Gast
Es geht mir ja nur darum, dass wieder von der "Resetstellung" begonnen wird, die andere Richtung wird nicht benötigt.
Der Sprung aus der Interruptroutine nach main lässt sich zwar programmieren, auf dem Stack bleibt aber die Adresse des Rücksprungs zurück (eventuell mit weiteren Parametern). Nach einigen Sprüngen läuft dann der Stack über und das Programm stürzt dann ab. Geht also so nicht.
Richi schrieb: > Es geht mir ja nur darum, dass wieder von der "Resetstellung" begonnen > wird, die andere Richtung wird nicht benötigt. Doch die wird benötigt :-) Du siehst sie nur nicht. Wenn der Interrupt aufgerufen wird, wird allerhand intern am Stack abgelegt. Dieser Stack muss wieder aufgeräumt werden. Wird aber die ISR nicht auf regulärem Wege beendet, passiert das nicht. Mach deine Programmstruktur richtig, dann brauchst du derartige Klimmzüge nicht. Im Interrupt wird eine Markierung gesetzt und im Hauptprogramm wird regelmässig nachgesehen ob die Markierung gesetzt wurde und wenn ja fährt sich das Programm wieder in seine Startkonfiguration. Dann hast du auch nicht das Problem, dass dir der Benutzer mit einem Tastendruck mitten in eine kritische Operation reinfunkt, sondern kannst gezielt und auch sicher auf den Tastendruck reagieren.
Bei jedem Rücksprung mir Goto bleib die beim Interrupt gespeicherte Rücksprungadresse auf dem Stack und der Stäck ist irgendwann voll=läuft über. Deine Struktur ist falsch. Schreibe alles! was beim Interrupt gemacht werden soll in! dein IRQ-Programm. wsm
Eine Sichere Methode den Stack zum Überlauf zu bringen!!!!! Der Interrupt legt los, springt ins Main, macht dort irgendwas und dann??? Auf dem Stack liegen doch die geretten Register und die Rückkehradresse! Was geschieht mit denen? Irgendwann steht der Stackpointer am Anschlag!
> Dann hast du > auch nicht das Problem, dass dir der Benutzer mit einem Tastendruck > mitten in eine kritische Operation reinfunkt Genau das will ich aber!!! Kann man denn nicht in der Interruptrutine das, was diese zuvor in den Stack geschrieben hat löschen, und dann springen?
Am besten in der ISR ein Flag setzen, welches im Hauptprogram abgefragt wird und dann die gewünschte Aufgabe ausführt
Nach meinem Verständnis von setjmp/longjmp bei gcc merkt sich dieser tatsächlich ein Stack-Frame, zu dem er bei longjmp zurückkehrt, wobei der Teil darunter "discarded" wird. So verrückt die Idee ist, sie könnte klappen, Was nicht klappen wird, ist die Wieder-Freigabe des Interrupts (das I-Flag). Ich denke nicht, dass C sich darum kümmert. Dennoch sträuben sich bei mir sämtliche Nackenhaare. So etwas lässt sich auch sauber lösen.
Richi schrieb: >> Dann hast du >> auch nicht das Problem, dass dir der Benutzer mit einem Tastendruck >> mitten in eine kritische Operation reinfunkt > > Genau das will ich aber!!! Dann programmiere in diese kritische Operation die entsprechende Abfrage des Merkers hinein und dokumentiere so ausdrücklich, dass du das an dieser Stelle erlaubst. By the way: Mit kritischer Operation meine ich nicht eine etwas länger andauernde Operation. Mit kritischer Operation meine ich zb das zeitliche Widerabschalten von Lampen die wegen einem Multiplex eigentlich mit zuviel Strom für den Dauerbetrieb angefahren werden. Wenn nach dem Einschalten das Abschalten nicht nach einer definierten Zeitdauer erfolgt, dann gibt es einen Hardware-Schaden. Und jetzt rate mal, was wohl passiert wenn deine ISR aufgerufen wird, wenn zwar schon eingeschaltet, aber noch nicht abgeschaltet wurde und sich dein Programm irgendwo hin verkrümelt und erst mal seine Zeit damit verplempert zb das LCD neu zu initialisieren. Oder eine Pumpe wird eingeschaltet und muss definiert wieder ausgeschaltet werden oder ... Das meint man mit kritischen Operationen: Operationen die unter allen Umständen hintereinander ausgeführt werden müssen. Egal was passiert.
> Kann man denn nicht in der Interruptrutine das, was diese zuvor in den > Stack geschrieben hat löschen, und dann springen? Man kann theoretisch die Rücksprung-Adresse durch eine andere überschreiben. Allerdings wird das trotzdem nicht richtig funktionieren, weil dein Hauptprogramm ja nicht darauf vorbereitet ist, daß da von außen irgendwo mitten rein gesprungen wird. Lass es bleiben. Es ist ein Hack übelster Sorte.
Stackinhalte können in asm mit pop zurückgeholt werden. Also einfach den überflüssigen Stackinhalt zurück-popen. Es stellt sich nur die Frage, wieviel byte dies sind und ob auch noch Register gepusht wurden? wsm
Das ständige Abfragen wäre eine Notlösung, finde ich aber doof. Denn wenn ich in jeder Zeile zuerst eine Abfrage tätigen muss, ist das nicht gerade Arbeitsunaufwändig. Ich will einfach nur eine art Resettaster, nur dass das Programm dann nicht neu gestartet sondern an einer anderen stelle weiter macht. Gruß Richi
man könnte aber auch den Return adresse auf dem Stack mit der Adresse vom goto ziel überschreiben. Am ende der ISR springt er dann an die gewünschte stelle. (ich würde es aber selber bestimmt nicht so machen)
Richi schrieb: > Das ständige Abfragen wäre eine Notlösung, finde ich aber doof. > Denn wenn ich in jeder Zeile zuerst eine Abfrage tätigen muss, ist das > nicht gerade Arbeitsunaufwändig. Halb so wild. In einem durchschnittlichen Programm sind das viel weniger Stellen als du jetzt denkst. Und von "Bei jeder Zeile" kann ja im Regelfall nicht die Rede sein. Bei Schleifen muss man ein wenig abwägen, wie lange die Schleife laufen wird und den Tastenabbruch mit in die Schleifenbedingung mit einbauen, aber abgesehen davon: Es reicht völlig, wenn dein Programm zeitlich gesehen, so alle 1ms den Merker abfragt. 1ms ist für einen µC eine halbe Ewigkeit. Für den Menschen hingegen, der den Taster drückt, ist das unglaublich kurz. Und ob dein µC 1ms früher oder später auf den 'Notaus' reagiert, spielt so gut wie keine Rolle, weil dein Bediener den Tastendruck sowieso nicht genau genug timen kann.
Richi schrieb:
> Aber was ist wenn mein Programm nicht durchschnittlich ist?
Warum bloss wundert mich dieser Erwiderung nach dieser Fragestellung
nicht mehr :-)
Na was hast du denn so Spezielles, dass es sich nicht lohnt den Saustall
erst mal aufzuräumen anstelle da noch ein Schäuflein draufzulegen?
Hmm. Irgendwie beschleicht mich da jetzt so ein komisches Gefühl :-)
Ich suche einfach nur nach einer einfacheren Lösung. Aber anscheinend gibt es keine. Gruß Richi
Ich habe den Eindruck, daß dein Programm schon den falschen Ansatz benutzt und du jetzt unter den Konsequenzen davon leidest. Ich kann mir irgendwie nicht vorstellen, daß dein Programm so speziell und ungewöhnlich ist, daß es nun wirklich gar nicht anders geht.
Es geht ja mit der "ständig Abfragen Methode". Aber wenigstens weiß ich, dass es jetzt nicht wirklich anders geht. Danke an alle Mitwirkenden! Gruß Richi
>Ich will einfach nur eine art Resettaster, nur dass das Programm dann >nicht neu gestartet sondern an einer anderen stelle weiter macht. Was wohl "nicht neu gestartet" und "eine Art Resettaster" bedeuten mag? Wie auch immer: mgl. Würgaround - zumindest ohne *jump-Gemurks: In "INT0"-ISR: Watchdog-Timer (sofern vorhanden) einschalten (wenn nicht schon an), Endlosschleife in ISR bis Watchdog-Auslösung -> Watchdogs-Reset d. HW. Zu Beginn von main() Reset-Ursache in einem der Register des bis dato nicht genannten Controllers abfragen: if (reset_ursache_watchdog) andere_stelle(); // sonst halt nicht "andere stelle"... Aber statt solch einem Krampf "Noch ein Tipp": Zustandsautomat. Dann reicht eine Statusabfrage in der Hauptschleife, die zwar auch "ständig augerufen" wird, aber nur einmal zu implementieren ist. Nicht lange in den State-Functions hertrödeln (analog ISRs), dann wird der Tastendruck bzw. die Änderunge des in der "INT0"-ISR gesetzten Flags auch schnell erkannt. >Aber was ist wenn mein Programm nicht durchschnittlich ist? Kann aber natürlich sein, dass ein Zustandautomat für das "nicht durchschnittliche" Programm zu durchschnittlich ist...
Hc Zimmerer schrieb: > Nach meinem Verständnis von setjmp/longjmp bei gcc merkt sich dieser > tatsächlich ein Stack-Frame, zu dem er bei longjmp zurückkehrt, wobei > der Teil darunter "discarded" wird. Natürlich balanciert setjmp/longjmp den Stack aus, wie alle C-Funktionen. Im AVR-GCC restauriert es auch den Interrupt-Enable-Status. In C braucht man sich um den Stack nicht zu kümmern, der Compiler ist in der Pflicht, ihn sauber zu halten. > So verrückt die Idee ist, sie könnte klappen Sie klappt. Trotzdem wird es nur selten verwendet, da es die Programmstruktur zerstört. D.h. solche Programme sind unübersichtlich, fehlerträchtig und schwer wartbar, erweiterbar. Es ist natürlich nicht schlimm, wenn irgendwelche Berechnungen abgewürgt werden. Dafür gehen aber fast alle Hardwarezugriffe in die Hose. Z.B. I2C, UART, SPI mögen sowas garnicht, wenn Pakete zerstört werden und halb gesetzte/gelesene 16Bit-Timer, ADCs können die wunderlichsten Effekte bewirken. Ich muß auch zustimmen, ich habs noch nie gebraucht. Reaktionen innerhalb 300ms auf nen Tastendruck werden vom Menschen als sofort empfunden. Es ist also unsinnig, um 10ms zu kämpfen und man kann ruhig alle gerade laufende Prozesse geordnet abschließen. Ich arbeite oft mit einer Mainloop, deren maximale Durchlaufzeit <200ms ist. D.h. ein Notaus muß nur einmalig in der Mainloop abgefragt werden. Länger als 200ms dauernde Sequenzen werden über einen Sequenzer (Statemachine) häppchenweise durchlaufen. Natürlich wird die Taste mit einem Timerinterrupt entprellt und gemerkt, kann also nicht verloren gehen, wenn jemand nur 100ms kurz draufhaut. Peter
Wobei 200ms bei einem Notaus schon lang sind. Vielleicht reichts noch für die subjektive Wahrnehmung, dass nach dem Tastendruck "sofort" was passiert. Spätestens im Schadensbild ist die Verzögerung dann aber je nach Umständen objektiv feststellbar.
der mechatroniker schrieb: > Wobei 200ms bei einem Notaus schon lang sind. Vielleicht reichts noch > für die subjektive Wahrnehmung, dass nach dem Tastendruck "sofort" was > passiert. Spätestens im Schadensbild ist die Verzögerung dann aber je > nach Umständen objektiv feststellbar. Das glaub ich nicht. Kein Mensch kann innerhalb von 200ms auf eine Fehlersituation mit einem Druck auf Notaus reagieren. Das dauert seine Zeit und da spielen dann 200ms mehr 'Reaktionszeit' auch keine große Rolle mehr, wenn die Maschine vorher schon 2 Minuten gequalmt hat. (Wobei 200ms schon extrem lang sind. Wenn man sich nicht allzu ungeschickt anstellt, dann ist diese Zeit locker auf 20ms oder weniger zu drücken) Ich glaube eher, wir haben wieder mal die Situation: Verbocktes Programm, dass irgendwann hängt. Sprich: ein Programmfehler. Und der 'Notaus' soll jetzt wieder mal alles richten.
@ der mechatroniker (Gast)
>Wobei 200ms bei einem Notaus schon lang sind.
Notaus per Software? Hust besser nicht . . .
MFG
Falk
Der Fairness halber muss man allerdings sagen, dass der TO nie von einem Notaus gesprochen hat. Es geht um einen 'Resettaster'.
Wenn ich ein goto aus einem Interrupt irgendwohin springen wollte, dann mache ich das! Stackpointer neu setzen, I-Flag löschen und was sonst noch in den Grundzustand gebracht werden muß. Fertig. Warum sollte ich mich zieren? Wenn ich ein Gerät auschalten will, dann mache ich das auch, wann ich will.
Ohne Aufwand schrieb: > Warum sollte ich mich zieren? Wenn ich ein Gerät auschalten will, dann > mache ich das auch, wann ich will. Du darfst gerne Deinen Tintendrucker mitten im Druckjob ausschalten. Denn Du bist es, der den eingetrockneten Druckkopf wechseln muß. Du darfst auch gerne Deinen PC ohne Shutdown ausschalten und Dich über zerstörte Daten auf der Festplatte freuen. Man darf immer das tun, was man will, wenn man die Folgen in Kauf nimmt. Man kann aber auch einfach vernünftig handeln und sich dann über die vermiedene Fehlfunktion und den gesparten Ärger freuen. Peter
Ohne Aufwand schrieb: > Wenn ich ein goto aus einem Interrupt irgendwohin springen wollte, dann > mache ich das! > > Stackpointer neu setzen, I-Flag löschen und was sonst noch in den > Grundzustand gebracht werden muß. Fertig. > Warum sollte ich mich zieren? Wenn ich ein Gerät auschalten will, dann > mache ich das auch, wann ich will. Kannst Du. Aber wenn ich Dein Chef bin, dann mache ich auch mit Dir was ich will ...
lalala schrieb:
> Bist du denn sein Chef? Fänd ich lustig...
OK, Deutschproblem
Wenn ich Dein Chef wäre, usw ...
>Bist du denn sein Chef? Fänd ich lustig...
Ich auch, dann hätte er nämlich ein Problem :-)
Warum seid Ihr bloß so ängstlich? Wenn dies nicht als Frage aufgetaucht
wäre, sondern von einem Platzhirsch in der Codesammlung, dann wäre es
die geniale Lösung gewesen.
Und plötzlich geht es nicht mehr um eine allgemeine µC Frage, sondern
gleich um einen Tintendrucker oder eine Festplatte, womöglich noch um
ein Flugzeug, was dann natürlich auf eine Millionenstadt abstürzt...
Der Themenersteller könnte ja freundlicherweise mal was von seinem Code posten. Manche würden aber anscheinend eher ihre Freundin verkaufen, als das zu tun... ;-)
Ohne Aufwand schrieb: > Wenn ich ein goto aus einem Interrupt irgendwohin springen wollte, dann > mache ich das! Würde ich auch machen. Nur wollte ich das noch nie, weil es bisher immer ohne solch eine Dampfhammermethode ging. Und wenn ich da in der Beschreibung was von Taste am INT0 lese, woraufhin sofort ganz schnell was passieren sollen müsste, kann ich jetzt schon sagen (wie alle vor mir auch), daß das nicht notwendig ist. Weder sofort noch ganz schnell (nach Mikrocontrollermaßstäben) noch überhaupt. Das ist die falsche Lösung zur falschen Antwort auf die falsche Frage. Oliver
> Wenn ich ein goto aus einem Interrupt irgendwohin springen wollte, dann > mache ich das! Und durch welchen genialen Trick umgehst du das Problem der Stack-Inkonsistenzen? Denk dir mal ein Stück Code in Assembler-Form. Irgendwo steht ein Push, später mal das dazugehörige Pop. Nun wird genau dazwischen der Interrupt ausgelöst, der verursacht einen Sprung an eine ganz andere Stelle im Programm, und das Pop wird nie ausgeführt. Und das ist noch die einfache Variante, denn in C hast du nicht mal mehr die Kontrolle über Stack und Register. Diese werden vom Compiler automatisch verwaltet. >> Bist du denn sein Chef? Fänd ich lustig... > > Ich auch, dann hätte er nämlich ein Problem :-) Bist du so ein problematischer Mitarbeiter? > Warum seid Ihr bloß so ängstlich? Weil es gelinde gesagt eine blöde Idee ist. > Wenn dies nicht als Frage aufgetaucht wäre, sondern von einem > Platzhirsch in der Codesammlung, dann wäre es die geniale Lösung > gewesen. Nein, wäre es nicht. Man wäre vom "Platzhirsch" enttäuscht gewesen. > Und plötzlich geht es nicht mehr um eine allgemeine µC Frage, sondern > gleich um einen Tintendrucker oder eine Festplatte, womöglich noch um > ein Flugzeug, was dann natürlich auf eine Millionenstadt abstürzt... Du hast mit gen Vergleichen begonnen.
>Und durch welchen genialen Trick umgehst du das Problem der >Stack-Inkonsistenzen? Wenn man nach main springt, sollte es die nicht geben. Lediglich bei 8051 sollte man noch eine Funktion aufrufen, die mit RETI endet, damit seine altertümliche Interruptbearbeitung wieder ins Lot kommt. >Du hast mit gen Vergleichen begonnen. Mea maxima culpa, obwohl ich das nicht nachvollziehen kann. Kannste ja Deinem Lehrer pätzen.
> Wenn man nach main springt, ... und vor dem Interrupt auch schon in main war ... > sollte es die nicht geben. Sollte vielleicht nicht, aber könnte trotzdem.
"Ich springe, solange ich will!" Dann schliesse den verdammten Taster an den verdammten Reset an und alle Fragen sind geklärt.
Ich denke es gibt eine einfache Lösung mit nur ein paar Zeilen: Es wird in der IRQ Routine einfach ein EEPROM Speicherplatz mit einem 0xFF beschrieben und ein Reset im Programm (in der IRQ Routine noch selbst) ausgelöst. Am Anfang vom main() wird zuerst im EEPROM nachgeschaut, ob 0xFF drinnen steht. Wenn ein 0xFF drinnen steht, dann wurde der Neustart durch den IRQ ausgelöst, dann wird dieser Speicherplatz gelöscht (eine 0x00 rein geschrieben) und zu einer bestimmten Stelle gesprungen - wie Richi es gewünscht hat. Wenn irgendwas anderes drinnen steht, dann ist es ein normaler Reset gewesen und es geht im main() einfach weiter, als ob nichts gewesen wäre. Aber an dieser Stelle dann sollte danach auch erst wieder vorsichtshalber eine 0x00 hinein geschrieben werden - aus folgendem Grund: Nur beim ersten einschalten wird das EEPROM im undefinierten Zustand sein. Man kann es so lassen und es einfach ein zweites mal einschalten (spätestens dann steht durch die oben genannte Stelle eine 0x00 drinnen). Oder man beschreibt den EEPROM Inhalt schon mit dem STK500/600/Ponyprog usw. Dann wird auch das erste einschalten keine Fehlabfrage wegen undefiniertem Zustand sein.
>Am Anfang vom main() wird zuerst im EEPROM nachgeschaut, ob 0xFF drinnen >steht. Wenn ein 0xFF drinnen steht, dann wurde der Neustart durch den >IRQ ausgelöst, dann wird dieser Speicherplatz gelöscht (eine 0x00 rein >geschrieben) und zu einer bestimmten Stelle gesprungen - wie Richi es >gewünscht hat. Vor Anfang von main hat der startup-Code aber schon alle Variablen neu initialisiert. So ganz einfach irgendwo im Programm weitermachen geht damit nur, wenn keinerlei Daten aus dem Leben vor dem Reset benötigt werden (was eher unwahrscheinlich ist). Die könnte man zwar auch ins EEPROM retten, ebenso könnte man die Abfrage auf Warmstart in den startup-code verlegen, aber so oder so wird das alles extrem kompliziert. Oliver
Oliver schrieb: > Vor Anfang von main hat der startup-Code aber schon alle Variablen neu > initialisiert. Kann man verhindern.
Man kann vieles, aber wozu? Zu 99,9% ist ein unnötig kompliziertes Programmkonzept das Problem, dass es zu lösen gilt.
>Man kann vieles, aber wozu? Zu 99,9% ist ein unnötig kompliziertes >Programmkonzept das Problem, dass es zu lösen gilt. Wenn jemand so etwas vorhat, würde ich nicht gleich immer Dummheit unterstellen. Es gibt µCs, die haben diverse Vektoren für Kaltstart (reset), Warmstart (2.reset), Wachhund (watchdog) und obendrein noch NMI. Abhängig vom jeweiligen Ereignis, kann man komplett neu initialisieren, oder an einer Stelle aufsetzen, die nicht den kompletten RAM-Inhalt löscht oder i/o-Pins neu konfiguriert. Wenn ich an meine Monitorprogramme für diverse µC zurückdenke, da gab es immer eine harte Abbruchmöglichkeit (z.B.) NMI oder Ctrl-C, um ein hängendes Programm abzubrechen (mit Register dump) und dennoch nicht über Reset alles auf 0 zu setzen. Es kommt eben darauf an, was man machen will.
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.