Forum: Mikrocontroller und Digitale Elektronik Interrupt macht Endlosschleife?


von schurli (Gast)


Lesenswert?

Hi

Wenn ich den Externen Interrupt auslöse, wird "Funktion ()" in einer 
Endlosschleife ausgeführt. Wie kann ich das Verhindern?

Hier mein kurzer Code:
int main (void){

//Initzialisierung der Interrupts
  MCUCR = (1<<ISC01) | (1<<ISC00);
  GICR = (1<<INT0);
  sei();

}

ISR(INT0_vect) //externer Interrupt auf Pin INT0
  {
    Funktion ();
  }


Vielen Dank!

von Patrick (Gast)


Lesenswert?

Wie sieht denn Deine "Funktion()" aus?

von Patrick (Gast)


Lesenswert?

Was für einen Controller verwendest Du? Nimmst Du da nicht die falschen 
Register? Anstatt des MCUCR müsstest Du doch das EICRA nehmen.

von Patrick (Gast)


Lesenswert?

Also eigentlich:
1
int main (void){
2
3
//Initzialisierung der Interrupts
4
  EICRA = (1<<ISC01) | (1<<ISC00);
5
  EIMSK = (1<<INT0);
6
  sei();
7
8
}
9
10
ISR(INT0_vect) //externer Interrupt auf Pin INT0
11
  {
12
    Funktion ();
13
  }

Aber das kommt auf Deinen Controller an.

von schurli (Gast)


Lesenswert?

Hi

Der Prozessor macht 100% einen Rücksprung aus der Funktion.
Hab das ganze schon mit nem LCD und Textausgabe getestet.

Habe folgendes gemacht um es zu Testen:

ISR(INT0_vect) //externer Interrupt auf Pin INT0
  {
   ...LCD Ausgabe "start"

    Funktion ();

   ...LCD Ausgabe "ende"

    while(1)
    {;
    }

  }


Mit der Eingebauten Endlosschleife wird die Funktion nur einmal 
ausgeführt - ist aber nicht sinn und Zweck meines Programms.

mfg

von tastendrücker (Gast)


Lesenswert?

Sicher, dass das Interrupt-Flag gelöscht wird?

von schurli (Gast)


Lesenswert?

Muss man das Flag am Ende des interrupts löschen?

von tastendrücker (Gast)


Lesenswert?

