Forum: Mikrocontroller und Digitale Elektronik Externe Interrupts INT0 und INT1 deaktivieren


von Alex P. (alex2203)


Lesenswert?

Hallo liebe Forengemeinde,
ich schreibe gerade ein Programm, welches eine LCD Menüanzeige ausgibt 
auf der Sensordaten (die Sensorinfos werden regelmäßig über Interrupts 
ausgelesen) ausgegeben werden. Der jeweilige LCD Anzeigetext wurde per 
Image2GLCD Konverter umgewandelt und in das Programm integriert. Die 
einzelnen Menüpunkte werden per Taster umgeschalten und auch bestätigt. 
Aufgrund der Menge an Anschlüssen die ich für dies und das benötige, 
muss ich die Taster auf die PINS PD2-PD4 am ATMEGA32 hängen. Dummerweise 
sind am PIN PD2 und PD3 die INT0 und INT1 Eingänge, so dass der µC mir 
bei Betätigung des Tasters einen Reset macht. (INT0 und INT1 besitzen 
keine ISRs). Das ganze Programm anzuhängen würde den Rahmen sprengen, 
aus diesem Grund lediglich den Main.c Teil sowie die ISR des 
Temperaturauslesens. Ich hoffe das genügt und mir kann jemand einen 
sinnvollen Hinweis geben, wie ich es schaffe das er bei Betätigung des 
PD2 und PD3 nicht resettet, sondern die entsprechende Entprellfunktion 
ausführt. Einen CLI() Befehl kann ich schlecht einsetzen, bzw. wüsste 
ich nicht wo dies sinnvoll ist, da er mir die Tasterabfrage per for(;;) 
durchführt.
Achja und eine Bitte noch. Nachdem es vielleicht sein kann, das andere 
irgendwann einmal das gleiche dumme Schicksal ereignet sollte sich die 
Diskussion hier aufs Fachliche beschränken. Unnütze Kommentare können 
wenn als nötig erachtet gerne per PN gesendet werden.

Nachdem mir hier bisher immer geholfen wurde, bin ich guter Dinge das 
dies auch diesesmal so ist. Vielen Dank schonmal.

Gruß

Der Alex
1
//Main.c
2
int main (void)
3
{
4
5
  //Definieren der Taster Eingangsports
6
  PORTD=0b00011100;    // Pullup Widerstand für Taster einschalten  
7
  DDRD=0b00100000;    //Pin D5 als PWM Ausgang, Pin D2,D3,D4 als Eingänge für Taster  
8
  
9
  
10
  //lokale Variablen
11
  uint16_t temp_1,temp_2,temp_3;
12
  uint16_t PWM_Prozent_neu;
13
  
14
  uint8_t i=0;
15
  uchar s[30];    //Variable Temperaturwert
16
  uchar Zahl;    //Variable RomCode Wert 1-Wire
17
  uchar s_1[31];    //Variable Temperaturwert 1
18
  uchar s_2[31];    //Variable Temperaturwert 2
19
  uchar s_3[31];    //Variable Temperaturwert 3
20
  uchar string[31];
21
    
22
  //LCD initialisieren
23
  lcd_init();
24
  uart_init();
25
  lcd_clear();
26
  //Interrupt für Tasterentprellung wird eingeschalten
27
  TCCR0 = (1<<CS02)|(1<<CS00);         // divide by 1024 from prescaler
28
  TIMSK |= (1<<TOIE0);                   // enable timer interrupt
29
  TIMSK|=(1<<TICIE1);
30
  
31
  
32
  
33
  //Interrupt für Ausführung Temperaturmessung und GPS-Datenaufnahme
34
  TCCR2 = (1<<WGM21)|(1<<CS22)|(1<<CS21);         // divide by 1024 from prescaler
35
  TCNT2=0;
36
  OCR2=255;
37
  TIMSK |= (1<<OCIE2);
38
  //GICR  &= ~ (1 << INT1);              // enable timer interrupt
39
  GICR=0x02;
40
41
  //Timereinstellung für PWM Modulation wird initialisiert
42
  TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM11)|(1<<WGM10);    //Output to Low
