Forum: Mikrocontroller und Digitale Elektronik interrupt ohne rücksprung


von thomas (Gast)


Lesenswert?

Hallo zusammen,
ich habe ein Verständnisproblem und würde mich freuen, wenn man mir 
helfen könnte. Ich programmiere in C. Wenn ich einen Interrupt auslöse, 
springt das Programm nach dem Durchlauf ja wieder an die Stelle, wo der 
Interrupt ausgelöst wurde. Kann man auch einen Interrupt auslösen, ohne 
das er sich merkt wo er gewesen ist? Das heißt, das Programm soll nach 
dem Interrupt einfach weiter laufen. Wäre für jede Antwort dankbar

von Karl H. (kbuchegg)


Lesenswert?

> Das heißt, das Programm soll nach
> dem Interrupt einfach weiter laufen.

Wo soll er denn weiterlaufen?
Wenn die Interruptfunktion zu Ende ist, muss es ja irgendwo weitergehen. 
Nur wo soll das denn sein, wenn nicht an der Stelle an der das 
Hauptprogramm unterbrochen wurde?

von Glaskugel (Gast)


Lesenswert?

Hallo Thomas,
was genau willst Du damit bezwecken?

Das Programm läuft an der Stelle weiter, an der es unterbrochen wurde!!! 
Welcher Sinn steckt hinter Deiner Frage....

von ROFL (Gast)


Lesenswert?

Zu deiner Frage habe ich ein Verständnisproblem.
Du sagst ja selbst, nach dem Ausführen der Interrupt-Routine springt der 
Prozessor wieder an die Stelle, an der der Interrupt ausgelöst wurde.
Das hat eben genau zur Folge, dass dein "eigentliches" Programm so 
weiterläuft, als sei es nie vom Interrupt unterbrochen worden.

von Peter D. (peda)


Lesenswert?

thomas wrote:
> Interrupt ausgelöst wurde. Kann man auch einen Interrupt auslösen, ohne
> das er sich merkt wo er gewesen ist?

Nein.

> Das heißt, das Programm soll nach
> dem Interrupt einfach weiter laufen.

Das nennt sich dann Chaos-Programmierung.
Du wirst mit diesem Ansatz nicht glücklich, sobald das Projekt etwas 
größer wird.

Wenn jeden Augenblich jede mögliche Task abgeschossen wird, kann man 
keine vernünftige Funktion erreichen.

Versuch mal mit Word einen Brief zu schreiben und ein anderer drückt 
ständig Alt-F4. Dann weißt Du wie sich die CPU bei Deinem Ansatz fühlt.


Peter

von thomas (Gast)


Lesenswert?

Also ich habe folgendes Problem:
Alle fünf Sekunden schicke ich über die Uart einen AT Befehl zu einem 
GSM Modul um die Netzqualität zu überprüfen. Jetzt rufe ich das Modul an 
und will einen anderen Interrupt auslösen, was auch funktioniert. Aber 
wenn ich genau dann anrufe, wenn der erste Interrupt ausgelöst wird, 
dann springt er im 2Interrupt an die Stelle des ersten Interrupts, 
obwohl der zweite Interrupt noch nicht komplett Abgearbeitet ist! Ich 
hoffe ihr könnt verstehen was ich meine, ist ein bischen doof zu 
erklären.
Ich probiere es noch mal anders:
Nach fünf Sekunden schicke ich at+csq ab und erhalt als Antwort 19,0 
alles super!
Dann rufe ich das Modul an erkennt, das ich z.B. nicht autorisiert bin 
und legt mit at+chup wieder auf. Erkennen kann ich das daran, dass ich 
"OK" zurückbekomme wenn at+chup erfolgreich war.
Jetzt passiert folgendes: Nach fünf Sekunden schickt das Programm at+csq
jetzt rufe ich an, dann macht das Programm at+chup und jetzt kommt kein 
OK sonder z.B 17,00 (Signalstärke) und das Programm hängt sich auf.
Ich habe probiert den Interrupt zu sperren cli() vor dem Befehl at+chup 
und danach wieder frezugeben mit sei(), aber trotzdem taucht der Fehler 
auf.

