Gibt es eine Möglichkeit (Routine, C Befehle, Syntaxe....) einen Funktionsablauf nach Rückkehr aus einer ISR sofort zu beenden? Konkret: Ich sende in einer Funktion (nicht main) in einer while schleife jede Sekunde ein kleines Datenpaket per UART raus. Nun soll dieses Senden aber sofort beendet werden, wenn ein bestimmtes Byte empfangen wird. Daüfr habe ich natürlich eine UART ISR angelegt die aufgerufen wird sobald Daten empfangen werden. (Das funktioniert auch alles). In dieser ISR prüfe ich dann ob dieses empfangene Byte einen bestimmten Wert hat und dann will ich das Senden einstellen. Möglichkeiten die mir einfallen aber unpraktisch sind: 1. in der Sende While schleife nach jedem!!! Sendebefehle (UCA0TXBUF usw..) eine andere Funktion aufrufen und überprüfen ob letztes empfangenes Byte eben dem Abbruchkriterium entsprich. Wenn ja dann mit break schleife verlassen. Diese Möglichkeit finde ich doof, weil mich dieser unnötige ständige Funktionsaufruf stört. 2. Die SendeFunktion derart veränder das zb. vorher immer geprüft wird ob a==1. In der ISR bei wahrer Abbruchbedingung einfach a=1 setzen und die Sendefunktion erneut aufrufen (oder zb. mit Übergabewert). Dann in der Sendefunktion entsprechend handeln. Diese Variante wird wahrschenlich funktionieren ABER ich bekome Bauchschmerzen, weil ich damit den ganzen Stack voll lege. Denn dann befindet sich die ISR und die Sendefunktion auf dem Stack (bzw. die Sprungadressen). Wenn ich dan irgendwann die Sendefunktion beende, wird aufeinmal wieder die ISR zu Ende geführt bzw. es erfolgt ein Senden (weil quasi die Daten ja noch nicht alle rausgeschickt wurden... es wurde ja abgebrochen...) Das ist also auch doof. Ich suche nach einer Möglichkeit wie ich allgemein gesagt, einer Funktion nach Wiedereinritt aus einer anderen mitteile dass sie nun beendet werden soll. Da die ISR aber eben nicht durch Software sondern Hardware aufgerufen wird kann ich nicht einfach sows machen: Sendefunktion (void) { //sende daten.. ... if(Empfangs_ISR()==0) break; } Auch kann ich der ISR ja keinen Rückgabewert erteilen oder?? (Sie ist ja immer void). Ist ja auch logisch, denn wenn das Programm aus der ISR wiederkommt, kann es mit einem Rückgabewert nichts anfangen. (es gibt ja kein if(ISR()==0).. oder a=ISR() Erledigen vielleicht CallBack Funktionen sowas? Hört sich zumindestens so an. Wäre über ein par Gedanken sehr dankbar...
Martin schrieb: > 1. in der Sende While schleife nach jedem!!! Sendebefehle (UCA0TXBUF > usw..) eine andere Funktion aufrufen und überprüfen ob letztes > empfangenes Byte eben dem Abbruchkriterium entsprich. Wenn ja dann mit > break schleife verlassen. Diese Möglichkeit finde ich doof, weil mich > dieser unnötige ständige Funktionsaufruf stört. Warum sollten Aufrufe stören? Die CPU führt ständig Aufrufe aus, von Einschalten der VCC bis zum Abschalten. Das ist ihr Job. Das ist also der ganz normale Weg: Du sendest ein Byte und dann rufst Du ne Funktion auf, die Dir sagt, ob Du das nächste senden sollst. Peter
Wenns nur darum geht, den ständigen Funktionsoverhead zu vermeiden, würd ich in der ISR einfach ein Flag setzen und vor dem Senden mit if() abfragen.
hmm ist das nen µC? falls ja hat der doch bestimmt nen interrupt wenn ein byte fertig gesendet wurde? damit wird dann eine subroutine aufgerufen die prüft ob noch weitere bytes gesendet werden sollen oder ob der ganze string "weg" ist. da kann man doch einfach ein flag einbauen, daß er abbricht und den rest vom string verwirft wenn dieses flag gesetzt ist...
Oh danke schonmal @Ben Das ist eine gute Idee, mit dem TXD Interrupt hab ich bis jetzt nicht gearbeitet. Wers mal versuchen. Verstehe ich sas richtig? Sobald das Byte das Shiftregister verlassen hat, wird dann bei richtiger Initialisrung das TXD Flag gesetzt und ISR ausgeührt? Also analog zu dem von mir verwendetem RXD Flag.... @Peter Ja klar ist es der Job des uC, aber ich will ja nicht das er anfängt zu schwitzen und dann noch von seinen eigentlichen Aufgaben abkommt. Wenn ichs aber recht überlege, kann ich mir eine kleine Überprüfung bei 9600 Baud wohl erlauben... @MeinerEiner Meinst du mit Flag einfach ne globale Variable? Danke für eure Antworten. Ihr habt mir sehr gute Lösungsansätze gegeben
Du kannst auch einfach in der ISR die Rücksprungadresse überschreiben, wird dann aber kein schönes Programm, und wartbar ist es auch nicht wirklich...
ich muß gestehen ich hab mit rs-232 noch nicht allzu viel sinnvolles gemacht. ich wollte nur wissen ob mein marke-eigenbau-testboard das kann. ich fand diesen interrupt die einfachere lösung weil mir der AVR damit von ganz alleine sagt wann er mit der übertragung von einem byte fertig ist und ich ihn nicht dauernd fragen brauch. wenn du jetzt weiter senden willst schreibst du das nächste byte in das entsprechende register und startest den transfer wieder. der nächste interrupt kommt wieder wenn das weg ist usw usw usw. wenn du aber keinen neuen transfer startest kommt auch kein neuer interrupt. du brauchst dir also nur ein flag im ram oder so setzen und das in der interruptroutine abfragen. ist es gesetzt verlässt du die routine einfach und das senden ist beendet weil keine neuen interrupts kommen. wenn du dann wieder was senden willst rufst du ja irgendeine funktion auf, die die startposition usw. setzt. die löscht dann auch das flag und startet den transfer des ersten bytes, der rest läuft von ganz alleine.
@Ben Ja versteh schon prinzipiell. Ich soll also wenn ich weiter senden möchte in der TXD-ISR die Sendefunktion aufrufen. Damit würde ich doch aber die ISR nie richtig beenden sondern immer wieder über den Funktionsaufruf verlassen...
Martin schrieb: > @Ben > > Ja versteh schon prinzipiell. Ich soll also wenn ich weiter senden > möchte in der TXD-ISR die Sendefunktion aufrufen. Damit würde ich doch > aber die ISR nie richtig beenden sondern immer wieder über den > Funktionsaufruf verlassen... Äh nein. Die Funktion kommt zurück zur ISR und die ISR steigt ganz normal aus.
Also das versteh ich nicht. Wo wird deiner Ausführung nach, nun die Sendefunktion aufgerufen? a) In der ISR b) garnicht, sie wird nur unterbrochen während ISR nach Senden eines Bytes aufgerufen wird Du meinst also das die ISR sozusagen akiv ein weiteres Senden verhindert,(indem Flag überprüft wird) jedoch nicht aktiv selbst zum Senden führt. Denn das macht die Sendefunktion alleine.
wofür steht bei dir ISR genau? durch den interrupt startet sich die funktion solange immer wieder selber bis sie keinen weiteren transfer startet. damit wird auch kein neuer interrupt ausgelöst und die funktion nicht länger neu gestartet. bei meinem test war das so gelöst, daß die zu übertragenden zeichen in einem puffer im RAM standen und deren anzahl bekannt war, zum starten wurde einfach der positionszeiger auf anfang gesetzt und der transfer des ersten zeichens gestartet. das wars, den rest macht der AVR von selber. du kannst dich also um andere dinge kümmern ohne den transfer weiter kontrollieren zu müssen. auch eine abfrage ob fertig ist jederzeit machbar, da wird einfach der positionszeiger mit der anzahl der zu übertragenden zeichen verglichen. sind beide identisch ist die übertragung beendet. die interruptroutine wurde durch den transfer-beendet-interrupt aufgerufen, hat kontrolliert ob noch weitere zeichen zu senden sind, wenn ja wurde der positionszeiger inkrementiert, das nächste zeichen geladen und ein neuer transfer gestartet, wenn nicht wurde die routine einfach ohne weiteres wieder verlassen. oder was willst du wissen?
Na endlich verstehen wir uns. ;) ISR = Interrupt Service Routine Fast genau den selben Ablauf habe ich schon implementiert. Nur eben nicht in der ISR sondern in einer eigenen Funktion. Ich arbeite mit dem MSP da geht der beschriebene Ablauf ebenso einfach. Wie die Routine aufgerufen wird ist klar. Nämlich durch einen Hardware Interrupt. Und sie staret sich immer wieder selbst. Die Daten werden also aus der ISR herraus gesendet und dann startet wieder die ISR. Das werde ich zwar etwas anders machen, aber das Problem mit dem Sendeabbruch lässt sich so lösen, denke ich. Es bleibt aber immer noch der Fakt das in deinem Fall, die ISR nicht ordentlich beendet wird. Denn bevor sie zu Ende ist, wird sie erneut aufgerufen.... Das heißt es wird der Stack zugemöhlt.
quatsch. die sog. "ISR" wird natürlich ordentlich beendet. wenn der transfer des nächsten bytes angestubst wurde holt man alle verwendeten datenregister und statusregister vom stack und am ende gibts nen schicken iret.
Was is hier quatsch. Wenn du mal etwas genauer beschreiben würdest, würde wir auch nicht immer an einander vorbeireden. Wenn du innerhalb der ISR erneut die ISR aufrufen lässt (durch den Interrupt), dann läuft die Funktion nicht "normal" durch bis ans Ende, sondern wird früher beendet. Erst wenn diese richtig beendet wird, nämlich dann wenn kein neuer Interrupt kommt wird der Stack leer geräumt. Wenn der Sendebefehl der letzte in der ISR ist dann wird natürlich nicht viel passieren außer etliche mal ein "schließen" der ISR. Und was ist ein iret
iret = interrupt return die routine kann sich gar nicht so einfach selbst starten, sie startet sich indirekt über den interrupt wieder wenn der nächste transfer beendet ist. bis dahin ist sie aber bereits laaaaaaaaange wieder beendet, da der uart deutlich langsamer ist als die cpu.
Ja das macht Sinn. Letzte Frage: Wie startest du den Sendevorgang, wenn noch garkeine Daten empfangen wurden. Das erste Zeichen muss also von außerhalb gesendet werden damit der Zyklus ersteinmal beginnt...?
das erste zeichen muß das hauptprogramm bzw. eine subroutine senden, sonst kann natürlich kein interrupt ausgelöst werden. aber mit diesem einen zeichen senden ist der gesamte sendevorgang für das hauptprogramm abgeschlossen, es braucht sich danach um nichts weiter zu kümmern.
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.