43
  TCCR1B = (1<<CS10)|(1<<WGM12);          //Prescaling 1024
44
  
45
  //LCD Startbildschirm
46
  lcd_draw_fullscreen_bmp(Pumpensteuerung_Logo);
47
  lcd_draw_rect(55,38,60,8,BLACK);          //Rahmen zeichnen
48
  lcd_set_cursor(56,30);                // Cursor wird auf Position gesetzt
49
  lcd_puts_p(small_font,PSTR("Initialisierung"));    // Ausgabe des Wortes
50
  for(i=2;i<=56;i++)                  // Füllen der Progressbar
51
  {
52
    _delay_ms(35);
53
    lcd_fill_rect (57,40,i,4,BLACK);        
54
  }
55
  GPS_available();                  //Überprüfung ob GPS angeschlossen ist und Daten liefert
56
  while (1)
57
  {
58
    
59
    MainMenu_leer();
60
    _delay_ms(50);
61
  }
62
63
}
64
65
//ISR
66
67
ISR(TIMER2_OVF_vect)
68
{
69
  z++;
70
  if(z==725)    //125 entspricht 1 Sekunde
71
  {
72
    PWM_Prozent=PWM_Einstellung(Temperatur_Uebergabe);
73
    PWM_Value=PWM_Prozent*10.23;
74
    OCR1A = PWM_Value;
75
    z=0;
76
    return;
77
  }
78
}

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Editiere Dein Post und benutze die Formatierung!
Warum liest Du nicht die Postingregeln?

Alexander Pl schrieb:
> INT0 und INT1 besitzen
> keine ISRs

Dann gibt man sie auch nicht frei.

Alexander Pl schrieb:
> Das ganze Programm anzuhängen würde den Rahmen sprengen

Dann reduziere es soweit, daß der Fehler noch auftritt und prüfe es vor 
dem Posten!

von Oldie (Gast)


Lesenswert?

In dem Programmgeschnipsel erkennt man nix.

Warum sind INT0 / 1, aktiviert, wenn sie nicht gebraucht werden?

Wenn sie denn aktiviert sind, kann man eine ISR schreiben,
die nix tut und sofort zurückkommt.

von Oliver (Gast)


Lesenswert?

Kein einziger Interrupt eines AVR aktiviert sich automatisch. Solange du 
keinen aktivierst, sind die inaktiv. Ergo brauchst du nichts zu 
deaktivieren.

Der Fehler liegt woanders...

Oliver

von Alex P. (alex2203)


Angehängte Dateien:

Lesenswert?

Guten Morgen,

okay ich muss zugeben, dass dies doch sehr unübersichtlich war, was ich 
geschickt habe. Sah aufn ersten Blick garnicht so schlimm aus. Schande 
auf mein Haupt.Ich gelobe Besserung.
Ich hab den Code nun gekürzt, die ganzen LCD Routinen rausgeschmissen 
und das Ganze nun per LED Kombination getestet. Die Invertierung beim 
PORTD ist STK 500 bedingt.
Das für mich eigenartige ist, dass wenn ich den Interrupt Timer 0 
beschriebenen Teil auskommentiere alles sehr sauber läuft wie es soll, 
sobald ich diesen mit aufnehme startet das Programm ständig von vorne. 
Die gleiche Situation erlebe ich im eigentlichen Programm bei 
Tasterdruck der Taste PD2,PD3(INT0,INT1).
Auch wenn der Fehler nicht identisch ist, so hoffe ich über die Lösung 
dieses Problems meinen eigentlichen Fehler zu finden. Würde mich freuen, 
wenn mir jemand auf die Sprünge helfen könnte. Vielen Dank.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ich seheh schon mal, das du Timer 0 auch mit Interrupt initialisierst, 
aber nicht behandelst. Das reicht schon aus, um den AVR regelmässig 
zurückzusetzen.
Denke dran, für jeden freigegebenen Interrupt musst du auch eine ISR 
vorhalten, sonst rennt der MC immer wieder in den Default Handler - und 
das ist nun mal der Resetvektor.