von Oliver (Gast)


Lesenswert?

Meine Glaskugel sagt mir, daß das alles überhaupt nichts mit Interrupts 
zu tun hat, sondern schlicht und einfach an einer völlig ungeeigneten 
Programmstruktur liegt.
Zumal auf einem AVR, auf dem die Befehle cli und sei Sinn machen würden, 
eine ISR nicht freiwillig für eine andere unterbrochen wird.

Also wie immer: Zeig mal den Code.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Ich werd zwar aus deiner Beschriebung nicht wirklich schlau, aber eines 
ist sicher: Deine Software-Architektur stimmt nicht. Mit deinem 
Interrupt-Return verbiegen löst du das eigentliche Problem nicht.
Ein Haus, das auf Sand gebaut ist, kann man zwar mit Holzbalken 
abstützen.  Das wird aber immer Stückwerk bleiben. Besser ist es das 
Haus abzureissen und zuallererst mal ein vernünftiges Fundament bauen.

In deinem Fall klingt das für mich:
Du hast dir nicht richtg überlegt, wie man einen µC dazu bringen kann, 
einzelne Tasks geordnet nacheinander abzuarbeiten. Das Stichwort dazu 
lautet: Job-Flags.
Ein Interrupt macht so gut wie keine Arbeit selber, sondern er setzt ein 
Jobflag, welches der Hauptschleife mitteilt, dass es wieder mal Zeit 
wäre die Signalqualität zu überprüfen.
Die Hauptschleife registriert dieses Ansinnen anhand des Jobflags und 
entscheidet, dass genau das zum jetzigen Zeitpunkt nicht machbar ist, 
weil da noch ein Anruf in der Bearbeitung steckt. Oder umgekehrt: Das 
ein Anruf reinkommt, der aber momentan nicht bearbeitet werden kann, 
weil gerade eine Signalqualitätsprüfung läuft.

Dein Problem ist ganz einfach, dass die linke Hand nichts davon weiß was 
die rechte Hand gerade macht. Die Lösung kann aber nicht lauten: Dann 
hauen wir halt mal auf die Finger. Die Lösung kann nur lauten: Es 
braucht eine Einrichtung, die die beiden Aktivitäten koordiniert.

(Oder so ähnlich. Wie gesagt, ich werde aus dem Zeugs da oben nicht 
wirklich schlau)

von thomas (Gast)


Lesenswert?

Ich darf leider nicht viel an Programmcode posten, aber ich kann die 
Struktur erklären, vielleicht liegt da ja der Hund begraben.
ISR(USART0_RXC_vect)
{
  flag=1;
}
ISR(USART1_RXC_vect){}
ISR(TIMER2_OVF_vect)
{
  time++;
}


int main()
{
  if(flag==1)
  {   mache was
     ;
     ;
     ;
     ;
     ;
      flag=0;
  }
  if(time==5)
  {
    uart0_puts("at+csq\r");
  }
wenn ich jetzt anrufe, dann wird über die uart0 vom gsm modul ein string 
rübergeschickt, also flag =1
}
ist das schon eine schlecht struktur?
wenn ja, wie sieht denn ein e gute struktur aus?

von thomas (Gast)


Lesenswert?

natürlich wird time immer wieder null gesetzt

von Johannes M. (johnny-m)


Lesenswert?

thomas wrote:
> ISR(USART0_RXC_vect)
> {
>   flag=1;
> }
> ISR(USART1_RXC_vect){}
Das ist tödlich! Die Interrupt Flags RXC0/1 werden erst dann gelöscht, 
wenn das UDR ausgelesen wird. Im Interrupt Handler muss deshalb UDR0 
bzw. 1 ausgelesen werden, sonst wird er immer wieder aufgerufen.

Dass das Programm / der µC sich aufhängen, wenn zwei Interrupt Handler 
ständig wieder aufgerufen werden und zwischen ihnen nur jeweils ein 
einzelner Befehl im Hauptprogramm bearbeitet wird, ist hoffentlich 
klar...

von was-willst-du (Gast)


Lesenswert?

>Ich darf leider nicht viel an Programmcode posten

