Forum: Mikrocontroller und Digitale Elektronik Funktion mittels ISR beenden


von Martin (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von MeinerEiner (Gast)


Lesenswert?

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.

von Ben (Gast)


Lesenswert?

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

von Martin (Gast)


Lesenswert?

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

von Claudio H. (bastelfinger)


Lesenswert?

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

von Ben (Gast)


Lesenswert?

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.

von Martin (Gast)


Lesenswert?

@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...

von Karl H. (kbuchegg)


Lesenswert?

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.

von Martin (Gast)


Lesenswert?

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.

von Ben (Gast)


Lesenswert?

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?

von Martin (Gast)


Lesenswert?

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.

von Ben (Gast)


Lesenswert?

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.

von Martin (Gast)


Lesenswert?

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

von Ben (Gast)


Lesenswert?

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.

von Martin (Gast)


Lesenswert?

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

von Ben (Gast)


Lesenswert?

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.

von Martin (Gast)


Lesenswert?

Ok, danke

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.