: Bearbeitet durch User
von Tho W. (tommyprog)


Lesenswert?

Guten morgen,

Du hast bei Dir im Code ein delay mit 35 und 50 gesetzt.
In diesem Moment macht die CPU GARNICHTS auser warten, warten und 
nochmals warten. Für den Fall eines Interrupts wird keiner ausgelöst.

Da du aber mit Interrrupts arbeitest, wie mit den Timer_2 interrupt, so 
würde ich an deiner Stelle eher eine For- Schleife machen, und über i=1 
bis i=50 ein delay von 1ms ausführen lassen.
Ist zwar auch immerhin 1*10^-3s aber wenigstens kann danach noch ein 
Interrupt kommen, der Prozessor wird nur nach einer ms blockiert.
mit einen delay ist es wie gesagt, komplett für 50 Ms gesperrt, und es 
geht mal dann garnichts außer warten.

Ansonsten, wie bereits die Forumskollegen erwähnt haben, arbeitest Du 
NICHT mit einen Interrupt, aktivier ihn nicht, und er bleibt aus.

Nur wenn du einen Interrupt brauchst, aktiviere ihn.

Mfg,
tommyProg

von Tho W. (tommyprog)


Lesenswert?

Hinzufügen möchte ich gerne die Frage, warum du einen festen Wert ins 
TCNT2, also in das Zählregister des Timers schreibst?
Laut meines Lesens von einen ATmega8 Datenblattes hat das schlechte 
Konsequenzen auf das Interruptverhalten des Timers.

Mfg,
tommyProg

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Tho Wes schrieb:
> In diesem Moment macht die CPU GARNICHTS auser warten, warten und
> nochmals warten. Für den Fall eines Interrupts wird keiner ausgelöst.

Das ist ein Irrtum. Die _delay_ms() und _delay_us() Routinen sperren 
keine Interrupts und sind unterbrechbar.

von Tho W. (tommyprog)


Lesenswert?

Matthias Sch. schrieb:
> Tho Wes schrieb:
>> In diesem Moment macht die CPU GARNICHTS auser warten, warten und
>> nochmals warten. Für den Fall eines Interrupts wird keiner ausgelöst.
>
> Das ist ein Irrtum. Die _delay_ms() und _delay_us() Routinen sperren
> keine Interrupts und sind unterbrechbar.

Ach du meine Güte. Bist Du dir da zu 100% sicher? Wenn ja, bedanke ich 
mich für die Wissenskorrektur

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Tho Wes schrieb:
> Bist Du dir da zu 100% sicher?

Jo, da bin ich sicher. In dem 3-Phasenumrichter bspw. wird ein kleines 
Delay von 5ms in der LCD Routine angewandt, damit der Cursor gut 
sichtbar ist, trotzdem läuft die interruptgesteuerte Erzeugung der 3 
Phasen störungsfrei weiter.
http://www.mikrocontroller.net/articles/3-Phasen_Frequenzumrichter_mit_AVR

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Tho Wes schrieb:
> Du hast bei Dir im Code ein delay mit 35 und 50 gesetzt.
> In diesem Moment macht die CPU GARNICHTS auser warten, warten und
> nochmals warten. Für den Fall eines Interrupts wird keiner ausgelöst.

Das ist Unsinn. Natürlich ist ein delay von einem Interrupt 
unterbrechbar.

von Tho W. (tommyprog)


Lesenswert?

Ja, Franky, ist ja schon gut, ich wurde bereits freundlich darauf 
hingewiesen, dann musst du es nichtmehr tun.

Mfg,
tommyProg

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Tho Wes schrieb:
> Ja, Franky, ist ja schon gut, ich wurde bereits freundlich darauf
> hingewiesen, dann musst du es nichtmehr tun.