Was ist das für eine Geheimprogrammierung? Willst Du ne fundierte 
Antwort oder sollen alle raten, was Du falsch machst?

- Aufgabenstellung verständlich erklären
- Fakten auf den Tisch legen
- Frage in verständlichem Deutsch formulieren

So klappts auch mit den Interrupts.

von thomas (Gast)


Lesenswert?

Hallo Johannes, heißt das, dass der Interrupt sozusagen zu lange 
ausgeführt wird? Bezw. zu oft? Wie müsste den dann der Händler aussehen?
Danke im voraus!

von Johannes M. (johnny-m)


Lesenswert?

thomas wrote:
> Hallo Johannes, heißt das, dass der Interrupt sozusagen zu lange
> ausgeführt wird? Bezw. zu oft? Wie müsste den dann der Händler aussehen?
> Danke im voraus!
Schreib ich chinesisch? Ich habe oben geschrieben, dass in den beiden 
Inerrupt Handlern das dazugehörige Datenregister ausgelesen werden muss, 
damit das jeweilige Interrupt Flag gelöscht wird. Das kann doch nicht so 
schwer zu verstehen sein...

Noch mal: Wenn einer der beiden Interrupts auftritt, wird das 
dazugeörige Flag gesetzt und der Handler ausgeführt. Wenn der Handler 
beendet wird, ohne dass das Datenregister gelesen wurde, ist das Flag 
nach dem Rücksprung noch gesetzt und der Handler wird praktisch sofort 
wieder aufgerufen, und zwar so lange, bis das Programm irgendwann mal an 
einer Stelle anlangt, wo das UDR ausgelesen und damit das Flag gelöscht 
wird!

von Karl H. (kbuchegg)


Lesenswert?

Johannes M. wrote:
> thomas wrote:
>> ISR(USART0_RXC_vect)
>> {
>>   flag=1;
>> }
>> ISR(USART1_RXC_vect){}
> Das ist tödlich! Die Interrupt Flags RXC0/1 werden erst dann gelöscht,
> wenn das UDR ausgelesen wird. Im Interrupt Handler muss deshalb UDR0
> bzw. 1 ausgelesen werden, sonst wird er immer wieder aufgerufen.

Ich denke mal, dass hier thomas aus 'Geheimhaltungsgründen' wieder mal 
einiges nicht gezeigt hat.


Daher wieder mal der Appell: zeig deinen richtigen Code, nicht etwas was 
so aussieht oder so ähnlich ist oder fast dem entspricht was du hast. 
Abspecken auf das Notwendigste macht Sinn, aber die relevanten Sachen 
genau so präsentieren wie sie wirklich im Code sind.

Und Freunde: Kommt nicht immer mit diesem Geheimhaltungsquatsch. 
Entweder ihr dürft in der Öffentlichkeit nach Hilfe fragen oder ihr 
dürft es nicht. Kein Mensch wird aus diesem Forum ein kommerzielles 
Projekt, das noch in der Entwicklungsphase steckt, klauen.

von thomas (Gast)


Lesenswert?

Es ist doch so, dass in den Interrupt Routinen so wenig wie möglich 
stehen soll, damit die Zeit so kurz wie möglich gehalten wird, oder?

von Johannes M. (johnny-m)


Lesenswert?

thomas wrote:
> Es ist doch so, dass in den Interrupt Routinen so wenig wie möglich
> stehen soll, damit die Zeit so kurz wie möglich gehalten wird, oder?
Aber das UDR muss trotzdem im Interrupt Handler gelesen werden. Und 
wenn Du das nicht tust, wird es nicht funktionieren! Ansonsten muss ich 
Karl heinz zustimmen...

von thomas (Gast)


Lesenswert?

Doch das ist alles was in der Interrupt Routine steht!
Wenn etwas über Uart0 empfangen wird, wird flag=1, und im Hauptrpogramm 
wird dann alles weitere Gehändelt, wie die einzelnen Zeichen über uart1 
ausgeben.
Ich wusste nicht, das man das UDR im Interrupthändler auslesen muss! das 
Probiere ich mal aus

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.