Forum: Mikrocontroller und Digitale Elektronik Interrupt Problem bei Rücksprung (While und If-Schleifen)


von Matthias S. (lecorde)


Lesenswert?

Moin,
mein Display funktioniert jetzt wunderbar, ich hab aber jetz noch ein 
Problem mit den Interrupts, wo ich auch nicht mehr weiter weiss.

Und zwar soll mein Programm (Phasenabschnittsteuerung mit wählbaren Ein- 
und Auschaltwinkel) bei jedem Nulldurchgang einen Interrupt starten 
(ext. Zero Point Detector), der wiederum einen Timer Interrupt einstellt 
und aktiviert. Beide Interrupts funktionieren auch tadellos jedoch 
werden bei den Rücksprungen aus den Interrupts die jeweiligen If- und 
While Schleifen an dem das Programm unterbrochen wurde bei dem 
Rücksprung übersprungen

Z.B:
1
    if(TASTE_M)
2
    {

Ursache: Wenn ich beim Debuggen vor dem Sprung die Adresse im Programm 
Counter ansehe lautet sie 0x72. Bei dem Sprung in den Interrupt wird sie 
auf 0x74 erhöht. Daher wird die Schleife übersprungen. Ändere ich den 
Rücksprungwert auf 0x72 spring das Programm wieder dahin wo es soll und 
die If-Bedingung wird wieder korrekt abgefragt.

Gibt es eine Einstellung mit der man die Rücksprungadresse ohne eine 
Erhöhung im Stack speichern kann?

hier mal ein Auszug aus meinem Programm:
1
int main()
2
{
3
...  
4
TCCR1B=0x02;
5
TIMSK=0x04;
6
//HW-Interrupt einstellen und aktivieren
7
MCUCR=0x0A;    //Int. Bedingungen einstellen
8
GIMSK=0x40;    //Int0 aktivieren
9
sei();      //HW-Int aktivieren
10
11
//Hauptprogrammschleife
12
  while(1)
13
  {
14
    if(TASTE_M)
15
    {
16
      merker=0;
17
      zeile = Zeichne_Pfeil(zeile);
18
19
  do{
20
  }while(TASTE_M);
21
  ...
22
    }
23
  return(0);
24
}
1
void INT0_vect(void)
2
{
3
alpha=0x01;
4
...
5
TCNT1H=0xFF; //Timerwert für Timer1
6
TCNT1L=0x38; //Timerwert für Timer1
7
sei();
8
}
1
void TIMER1_OVF_vect(void)
2
{
3
alpha++;
4
TCNT1H=0xFF;
5
TCNT1L=0x38;
6
...
7
sei();
8
}

MfG
Matthias

von gast (Gast)


Lesenswert?

Lass mal das sei(); am ende er int routinen weg.

von Matthias S. (lecorde)


Lesenswert?

Das sei() ist ja nötig um die Interrupt wieder zu aktivieren 
(SREG=0x80). Nach jedem Interrupt wird SREG zurückgesetzt und wenn ich 
das sei() nicht mache wird der Interrupt nur einmal ausgeführt.

von Peter (Gast)


Lesenswert?

nein ist es nicht, dafür ist ein reti zuständig, das setzt der Compiler 
selber. (zur not mal im Asselbly nachschauen)

von Stefan E. (sternst)


Lesenswert?

Matthias S. schrieb:
> Das sei() ist ja nötig um die Interrupt wieder zu aktivieren
> (SREG=0x80). Nach jedem Interrupt wird SREG zurückgesetzt und wenn ich
> das sei() nicht mache wird der Interrupt nur einmal ausgeführt.

Welcher Compiler überhaupt? GCC? Dann sind die Interrupt-Routinen nicht 
richtig definiert, was auch der Grund dafür ist, dass du 
fälschlicherweise ein sei am Ende brauchst (weil deine Funktionen so 
nämlich nur ein ret statt eines reti am Ende haben).

von Stefan E. (sternst)


Lesenswert?

Zusatz:
Das dürfte auch der Grund für das beobachtete Fehlverhalten sein, denn 
die Interrupt-Funktionen sichern so auch die Register nicht korrekt.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

>  (While und If-Schleifen)
> die jeweiligen If- und While Schleifen
Es gibt nach wie vor keine If-Schleifen ...
Das einzige was mit If möglich ist, ist eine Abfrage.

> hier mal ein Auszug aus meinem Programm: ...
Hast du irgendwelche asm-Zeilen (Inline-Assembler) in den Programm?

von Matthias S. (lecorde)


Lesenswert?

Ja, ich Arbeite mit dem AVR_Studio -> GCC,

bei mir bringt der Befehl reti leider nicht und bei ret schimpft der 
Compiler.

von Stefan E. (sternst)


Lesenswert?

Andreas W. schrieb:

> normalerweise sollte Dein Compiler am Ende der Interuptfunktion den
> Befehl: "reti"   setzen

Außer halt, der Compiler weiß gar nicht, dass es Interruptfunktionen 
sind, so wie in diesem Fall.

von Stefan E. (sternst)


Lesenswert?

Matthias S. schrieb:
> Ja, ich Arbeite mit dem AVR_Studio -> GCC,
>
> bei mir bringt der Befehl reti leider nicht und bei ret schimpft der
> Compiler.

Du sollst den auch nicht selber einfügen, sondern die Interrupt-Funktion 
korrekt deklarieren.
http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

von Matthias S. (lecorde)


Lesenswert?

Stefan Ernst schrieb:
> Zusatz:
> Das dürfte auch der Grund für das beobachtete Fehlverhalten sein, denn
> die Interrupt-Funktionen sichern so auch die Register nicht korrekt.

Das hab ich anfangs auch gedacht, aber der Inhalt vom Stackpointer zeigt 
während der Interruptroutine schon auf den nächsten Befehl.

PC
0x72   if(TASTE_M)      //-> Sprung in den Interrupt (SP=0x74)
       {
0x74     i++;           //<-Rücksprung aus dem Interrupt

Das sei() hab ich erstmal wieder weggenommen.

von (prx) A. K. (prx)


Lesenswert?

Wer weiss, vielleicht ist das bei Interrupts immer so. Anderswo (ARM) 
ist das normal. Also mach richtige Interrupt-Handler aus deinen falschen 
Interrupt-Handlern und diskutier nicht mit der Hardware wer Recht hat. 
Die ist garantiert sturer.

von Stefan E. (sternst)


Lesenswert?

Matthias S. schrieb:

> Das hab ich anfangs auch gedacht, aber der Inhalt vom Stackpointer zeigt
> während der Interruptroutine schon auf den nächsten Befehl.

Das ist völlig normal und korrekt so. Wenn dein Programm sich nicht so 
verhält, wie von dir erwartet, hat das damit rein gar nichts zu tun. 
Hast du die Interrupt-Funktionen denn inzwischen mal korrigiert?

von Karl H. (kbuchegg)


Lesenswert?

Matthias S. schrieb:
> (ext. Zero Point Detector), der wiederum einen Timer Interrupt einstellt
> und aktiviert. Beide Interrupts funktionieren auch tadellos

Wobei ich mich trotzdem immer noch wundere, wieso deine Funktionen (den 
das sind keine Interrupt Handler, die müssen spezielle Funktionsheader 
haben) überhaupt aufgerufen werden.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Nur ne Schätzung:
Es wäre ggf möglich, wenn man die Funktionsadressen selber in die 
Interruptvektoren schreibt.

von (prx) A. K. (prx)


Lesenswert?

Die Interrupt-Leiste ruft bestimmte Namen auf. Wenn die passen hat man 
gewonnen.

von Matthias S. (lecorde)


Lesenswert?

Ja, dank den Hinweisen von 
http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html 
funktionieren meine Int-Routinen nun. ich hab sie jetzt wie folgt 
umdeklariert:
1
ISR(INT0_vect)
2
{
3
  alpha=0x01;
4
  if(alpha==alpha_ein)
5
  {
6
    STELLER_2_LOW();
7
    STELLER_1_HI();
8
  }  
9
  TCNT1H=0xFF;
10
  TCNT1L=0x38;
11
  //reti();
12
}
13
14
ISR(TIMER1_OVF_vect)
15
{
16
  alpha++;
17
  TCNT1H=0xFF;
18
  TCNT1L=0x38;
19
  if(alpha==alpha_ein)
20
  {
21
    STELLER_2_LOW();
22
    STELLER_1_HI();
23
  }
24
25
  if(alpha==alpha_aus)
26
  {
27
    STELLER_1_LOW();
28
    STELLER_2_HI();
29
  }
30
}

Vielen Dank und MfG
Matthias

von Matthias S. (lecorde)


Lesenswert?

Karl heinz Buchegger schrieb:
> Matthias S. schrieb:
>> (ext. Zero Point Detector), der wiederum einen Timer Interrupt einstellt
>> und aktiviert. Beide Interrupts funktionieren auch tadellos
>
> Wobei ich mich trotzdem immer noch wundere, wieso deine Funktionen (den
> das sind keine Interrupt Handler, die müssen spezielle Funktionsheader
> haben) überhaupt aufgerufen werden.

Das hab ich mich anfangs auch drüber gewundert aber es hat ja bis auf 
den Rücksprung vor div. Schleifen und If-Abfragungen funktioniert

von Stefan E. (sternst)


Lesenswert?

Karl heinz Buchegger schrieb:
> Matthias S. schrieb:
>> (ext. Zero Point Detector), der wiederum einen Timer Interrupt einstellt
>> und aktiviert. Beide Interrupts funktionieren auch tadellos
>
> Wobei ich mich trotzdem immer noch wundere, wieso deine Funktionen (den
> das sind keine Interrupt Handler, die müssen spezielle Funktionsheader
> haben) überhaupt aufgerufen werden.

Weil auch ohne das "ISR" der Name der Funktion vom Präprozessor in die 
Vektornummer übersetzt wird.

von (prx) A. K. (prx)


Lesenswert?

Keine Sorge, da wäre später noch viel mehr merkwürdiger Blödsinn 
passiert, wie beispielsweise Variablen die zufällig und mysteriös ihren 
Wert ändern. Der Unterschied zwischen Funktionen und ISRs beschränkt 
sich nicht auf das I-Flag und die Korrektur der Return-Adresse.

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.