Sorry, war mit dem Durchlesen des Threads noch nicht ganz durch, sonst 
hätte ich es mir verkniffen. Aber solche Aussagen kann man einfach nicht 
stehenlassen, sonst glaubt da noch einer dran.

Ehrlich gesagt, ich wundere mich ein wenig... für jemanden mit angeblich 
20 Jahren Berufserfahrung hast Du erschreckend wenig Ahnung.

von Tho W. (tommyprog)


Lesenswert?

> Sorry, war mit dem Durchlesen des Threads noch nicht ganz durch, sonst
> hätte ich es mir verkniffen. Aber solche Aussagen kann man einfach nicht
> stehenlassen, sonst glaubt da noch einer dran.
>
> Ehrlich gesagt, ich wundere mich ein wenig... für jemanden mit angeblich
> 20 Jahren Berufserfahrung hast Du erschreckend wenig Ahnung.

Entschuldigung angenommen, Franky. Nein, das stimmt, da hast du recht.
Kannst mir bitte den Link schicken, wo das mit 20 Jahren Berufserfahrung 
steht (und ernst gemeint ist)?

Mfg,
tommyProg

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Tho Wes schrieb:
> Kannst mir bitte den Link schicken, wo das mit 20 Jahren Berufserfahrung
> steht (und ernst gemeint ist)?

Beitrag "Re: Mikrocontroller Aufgabe"

Aber lass uns hier keine alten Kamellen auspacken ;-)

von Tho W. (tommyprog)


Lesenswert?

Frank M. schrieb:
> Tho Wes schrieb:
>> Kannst mir bitte den Link schicken, wo das mit 20 Jahren Berufserfahrung
>> steht (und ernst gemeint ist)?
>
> Beitrag "Re: Mikrocontroller Aufgabe"
>
> Aber lass uns hier keine alten Kamellen auspacken ;-)

Achso^^. Dachte schon, ich hätte geschrieben, dass ich selber 20 Jahre 
Berufserfahrung hätte xD

von Alex P. (alex2203)


Angehängte Dateien:

Lesenswert?

Es freut mich das mir so viele Leute versuchen zu helfen und auch das 
mein Beitrag zum illusteren Small-Talk einlädt.

Danke Matthias für den Tipp. Nach Einarbeitung der anderen ISR 
funktioniert die ganze Schoße wie sie soll, nur leider nicht im Original 
Programm. Ich sehe das so (bitte korrigiert mich falls ich falsch 
liege): Nachdem die Timer0 und 2 Interrupts entsprechende ISRs besitzen 
und Timer1 keinen Interrupt hat und somit keine ISR braucht passt das 
eigentlich. Komischerweise wird im eigentlichen Programm bei aufruf der 
Entprellfunktion der Reset ausgelöst. Vielleicht sollte ich die 
Entprellfunktion komplett entfernen und das Ganze mit delay Zeiten 
lösen, wobei mir diese Funktion wirklich sehr gut gefällt.

Hat zufällig noch jemand einen Ansatz woran es liegen kann?

Grüße

Alex

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

> uint16_t z;

Wenn du diese Variable global halten willst, sollte auch sie 'volatile' 
erklärt werden. Das liegt u.a. daran, das der Kompiler ISR als nicht 
angesprungene Programmteile erkennt und somit erstmal alle Dinge, die 
sich darauf beziehen, wegoptimieren will. Genauer kann dir das z.B. 
Karl-Heinz erklären.
Der m.E. elegantere Weg ist es, z einfach als static zu erklären, und 
sie in die ISR mit reinzunehmen:
1
ISR(TIMER2_COMP_vect)
2
{
3
static uint16_t z;
4
  z++;
5
  if(z==1024)    //30 entspricht ca 1 Sekunde
6
  {
7
    PORTD^=(1<<PD5);    //PIN D1 wird getoggelt um Interruptausführung zu sehen
8
    z=0;
9
    
10
  }
11
  OCR1A = z;
12
}
Das ist aber Geschmackssache. Manche Leute meckern über viele globale 
Variablen, ist aber bei einem MC eigentlich wurscht.