Das weiss ich bei deinem µC bzw. Compiler nicht. Bei PIC's/Assembler 
muss man die Flags löschen, bzw. sie werden bei bestimmten Aktionen 
gelöscht. Z.B. wird das USART RXIF durch lesen des RX-Registers gelöscht 
(wenn ich's richtig in Erinnerung habe).

von Klaus (Gast)


Lesenswert?

Ja, zum Beispiel bei ARM geschieht das nicht automatisch. Und solange 
man da das Flag/Bit der Quelle, welche den Interrupt ausgelöst hat, 
nicht zurücksetzt, wird sofort nach Rücksprung aus der Interrupt-Routine 
wieder ein Interrupt ausgelöst.

von schurli (Gast)


Lesenswert?

Kann mir jemand sagen wie das für einen Atmega32 unter C funktioniert?

mfg

von MM (Gast)


Lesenswert?

Das hängt davon ab, was es für ein Interrupt ist.

Wenn es ein Level getriggerter Interrupt ist, wird der solange wie
der Pin LOW ist immer wieder aufgerufen. Vermute, daß es das ist was 
passiert.

Ein flankengetriggerter INT wird nur jeweils einmal ausgelöst und
ausgeführt.

Gruß, Marcus

von schurli (Gast)


Lesenswert?

Meiner ist Flankengetriggert, wird aber immer wieder durchlaufen?

von SoLaLa (Gast)


Lesenswert?

vielleicht... vielleicht... vielleicht solltest Du mal Deinen kompletten 
source posten

von Klaus (Gast)


Lesenswert?

Außerdem sollte am Ende von Main noch ein
1
while(1);
 stehen. Sonst rennt der Controller über das Ende von Main hinaus und 
baut Mist.

von schurli (Gast)


Lesenswert?

Hier der Code:
Dient dazu, ein Sms mit dem Avr zu versenden.
Code zum Versenden stammt hauptsächlich von Ulrich Radig - vielen Dank.

Warum läuft der Interrupt in einer Endlosschleife.
Ausgelöst wird er duch einen prellenden Schalter. Das ist meiner Meinung 
nach aber kein Grund für die Endlosschleife.



[c]
#include <main.h>

#include <stdint.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include "lcd.h"


int main (void){


  //Initzialisierung der Interrupts
  MCUCR = (1<<ISC01) | (1<<ISC00);
  GICR = (1<<INT0);
  sei();


  /* initialize display, cursor off */
      lcd_init(LCD_DISP_ON);

      /* clear display and home cursor */
      lcd_clrscr();
  lcd_puts("AVR Test\n");

  //Hauptprogramm
  while (1)
  {

  }



return (1);
}

ISR(INT0_vect) //externer Interrupt auf Pin INT0
  {


  lcd_clrscr();
  lcd_puts("*   sending!   *");

  Send_SMS("464646467","TESTALARM",0,0);

  lcd_clrscr();
  lcd_puts("funktioniert!");


  }





char Send_SMS (char* zielnummer,char* nachricht, char i,char j)
{  unsigned char tmp1 = 0;
  unsigned char tmp2 = 0;
  unsigned char tmp3 = 0;
  unsigned char tmp4 = 1;
  unsigned char nachrichtneu[49];
  unsigned char zielnummerneu[16];
  unsigned char shift = 0;
  unsigned char k=0;

  //erzeugen des Nachrichten Strings

  if (!i)
  {
  while (nachricht[tmp1] != 0){
    nachrichtneu[tmp4] = (nachricht[tmp1]&0x7F)>>shift;
    if (shift != 0){
      nachrichtneu[tmp4-1] |= 
(nachricht[tmp1]&((1<<shift)-1))<<(8-shift);
      };
    shift++;
    tmp1++;
    if (shift == 8){
      shift=0;
    }
    else{
      tmp4++;
    }
  }
  nachrichtneu[0]= tmp1;
  }
  else
  {

    for(tmp4=0;tmp4<(2*strlen(nachricht));tmp4=tmp4+2)
    {  nachrichtneu[tmp4+1]=0;
      nachrichtneu[tmp4+2]=nachricht[k];
      k++;
      //printf("%02X", nachrichtneu[v]);
      //printf("%02X", nachrichtneu[v+1]);
    }
    tmp4; //++;
    nachrichtneu[0]=tmp4;
    printf("\n");
  }

  while (zielnummer[tmp3] !=0){
  tmp2 = zielnummer[tmp3+1];
  zielnummerneu[tmp3+1] = zielnummer[tmp3];
  if (tmp4 == 0){
    zielnummerneu[tmp3] = 'F';
    tmp3=tmp3 + 2;
    zielnummerneu[tmp3] = 0x0;
    break;
  }
  zielnummerneu[tmp3] = tmp2;
  tmp3=tmp3 + 2;
  zielnummerneu[tmp3] = 0x0;
  }


  printf("at+cmgs=%i\r\n",(tmp4+(tmp3/2)+ smsclen));
  while(uart_getchar()!='>');

  printf("%02X", smsclen);
  printf(smscnumber);


  printf(firstoctet);

  printf(tp_mr);

  if(zielnummerneu[tmp3-2] =='F'){
  tmp3--;
  };
  printf("%02X91",tmp3);
  printf(zielnummerneu);


  printf(tp_pid);

  if (!i)
  {
  if(j)
  {printf(tp_dcs7_c1);}
  else
  {printf(tp_dcs7_c0);}
  }
  else
  {printf(tp_dcs16_c0);}




  for (tmp1=0;tmp1<tmp4;tmp1++){
    printf("%02X", nachrichtneu[tmp1]);
  };
  printf("%c",0x1a); //Strg+Z


  while(uart_getchar()!='+');

return (1);
}
  [c]

von schurli (Gast)


Lesenswert?

Hat keiner eine Idee?

von tastendrücker (Gast)


Lesenswert?

hmmm. Ich (PICer) habe mir mal ein Datasheet vom Atmega32 runtergeladen. 
Da steht zumindest, das das I-Flag automatisch gelöscht wird, wenn die 
ISR aufgerufen wird:

----------------------------------------------
• Bit 6 – INTF0: External Interrupt Flag 0
When an edge or logic change on the INT0 pin triggers an interrupt 
request, INTF0 becomes set
(one). If the I-bit in SREG and the INT0 bit in GICR are set (one), the 
MCU will jump to the corre-
sponding interrupt vector. The flag is cleared when the interrupt 
routine is executed.
Alternatively, the flag can be cleared by writing a logical one to it. 
This flag is always cleared
when INT0 is configured as a level interrupt.
----------------------------------------------

Da ich aber die AVRs nicht kenne, kann ich die nicht sehr weiterhelfen. 
Allerdings denke ich, dass soetwas:

  Send_SMS("464646467","TESTALARM",0,0);
  :
char Send_SMS (char* zielnummer,char* nachricht, char i,char j)
{
 :
 return (1);
}

eher schlechter Stil ist. Wenn Send_SMS ein char zurückgibt, dann sollte 
der Aufruf den auch übernehmen.

 char res;

 res = Send_SMS("464646467","TESTALARM",0,0);


Kann es da nicht evtl. einen Stack-Überlauf geben, wenn Send_SMS einen 
Wert zurückgibt, der nicht übernommen wird?

von Johannes M. (johnny-m)


Lesenswert?

tastendrücker wrote:
> hmmm. Ich (PICer) habe mir mal ein Datasheet vom Atmega32 runtergeladen.
> Da steht zumindest, das das I-Flag automatisch gelöscht wird, wenn die
> ISR aufgerufen wird:
Ist beim AVR genauso.

> eher schlechter Stil ist. Wenn Send_SMS ein char zurückgibt, dann sollte
> der Aufruf den auch übernehmen.
Muss aber nicht, wenn er nicht benötigt wird.

> Kann es da nicht evtl. einen Stack-Überlauf geben, wenn Send_SMS einen
> Wert zurückgibt, der nicht übernommen wird?
Nein. In C ist es problemlos möglich, einen Rückgabewert zu ignorieren. 
Das bringt auch keinerlei Nachteile oder Nebeneffekte mit sich. Es gibt 
eine ganze Reihe Funktionen (auch Standard-Bibliotheksfunktionen), die 
einen Wert zurückgeben, der aber nur in Sonderfällen wirklich sinnvoll 
verwendet werden kann und deshalb in den meisten Fällen verworfen wird. 
Die besten Beispiele dafür stehen in der stdio.h. Oder verwendest Du 
etwa immer den Rückgabewert von printf & Co.? Schließlich gibt 
printf einen int zurück...

von Stefan E. (sternst)


Lesenswert?

tastendrücker wrote:

> Kann es da nicht evtl. einen Stack-Überlauf geben, wenn Send_SMS einen
> Wert zurückgibt, der nicht übernommen wird?

Nein.
Es ist völlig in Ordnung (im technischen Sinne), wenn man einen 
Rückgabewert nicht verwendet.

von Stefan E. (sternst)


Lesenswert?

schurli wrote:

> Ausgelöst wird er duch einen prellenden Schalter. Das ist meiner Meinung
> nach aber kein Grund für die Endlosschleife.

Nun, zumindest wird dadurch der Interrupt schon mal 2 mal direkt 
hintereinander ausgeführt. Lösche am besten am Ende des Interrupt das 
Anforderungsbit nochmal "per Hand".

von schurli (Gast)


Lesenswert?

Hi

Heißt das ich muss das INTF0 Bit am Intrruptende rücksetzen?
Irgendwo muss es ja auch wieder gesetzt werden, damit der Interrupt 
wieder funktioniert?

---------------------------------------------------------
• Bit 6 – INTF0: External Interrupt Flag 0
When an edge or logic change on the INT0 pin triggers an interrupt
request, INTF0 becomes set
(one). If the I-bit in SREG and the INT0 bit in GICR are set (one), the
MCU will jump to the corre-
sponding interrupt vector. The flag is cleared when the interrupt
routine is executed.
Alternatively, the flag can be cleared by writing a logical one to it.
This flag is always cleared
when INT0 is configured as a level interrupt.
---------------------------------------------------------

von Johannes M. (johnny-m)


Lesenswert?

schurli wrote:
> Heißt das ich muss das INTF0 Bit am Intrruptende rücksetzen?
> Irgendwo muss es ja auch wieder gesetzt werden, damit der Interrupt
> wieder funktioniert?
Nicht, damit er wieder "funktioniert", sondern damit er nicht sofort 
nochmal aufgerufen wird. Schließlich ist es zu dem Zeitpunkt schon 
wieder gesetzt, und genau deswegen wird nach Verlassen des Interrupt 
Handlers dieser erneut aufgerufen.

Das was Du da machst mit stangenweise printf & Co. in der ISR geht 
auch nur gut, solange das der einzige Interrupt in Deinem Programm 
ist...

von Jürgen S. (starblue) Benutzerseite


Lesenswert?

Johannes M. wrote:
>
> Das was Du da machst mit stangenweise printf & Co. in der ISR geht
> auch nur gut, solange das der einzige Interrupt in Deinem Programm
> ist...

Auf deutsch gesagt, es macht keinen Sinn, hier überhaupt einen Interrupt 
zu verwenden.

Jürgen

von schurli (Gast)


Lesenswert?

GIFR = (0<<INTF0);

am Ende de Interrupts ändert nichts
Bitte helft mir.

von schurli (Gast)


Lesenswert?

Soll ich ne Positive Flanke von nen Pinn abfragen?

mfg

von Stefan E. (sternst)


Lesenswert?

schurli wrote:
> GIFR = (0<<INTF0);
>
> am Ende de Interrupts ändert nichts
> Bitte helft mir.

Zum Löschen des Bits muss man eine Eins schreiben.

von Johannes M. (johnny-m)


Lesenswert?

schurli wrote:
> GIFR = (0<<INTF0);
>
> am Ende de Interrupts ändert nichts
> Bitte helft mir.
Schau bitte ins Datenblatt bzw. ins AVR-GCC-Tutorial. Da steht, wie 
man ein Interrupt Flag löscht. So jedenfalls nicht...

von schurli (Gast)


Lesenswert?

GIFR &= 0xDF;
Brachte die Lösung!
Danke an alle die mir helfen wollten!

von Johannes M. (johnny-m)


Lesenswert?

schurli wrote:
> GIFR &= 0xDF;
> Brachte die Lösung!
???
1
GIFR = 1 << INTF0;
hätte es getan, ist lesbar und macht wirklich genau das was es soll...

Das mit dem & funktioniert eigentlich nur zufällig wegen Nebeneffekten 
von Read-Modify-Write-Operationen.

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.