Aber hauptsächlich hast du bei PeDas ISR die Hälfte vergessen, die geht 
noch weiter:
1
ISR( TIMER0_OVF_vect )                            // every 10ms
2
{
3
  static uint8_t ct0, ct1, rpt;
4
  uint8_t i;
5
 
6
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
7
 
8
  i = key_state ^ ~KEY_PIN;                       // key changed ?
9
  ct0 = ~( ct0 & i );                             // reset or count ct0
10
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
11
  i &= ct0 & ct1;                                 // count until roll over ?
12
  key_state ^= i;                                 // then toggle debounced state
13
  key_press |= key_state & i;                     // 0->1: key press detect
14
 
15
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
16
     rpt = REPEAT_START;                          // start delay
17
  if( --rpt == 0 ){
18
    rpt = REPEAT_NEXT;                            // repeat delay
19
    key_rpt |= key_state & REPEAT_MASK;
20
  }
21
}
Du musst allerdings vorher mindestens noch KEY_MASK deklarieren, KEY_PIN 
hast da ja hardkodiert.

von Karl H. (kbuchegg)


Lesenswert?

Alexander Pl schrieb:

> Nach Einarbeitung der anderen ISR
> funktioniert die ganze Schoße wie sie soll, nur leider nicht im Original
> Programm.

Wer oder was ist jetzt das Originalprogramm?
Das aus dem Eröffnungposting, oder das zuletzt gepostete?

> Ich sehe das so (bitte korrigiert mich falls ich falsch
> liege): Nachdem die Timer0 und 2 Interrupts entsprechende ISRs besitzen
> und Timer1 keinen Interrupt hat und somit keine ISR braucht passt das
> eigentlich.

Exakt.

> Komischerweise wird im eigentlichen Programm bei aufruf der
> Entprellfunktion der Reset ausgelöst.

Ich geh mal davon aus, dass das 'eigentlichen Programm' im wesentlichen 
das aus dem Eröffnungsposting ist, in das du noch die Tastenbehandlung 
eingebaut hast.

Da ist noch ein Fehler drinn
1
  TIMSK |= (1<<OCIE2);
2
3
4
...
5
6
ISR(TIMER2_OVF_vect)
7
8
...

Output Compare INterrupt ist nicht dasselbe wie Overflow Interrupt.

-> Reset

> Vielleicht sollte ich die
> Entprellfunktion komplett entfernen

Die PeDa Funktionalität funktioniert super. Wenn in deinem Programm was 
abschmiert, dann ist das so ziemlich die einzige Stelle (wenn du den 
Code korrekt Copy&Paste übernommen hast), an der du nicht suchen 
brauchst.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> Die PeDa Funktionalität funktioniert super. Wenn in deinem Programm was
> abschmiert, dann ist das so ziemlich die einzige Stelle (wenn du den
> Code korrekt Copy&Paste übernommen hast), an der du nicht suchen
> brauchst.


PS: Wenn du keinen Autorepeat brauchst, dann kannst du natürlich den 
ganzen Teil bzgl. key_rpt aus der ISR raus lassen. Aber dann solltest du 
auch die Variable key_rpt komplett entfernen und auch die 'short' 
Funktion nicht mehr benutzen. Die einzige Funktion, die du noch brauchst 
ist get_key_press.

von Alex P. (alex2203)


Lesenswert?

Hammer!

Es geht. Endlich keinen Reset mehr. Die ausschlaggebende Änderung war 
den ISR Timer 2 in Compare umzuschreiben. Was mich nur wirklich 
verwundert ist die Tatsache das ich, obwohl ich wirklich mehrmals Zeile 
für Zeile durchgegangen bin, dies nicht gesehen habe.

Vielen Dank kbuchegg und allen die sich die Mühe gemacht haben mir 
helfen zu wollen.

Dieses Forum hier ist wirklich Oberklasse und so macht es auch Spaß sich 
mit der manchmal nicht ganz leichten Materie zu beschäftigen und 
dazuzulernen.

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.